* [Qemu-devel] [PATCH 0/8] pci core reorg @ 2012-12-12 13:13 Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 1/8] pci: prepare makefiles for pci code reorganization Michael S. Tsirkin ` (9 more replies) 0 siblings, 10 replies; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 13:13 UTC (permalink / raw) To: qemu-devel This patchset starts some cleanups of the pci core by rearranging the code: pci core is split out from devices into its own directory, pci internals.h is renamed as it's used externally a lot. I'd like to merge this quickly to avoid conflicting with others work. Plan to send pull request tomorrow, if you have concerns, speak up soon pls. Thanks, Michael S. Tsirkin (8): pci: prepare makefiles for pci code reorganization MAINTAINERS: add hw/pci/ to list of PCI files pci: move pci core code to hw/pci pci: update all users to look in pci/ pci: make external dependencies explicit Revert "pci: prepare makefiles for pci code reorganization" pci: rename pci_internals.h pci_bus.h pci_bus: update comment MAINTAINERS | 1 + arch_init.c | 2 +- hw/Makefile.objs | 10 +- hw/ac97.c | 2 +- hw/acpi_ich9.c | 2 +- hw/acpi_piix4.c | 2 +- hw/alpha_sys.h | 4 +- hw/apb_pci.c | 8 +- hw/apic.c | 2 +- hw/bonito.c | 4 +- hw/cirrus_vga.c | 2 +- hw/dec_pci.c | 8 +- hw/e1000.c | 2 +- hw/eepro100.c | 2 +- hw/es1370.c | 2 +- hw/esp-pci.c | 2 +- hw/grackle_pci.c | 4 +- hw/gt64xxx.c | 4 +- hw/hda-audio.c | 2 +- hw/i386/Makefile.objs | 2 +- hw/i82378.c | 2 +- hw/i82801b11.c | 2 +- hw/ich9.h | 8 +- hw/ide.h | 2 +- hw/ide/ahci.c | 4 +- hw/ide/cmd646.c | 2 +- hw/ide/core.c | 2 +- hw/ide/ich.c | 4 +- hw/ide/pci.c | 2 +- hw/ide/piix.c | 2 +- hw/ide/via.c | 2 +- hw/intel-hda.c | 4 +- hw/ioh3420.c | 6 +- hw/ioh3420.h | 2 +- hw/ivshmem.c | 4 +- hw/kvm/apic.c | 2 +- hw/kvm/pci-assign.c | 4 +- hw/lpc_ich9.c | 8 +- hw/lsi53c895a.c | 2 +- hw/macio.c | 2 +- hw/megasas.c | 4 +- hw/mips_fulong2e.c | 2 +- hw/mips_malta.c | 2 +- hw/msi.c | 395 --------- hw/msi.h | 50 -- hw/msix.c | 562 ------------ hw/msix.h | 41 - hw/ne2000.c | 2 +- hw/openpic.c | 2 +- hw/pc.c | 4 +- hw/pc_piix.c | 4 +- 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_bus.h | 74 ++ hw/pci/pci_host.c | 180 ++++ hw/pci/pci_host.h | 62 ++ hw/pci/pci_ids.h | 147 ++++ 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_bridge_dev.c | 12 +- 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/pcnet-pci.c | 2 +- hw/piix4.c | 2 +- hw/piix_pci.c | 4 +- hw/ppc/Makefile.objs | 2 +- hw/ppc/e500.c | 2 +- hw/ppc440_bamboo.c | 2 +- hw/ppc4xx.h | 2 +- hw/ppc4xx_pci.c | 4 +- hw/ppc_newworld.c | 2 +- hw/ppc_oldworld.c | 2 +- hw/ppc_prep.c | 4 +- hw/ppce500_pci.c | 4 +- hw/prep_pci.c | 4 +- hw/q35.h | 4 +- hw/qxl.h | 2 +- hw/r2d.c | 2 +- hw/realview.c | 2 +- hw/rtl8139.c | 2 +- hw/serial-pci.c | 2 +- hw/sga.c | 2 +- hw/sh_pci.c | 4 +- hw/shpc.c | 681 --------------- hw/shpc.h | 48 - hw/slotid_cap.c | 44 - hw/slotid_cap.h | 11 - hw/smbus_ich9.c | 2 +- hw/spapr.c | 4 +- hw/spapr_pci.c | 10 +- hw/spapr_pci.h | 4 +- hw/sun4u.c | 2 +- hw/unin_pci.c | 4 +- hw/usb/hcd-ehci-pci.c | 2 +- hw/usb/hcd-ohci.c | 2 +- hw/usb/hcd-uhci.c | 2 +- hw/usb/hcd-xhci.c | 6 +- hw/versatile_pci.c | 4 +- hw/versatilepb.c | 2 +- hw/vfio_pci.c | 6 +- hw/vga-pci.c | 2 +- hw/vga.c | 2 +- hw/virtio-balloon.h | 2 +- hw/virtio-net.h | 2 +- hw/virtio-pci.c | 6 +- hw/virtio-scsi.h | 2 +- hw/vmware_vga.c | 2 +- hw/vt82c686.c | 4 +- hw/wdt_i6300esb.c | 2 +- hw/xen-host-pci-device.h | 2 +- hw/xen_apic.c | 2 +- hw/xen_platform.c | 2 +- hw/xen_pt.c | 2 +- hw/xen_pt.h | 2 +- hw/xio3130_downstream.c | 6 +- hw/xio3130_downstream.h | 2 +- hw/xio3130_upstream.c | 6 +- hw/xio3130_upstream.h | 2 +- kvm-all.c | 2 +- kvm-stub.c | 2 +- monitor.c | 2 +- target-i386/kvm.c | 2 +- xen-all.c | 2 +- 162 files changed, 9173 insertions(+), 9176 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_bus.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_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 -- MST ^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 1/8] pci: prepare makefiles for pci code reorganization 2012-12-12 13:13 [Qemu-devel] [PATCH 0/8] pci core reorg Michael S. Tsirkin @ 2012-12-12 13:14 ` Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 2/8] MAINTAINERS: add hw/pci/ to list of PCI files Michael S. Tsirkin ` (8 subsequent siblings) 9 siblings, 0 replies; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 13:14 UTC (permalink / raw) To: qemu-devel To make it easier to move code around without breaking build at intermedite steps, tweak makefiles to look in pci/ and hw/ for include files, automatically. This will be reverted at the end of the reorganization. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- Makefile | 1 + Makefile.target | 1 + Makefile.user | 1 + hw/pci/hw | 1 + 4 files changed, 4 insertions(+) create mode 120000 hw/pci/hw diff --git a/Makefile b/Makefile index 9ecbcbb..b9a81d1 100644 --- a/Makefile +++ b/Makefile @@ -146,6 +146,7 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS) QEMU_CFLAGS+=$(CURL_CFLAGS) QEMU_CFLAGS += -I$(SRC_PATH)/include +QEMU_CFLAGS+=-I$(SRC_PATH)/hw/pci -I$(SRC_PATH)/hw ui/cocoa.o: ui/cocoa.m diff --git a/Makefile.target b/Makefile.target index 8b658c0..e2e8840 100644 --- a/Makefile.target +++ b/Makefile.target @@ -12,6 +12,7 @@ endif QEMU_CFLAGS += -I.. -I$(SRC_PATH)/target-$(TARGET_BASE_ARCH) -DNEED_CPU_H QEMU_CFLAGS+=-I$(SRC_PATH)/include +QEMU_CFLAGS+=-I$(SRC_PATH)/hw/pci -I$(SRC_PATH)/hw ifdef CONFIG_USER_ONLY # user emulator name diff --git a/Makefile.user b/Makefile.user index 9302d33..045ecd3 100644 --- a/Makefile.user +++ b/Makefile.user @@ -11,6 +11,7 @@ $(call set-vpath, $(SRC_PATH)) QEMU_CFLAGS+=-I.. QEMU_CFLAGS += -I$(SRC_PATH)/include QEMU_CFLAGS += -DCONFIG_USER_ONLY +QEMU_CFLAGS+=-I$(SRC_PATH)/hw/pci -I$(SRC_PATH)/hw include $(SRC_PATH)/Makefile.objs diff --git a/hw/pci/hw b/hw/pci/hw new file mode 120000 index 0000000..945c9b4 --- /dev/null +++ b/hw/pci/hw @@ -0,0 +1 @@ +. \ No newline at end of file -- MST ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 2/8] MAINTAINERS: add hw/pci/ to list of PCI files 2012-12-12 13:13 [Qemu-devel] [PATCH 0/8] pci core reorg Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 1/8] pci: prepare makefiles for pci code reorganization Michael S. Tsirkin @ 2012-12-12 13:14 ` Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci Michael S. Tsirkin ` (7 subsequent siblings) 9 siblings, 0 replies; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 13:14 UTC (permalink / raw) To: qemu-devel Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2ede20d..c1b16c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -490,6 +490,7 @@ F: hw/omap* PCI M: Michael S. Tsirkin <mst@redhat.com> S: Supported +F: hw/pci/* F: hw/pci* F: hw/piix* -- MST ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci 2012-12-12 13:13 [Qemu-devel] [PATCH 0/8] pci core reorg Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 1/8] pci: prepare makefiles for pci code reorganization Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 2/8] MAINTAINERS: add hw/pci/ to list of PCI files Michael S. Tsirkin @ 2012-12-12 13:14 ` Michael S. Tsirkin 2012-12-12 19:53 ` Blue Swirl 2012-12-12 13:14 ` [Qemu-devel] [PATCH 4/8] pci: update all users to look in pci/ Michael S. Tsirkin ` (6 subsequent siblings) 9 siblings, 1 reply; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 13:14 UTC (permalink / raw) To: qemu-devel Move files and modify makefiles to pick them at the new location. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- hw/Makefile.objs | 10 +- hw/i386/Makefile.objs | 2 +- hw/msi.c | 395 --------- hw/msi.h | 50 -- hw/msix.c | 562 ------------- hw/msix.h | 41 - hw/pci-hotplug.c | 293 ------- hw/pci-stub.c | 47 -- hw/pci.c | 2168 ------------------------------------------------ hw/pci.h | 684 --------------- hw/pci/Makefile.objs | 6 + hw/pci/msi.c | 395 +++++++++ hw/pci/msi.h | 50 ++ hw/pci/msix.c | 562 +++++++++++++ hw/pci/msix.h | 41 + hw/pci/pci-hotplug.c | 293 +++++++ hw/pci/pci-stub.c | 47 ++ hw/pci/pci.c | 2168 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/pci/pci.h | 684 +++++++++++++++ hw/pci/pci_bridge.c | 363 ++++++++ hw/pci/pci_bridge.h | 66 ++ hw/pci/pci_host.c | 180 ++++ hw/pci/pci_host.h | 62 ++ hw/pci/pci_ids.h | 147 ++++ hw/pci/pci_internals.h | 78 ++ hw/pci/pci_regs.h | 717 ++++++++++++++++ hw/pci/pcie.c | 555 +++++++++++++ hw/pci/pcie.h | 142 ++++ hw/pci/pcie_aer.c | 1032 +++++++++++++++++++++++ hw/pci/pcie_aer.h | 106 +++ hw/pci/pcie_host.c | 161 ++++ hw/pci/pcie_host.h | 54 ++ hw/pci/pcie_port.c | 114 +++ hw/pci/pcie_port.h | 51 ++ hw/pci/pcie_regs.h | 156 ++++ hw/pci/shpc.c | 681 +++++++++++++++ hw/pci/shpc.h | 48 ++ hw/pci/slotid_cap.c | 44 + hw/pci/slotid_cap.h | 11 + hw/pci_bridge.c | 363 -------- hw/pci_bridge.h | 66 -- hw/pci_host.c | 180 ---- hw/pci_host.h | 62 -- hw/pci_ids.h | 147 ---- hw/pci_internals.h | 78 -- hw/pci_regs.h | 717 ---------------- hw/pcie.c | 555 ------------- hw/pcie.h | 142 ---- hw/pcie_aer.c | 1032 ----------------------- hw/pcie_aer.h | 106 --- hw/pcie_host.c | 161 ---- hw/pcie_host.h | 54 -- hw/pcie_port.c | 114 --- hw/pcie_port.h | 51 -- hw/pcie_regs.h | 156 ---- hw/ppc/Makefile.objs | 2 +- hw/shpc.c | 681 --------------- hw/shpc.h | 48 -- hw/slotid_cap.c | 44 - hw/slotid_cap.h | 11 - 60 files changed, 9018 insertions(+), 9018 deletions(-) delete mode 100644 hw/msi.c delete mode 100644 hw/msi.h delete mode 100644 hw/msix.c delete mode 100644 hw/msix.h delete mode 100644 hw/pci-hotplug.c delete mode 100644 hw/pci-stub.c delete mode 100644 hw/pci.c delete mode 100644 hw/pci.h create mode 100644 hw/pci/Makefile.objs create mode 100644 hw/pci/msi.c create mode 100644 hw/pci/msi.h create mode 100644 hw/pci/msix.c create mode 100644 hw/pci/msix.h create mode 100644 hw/pci/pci-hotplug.c create mode 100644 hw/pci/pci-stub.c create mode 100644 hw/pci/pci.c create mode 100644 hw/pci/pci.h create mode 100644 hw/pci/pci_bridge.c create mode 100644 hw/pci/pci_bridge.h create mode 100644 hw/pci/pci_host.c create mode 100644 hw/pci/pci_host.h create mode 100644 hw/pci/pci_ids.h create mode 100644 hw/pci/pci_internals.h create mode 100644 hw/pci/pci_regs.h create mode 100644 hw/pci/pcie.c create mode 100644 hw/pci/pcie.h create mode 100644 hw/pci/pcie_aer.c create mode 100644 hw/pci/pcie_aer.h create mode 100644 hw/pci/pcie_host.c create mode 100644 hw/pci/pcie_host.h create mode 100644 hw/pci/pcie_port.c create mode 100644 hw/pci/pcie_port.h create mode 100644 hw/pci/pcie_regs.h create mode 100644 hw/pci/shpc.c create mode 100644 hw/pci/shpc.h create mode 100644 hw/pci/slotid_cap.c create mode 100644 hw/pci/slotid_cap.h delete mode 100644 hw/pci_bridge.c delete mode 100644 hw/pci_bridge.h delete mode 100644 hw/pci_host.c delete mode 100644 hw/pci_host.h delete mode 100644 hw/pci_ids.h delete mode 100644 hw/pci_internals.h delete mode 100644 hw/pci_regs.h delete mode 100644 hw/pcie.c delete mode 100644 hw/pcie.h delete mode 100644 hw/pcie_aer.c delete mode 100644 hw/pcie_aer.h delete mode 100644 hw/pcie_host.c delete mode 100644 hw/pcie_host.h delete mode 100644 hw/pcie_port.c delete mode 100644 hw/pcie_port.h delete mode 100644 hw/pcie_regs.h delete mode 100644 hw/shpc.c delete mode 100644 hw/shpc.h delete mode 100644 hw/slotid_cap.c delete mode 100644 hw/slotid_cap.h diff --git a/hw/Makefile.objs b/hw/Makefile.objs index d581d8d..228acd6 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,14 +1,10 @@ -common-obj-y = usb/ ide/ +common-obj-y = usb/ ide/ pci/ common-obj-y += loader.o common-obj-$(CONFIG_VIRTIO) += virtio-console.o common-obj-$(CONFIG_VIRTIO) += virtio-rng.o common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o common-obj-y += fw_cfg.o -common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o -common-obj-$(CONFIG_PCI) += msix.o msi.o -common-obj-$(CONFIG_PCI) += shpc.o -common-obj-$(CONFIG_PCI) += slotid_cap.o -common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o +common-obj-$(CONFIG_PCI) += pci_bridge_dev.o common-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o common-obj-$(CONFIG_PCI) += i82801b11.o common-obj-y += watchdog.o @@ -102,8 +98,6 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o # PCI watchdog devices common-obj-$(CONFIG_PCI) += wdt_i6300esb.o -common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o - # PCI network cards common-obj-$(CONFIG_NE2000_PCI) += ne2000.o common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 0d3f6a8..257f3c1 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -2,7 +2,7 @@ obj-y += mc146818rtc.o pc.o obj-y += apic_common.o apic.o kvmvapic.o obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o obj-y += vmport.o -obj-y += pci-hotplug.o smbios.o wdt_ib700.o +obj-y += pci/pci-hotplug.o smbios.o wdt_ib700.o obj-y += debugcon.o multiboot.o obj-y += pc_piix.o obj-y += pc_sysfw.o diff --git a/hw/msi.c b/hw/msi.c deleted file mode 100644 index 33037a8..0000000 --- a/hw/msi.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * msi.c - * - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "msi.h" -#include "range.h" - -/* Eventually those constants should go to Linux pci_regs.h */ -#define PCI_MSI_PENDING_32 0x10 -#define PCI_MSI_PENDING_64 0x14 - -/* PCI_MSI_ADDRESS_LO */ -#define PCI_MSI_ADDRESS_LO_MASK (~0x3) - -/* If we get rid of cap allocator, we won't need those. */ -#define PCI_MSI_32_SIZEOF 0x0a -#define PCI_MSI_64_SIZEOF 0x0e -#define PCI_MSI_32M_SIZEOF 0x14 -#define PCI_MSI_64M_SIZEOF 0x18 - -#define PCI_MSI_VECTORS_MAX 32 - -/* Flag for interrupt controller to declare MSI/MSI-X support */ -bool msi_supported; - -/* If we get rid of cap allocator, we won't need this. */ -static inline uint8_t msi_cap_sizeof(uint16_t flags) -{ - switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) { - case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT: - return PCI_MSI_64M_SIZEOF; - case PCI_MSI_FLAGS_64BIT: - return PCI_MSI_64_SIZEOF; - case PCI_MSI_FLAGS_MASKBIT: - return PCI_MSI_32M_SIZEOF; - case 0: - return PCI_MSI_32_SIZEOF; - default: - abort(); - break; - } - return 0; -} - -//#define MSI_DEBUG - -#ifdef MSI_DEBUG -# define MSI_DPRINTF(fmt, ...) \ - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) -#else -# define MSI_DPRINTF(fmt, ...) do { } while (0) -#endif -#define MSI_DEV_PRINTF(dev, fmt, ...) \ - MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) - -static inline unsigned int msi_nr_vectors(uint16_t flags) -{ - return 1U << - ((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1)); -} - -static inline uint8_t msi_flags_off(const PCIDevice* dev) -{ - return dev->msi_cap + PCI_MSI_FLAGS; -} - -static inline uint8_t msi_address_lo_off(const PCIDevice* dev) -{ - return dev->msi_cap + PCI_MSI_ADDRESS_LO; -} - -static inline uint8_t msi_address_hi_off(const PCIDevice* dev) -{ - return dev->msi_cap + PCI_MSI_ADDRESS_HI; -} - -static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit) -{ - return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32); -} - -static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit) -{ - return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32); -} - -static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit) -{ - return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_PENDING_32); -} - -/* - * Special API for POWER to configure the vectors through - * a side channel. Should never be used by devices. - */ -void msi_set_message(PCIDevice *dev, MSIMessage msg) -{ - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; - - if (msi64bit) { - pci_set_quad(dev->config + msi_address_lo_off(dev), msg.address); - } else { - pci_set_long(dev->config + msi_address_lo_off(dev), msg.address); - } - pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data); -} - -MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) -{ - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; - unsigned int nr_vectors = msi_nr_vectors(flags); - MSIMessage msg; - - assert(vector < nr_vectors); - - if (msi64bit) { - msg.address = pci_get_quad(dev->config + msi_address_lo_off(dev)); - } else { - msg.address = pci_get_long(dev->config + msi_address_lo_off(dev)); - } - - /* upper bit 31:16 is zero */ - msg.data = pci_get_word(dev->config + msi_data_off(dev, msi64bit)); - if (nr_vectors > 1) { - msg.data &= ~(nr_vectors - 1); - msg.data |= vector; - } - - return msg; -} - -bool msi_enabled(const PCIDevice *dev) -{ - return msi_present(dev) && - (pci_get_word(dev->config + msi_flags_off(dev)) & - PCI_MSI_FLAGS_ENABLE); -} - -int msi_init(struct PCIDevice *dev, uint8_t offset, - unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask) -{ - unsigned int vectors_order; - uint16_t flags; - uint8_t cap_size; - int config_offset; - - if (!msi_supported) { - return -ENOTSUP; - } - - MSI_DEV_PRINTF(dev, - "init offset: 0x%"PRIx8" vector: %"PRId8 - " 64bit %d mask %d\n", - offset, nr_vectors, msi64bit, msi_per_vector_mask); - - assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */ - assert(nr_vectors > 0); - assert(nr_vectors <= PCI_MSI_VECTORS_MAX); - /* the nr of MSI vectors is up to 32 */ - vectors_order = ffs(nr_vectors) - 1; - - flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1); - if (msi64bit) { - flags |= PCI_MSI_FLAGS_64BIT; - } - if (msi_per_vector_mask) { - flags |= PCI_MSI_FLAGS_MASKBIT; - } - - cap_size = msi_cap_sizeof(flags); - config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size); - if (config_offset < 0) { - return config_offset; - } - - dev->msi_cap = config_offset; - dev->cap_present |= QEMU_PCI_CAP_MSI; - - pci_set_word(dev->config + msi_flags_off(dev), flags); - pci_set_word(dev->wmask + msi_flags_off(dev), - PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); - pci_set_long(dev->wmask + msi_address_lo_off(dev), - PCI_MSI_ADDRESS_LO_MASK); - if (msi64bit) { - pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff); - } - pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff); - - if (msi_per_vector_mask) { - /* Make mask bits 0 to nr_vectors - 1 writable. */ - pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit), - 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors)); - } - return config_offset; -} - -void msi_uninit(struct PCIDevice *dev) -{ - uint16_t flags; - uint8_t cap_size; - - if (!msi_present(dev)) { - return; - } - flags = pci_get_word(dev->config + msi_flags_off(dev)); - cap_size = msi_cap_sizeof(flags); - pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size); - dev->cap_present &= ~QEMU_PCI_CAP_MSI; - - MSI_DEV_PRINTF(dev, "uninit\n"); -} - -void msi_reset(PCIDevice *dev) -{ - uint16_t flags; - bool msi64bit; - - if (!msi_present(dev)) { - return; - } - - flags = pci_get_word(dev->config + msi_flags_off(dev)); - flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); - msi64bit = flags & PCI_MSI_FLAGS_64BIT; - - pci_set_word(dev->config + msi_flags_off(dev), flags); - pci_set_long(dev->config + msi_address_lo_off(dev), 0); - if (msi64bit) { - pci_set_long(dev->config + msi_address_hi_off(dev), 0); - } - pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0); - if (flags & PCI_MSI_FLAGS_MASKBIT) { - pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0); - pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0); - } - MSI_DEV_PRINTF(dev, "reset\n"); -} - -static bool msi_is_masked(const PCIDevice *dev, unsigned int vector) -{ - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); - uint32_t mask; - assert(vector < PCI_MSI_VECTORS_MAX); - - if (!(flags & PCI_MSI_FLAGS_MASKBIT)) { - return false; - } - - mask = pci_get_long(dev->config + - msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT)); - return mask & (1U << vector); -} - -void msi_notify(PCIDevice *dev, unsigned int vector) -{ - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; - unsigned int nr_vectors = msi_nr_vectors(flags); - MSIMessage msg; - - assert(vector < nr_vectors); - if (msi_is_masked(dev, vector)) { - assert(flags & PCI_MSI_FLAGS_MASKBIT); - pci_long_test_and_set_mask( - dev->config + msi_pending_off(dev, msi64bit), 1U << vector); - MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector); - return; - } - - msg = msi_get_message(dev, vector); - - MSI_DEV_PRINTF(dev, - "notify vector 0x%x" - " address: 0x%"PRIx64" data: 0x%"PRIx32"\n", - vector, msg.address, msg.data); - stl_le_phys(msg.address, msg.data); -} - -/* Normally called by pci_default_write_config(). */ -void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len) -{ - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; - bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT; - unsigned int nr_vectors; - uint8_t log_num_vecs; - uint8_t log_max_vecs; - unsigned int vector; - uint32_t pending; - - if (!msi_present(dev) || - !ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) { - return; - } - -#ifdef MSI_DEBUG - MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n", - addr, val, len); - MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32, - flags, - pci_get_long(dev->config + msi_address_lo_off(dev))); - if (msi64bit) { - fprintf(stderr, " address-hi: 0x%"PRIx32, - pci_get_long(dev->config + msi_address_hi_off(dev))); - } - fprintf(stderr, " data: 0x%"PRIx16, - pci_get_word(dev->config + msi_data_off(dev, msi64bit))); - if (flags & PCI_MSI_FLAGS_MASKBIT) { - fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32, - pci_get_long(dev->config + msi_mask_off(dev, msi64bit)), - pci_get_long(dev->config + msi_pending_off(dev, msi64bit))); - } - fprintf(stderr, "\n"); -#endif - - if (!(flags & PCI_MSI_FLAGS_ENABLE)) { - return; - } - - /* - * Now MSI is enabled, clear INTx# interrupts. - * the driver is prohibited from writing enable bit to mask - * a service request. But the guest OS could do this. - * So we just discard the interrupts as moderate fallback. - * - * 6.8.3.3. Enabling Operation - * While enabled for MSI or MSI-X operation, a function is prohibited - * from using its INTx# pin (if implemented) to request - * service (MSI, MSI-X, and INTx# are mutually exclusive). - */ - pci_device_deassert_intx(dev); - - /* - * nr_vectors might be set bigger than capable. So clamp it. - * This is not legal by spec, so we can do anything we like, - * just don't crash the host - */ - log_num_vecs = - (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1); - log_max_vecs = - (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1); - if (log_num_vecs > log_max_vecs) { - flags &= ~PCI_MSI_FLAGS_QSIZE; - flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1); - pci_set_word(dev->config + msi_flags_off(dev), flags); - } - - if (!msi_per_vector_mask) { - /* if per vector masking isn't supported, - there is no pending interrupt. */ - return; - } - - nr_vectors = msi_nr_vectors(flags); - - /* This will discard pending interrupts, if any. */ - pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit)); - pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors); - pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending); - - /* deliver pending interrupts which are unmasked */ - for (vector = 0; vector < nr_vectors; ++vector) { - if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) { - continue; - } - - pci_long_test_and_clear_mask( - dev->config + msi_pending_off(dev, msi64bit), 1U << vector); - msi_notify(dev, vector); - } -} - -unsigned int msi_nr_vectors_allocated(const PCIDevice *dev) -{ - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); - return msi_nr_vectors(flags); -} diff --git a/hw/msi.h b/hw/msi.h deleted file mode 100644 index 150b09a..0000000 --- a/hw/msi.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * msi.h - * - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef QEMU_MSI_H -#define QEMU_MSI_H - -#include "qemu-common.h" -#include "pci.h" - -struct MSIMessage { - uint64_t address; - uint32_t data; -}; - -extern bool msi_supported; - -void msi_set_message(PCIDevice *dev, MSIMessage msg); -MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector); -bool msi_enabled(const PCIDevice *dev); -int msi_init(struct PCIDevice *dev, uint8_t offset, - unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask); -void msi_uninit(struct PCIDevice *dev); -void msi_reset(PCIDevice *dev); -void msi_notify(PCIDevice *dev, unsigned int vector); -void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); -unsigned int msi_nr_vectors_allocated(const PCIDevice *dev); - -static inline bool msi_present(const PCIDevice *dev) -{ - return dev->cap_present & QEMU_PCI_CAP_MSI; -} - -#endif /* QEMU_MSI_H */ diff --git a/hw/msix.c b/hw/msix.c deleted file mode 100644 index 136ef09..0000000 --- a/hw/msix.c +++ /dev/null @@ -1,562 +0,0 @@ -/* - * MSI-X device support - * - * This module includes support for MSI-X in pci devices. - * - * Author: Michael S. Tsirkin <mst@redhat.com> - * - * 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 the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "hw.h" -#include "msi.h" -#include "msix.h" -#include "pci.h" -#include "range.h" - -#define MSIX_CAP_LENGTH 12 - -/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */ -#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1) -#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8) -#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8) - -static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) -{ - uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; - MSIMessage msg; - - msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); - msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); - return msg; -} - -/* - * Special API for POWER to configure the vectors through - * a side channel. Should never be used by devices. - */ -void msix_set_message(PCIDevice *dev, int vector, struct MSIMessage msg) -{ - uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; - - pci_set_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR, msg.address); - pci_set_long(table_entry + PCI_MSIX_ENTRY_DATA, msg.data); - table_entry[PCI_MSIX_ENTRY_VECTOR_CTRL] &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; -} - -static uint8_t msix_pending_mask(int vector) -{ - return 1 << (vector % 8); -} - -static uint8_t *msix_pending_byte(PCIDevice *dev, int vector) -{ - return dev->msix_pba + vector / 8; -} - -static int msix_is_pending(PCIDevice *dev, int vector) -{ - return *msix_pending_byte(dev, vector) & msix_pending_mask(vector); -} - -static void msix_set_pending(PCIDevice *dev, int vector) -{ - *msix_pending_byte(dev, vector) |= msix_pending_mask(vector); -} - -static void msix_clr_pending(PCIDevice *dev, int vector) -{ - *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector); -} - -static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask) -{ - unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; - return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT; -} - -static bool msix_is_masked(PCIDevice *dev, int vector) -{ - return msix_vector_masked(dev, vector, dev->msix_function_masked); -} - -static void msix_fire_vector_notifier(PCIDevice *dev, - unsigned int vector, bool is_masked) -{ - MSIMessage msg; - int ret; - - if (!dev->msix_vector_use_notifier) { - return; - } - if (is_masked) { - dev->msix_vector_release_notifier(dev, vector); - } else { - msg = msix_get_message(dev, vector); - ret = dev->msix_vector_use_notifier(dev, vector, msg); - assert(ret >= 0); - } -} - -static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked) -{ - bool is_masked = msix_is_masked(dev, vector); - - if (is_masked == was_masked) { - return; - } - - msix_fire_vector_notifier(dev, vector, is_masked); - - if (!is_masked && msix_is_pending(dev, vector)) { - msix_clr_pending(dev, vector); - msix_notify(dev, vector); - } -} - -static void msix_update_function_masked(PCIDevice *dev) -{ - dev->msix_function_masked = !msix_enabled(dev) || - (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK); -} - -/* Handle MSI-X capability config write. */ -void msix_write_config(PCIDevice *dev, uint32_t addr, - uint32_t val, int len) -{ - unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET; - int vector; - bool was_masked; - - if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) { - return; - } - - was_masked = dev->msix_function_masked; - msix_update_function_masked(dev); - - if (!msix_enabled(dev)) { - return; - } - - pci_device_deassert_intx(dev); - - if (dev->msix_function_masked == was_masked) { - return; - } - - for (vector = 0; vector < dev->msix_entries_nr; ++vector) { - msix_handle_mask_update(dev, vector, - msix_vector_masked(dev, vector, was_masked)); - } -} - -static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr, - unsigned size) -{ - PCIDevice *dev = opaque; - - return pci_get_long(dev->msix_table + addr); -} - -static void msix_table_mmio_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - PCIDevice *dev = opaque; - int vector = addr / PCI_MSIX_ENTRY_SIZE; - bool was_masked; - - was_masked = msix_is_masked(dev, vector); - pci_set_long(dev->msix_table + addr, val); - msix_handle_mask_update(dev, vector, was_masked); -} - -static const MemoryRegionOps msix_table_mmio_ops = { - .read = msix_table_mmio_read, - .write = msix_table_mmio_write, - /* TODO: MSIX should be LITTLE_ENDIAN. */ - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, - unsigned size) -{ - PCIDevice *dev = opaque; - - return pci_get_long(dev->msix_pba + addr); -} - -static const MemoryRegionOps msix_pba_mmio_ops = { - .read = msix_pba_mmio_read, - /* TODO: MSIX should be LITTLE_ENDIAN. */ - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) -{ - int vector; - - for (vector = 0; vector < nentries; ++vector) { - unsigned offset = - vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; - bool was_masked = msix_is_masked(dev, vector); - - dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT; - msix_handle_mask_update(dev, vector, was_masked); - } -} - -/* Initialize the MSI-X structures */ -int msix_init(struct PCIDevice *dev, unsigned short nentries, - MemoryRegion *table_bar, uint8_t table_bar_nr, - unsigned table_offset, MemoryRegion *pba_bar, - uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos) -{ - int cap; - unsigned table_size, pba_size; - uint8_t *config; - - /* Nothing to do if MSI is not supported by interrupt controller */ - if (!msi_supported) { - return -ENOTSUP; - } - - if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) { - return -EINVAL; - } - - table_size = nentries * PCI_MSIX_ENTRY_SIZE; - pba_size = QEMU_ALIGN_UP(nentries, 64) / 8; - - /* Sanity test: table & pba don't overlap, fit within BARs, min aligned */ - if ((table_bar_nr == pba_bar_nr && - ranges_overlap(table_offset, table_size, pba_offset, pba_size)) || - table_offset + table_size > memory_region_size(table_bar) || - pba_offset + pba_size > memory_region_size(pba_bar) || - (table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) { - return -EINVAL; - } - - cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH); - if (cap < 0) { - return cap; - } - - dev->msix_cap = cap; - dev->cap_present |= QEMU_PCI_CAP_MSIX; - config = dev->config + cap; - - pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1); - dev->msix_entries_nr = nentries; - dev->msix_function_masked = true; - - pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_nr); - pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr); - - /* Make flags bit writable. */ - dev->wmask[cap + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK | - MSIX_MASKALL_MASK; - - dev->msix_table = g_malloc0(table_size); - dev->msix_pba = g_malloc0(pba_size); - dev->msix_entry_used = g_malloc0(nentries * sizeof *dev->msix_entry_used); - - msix_mask_all(dev, nentries); - - memory_region_init_io(&dev->msix_table_mmio, &msix_table_mmio_ops, dev, - "msix-table", table_size); - memory_region_add_subregion(table_bar, table_offset, &dev->msix_table_mmio); - memory_region_init_io(&dev->msix_pba_mmio, &msix_pba_mmio_ops, dev, - "msix-pba", pba_size); - memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio); - - return 0; -} - -int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, - uint8_t bar_nr) -{ - int ret; - char *name; - - /* - * Migration compatibility dictates that this remains a 4k - * BAR with the vector table in the lower half and PBA in - * the upper half. Do not use these elsewhere! - */ -#define MSIX_EXCLUSIVE_BAR_SIZE 4096 -#define MSIX_EXCLUSIVE_BAR_TABLE_OFFSET 0 -#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2) -#define MSIX_EXCLUSIVE_CAP_OFFSET 0 - - if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) { - return -EINVAL; - } - - name = g_strdup_printf("%s-msix", dev->name); - memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE); - g_free(name); - - ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr, - MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar, - bar_nr, MSIX_EXCLUSIVE_BAR_PBA_OFFSET, - MSIX_EXCLUSIVE_CAP_OFFSET); - if (ret) { - memory_region_destroy(&dev->msix_exclusive_bar); - return ret; - } - - pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY, - &dev->msix_exclusive_bar); - - return 0; -} - -static void msix_free_irq_entries(PCIDevice *dev) -{ - int vector; - - for (vector = 0; vector < dev->msix_entries_nr; ++vector) { - dev->msix_entry_used[vector] = 0; - msix_clr_pending(dev, vector); - } -} - -static void msix_clear_all_vectors(PCIDevice *dev) -{ - int vector; - - for (vector = 0; vector < dev->msix_entries_nr; ++vector) { - msix_clr_pending(dev, vector); - } -} - -/* Clean up resources for the device. */ -void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar) -{ - if (!msix_present(dev)) { - return; - } - pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH); - dev->msix_cap = 0; - msix_free_irq_entries(dev); - dev->msix_entries_nr = 0; - memory_region_del_subregion(pba_bar, &dev->msix_pba_mmio); - memory_region_destroy(&dev->msix_pba_mmio); - g_free(dev->msix_pba); - dev->msix_pba = NULL; - memory_region_del_subregion(table_bar, &dev->msix_table_mmio); - memory_region_destroy(&dev->msix_table_mmio); - g_free(dev->msix_table); - dev->msix_table = NULL; - g_free(dev->msix_entry_used); - dev->msix_entry_used = NULL; - dev->cap_present &= ~QEMU_PCI_CAP_MSIX; -} - -void msix_uninit_exclusive_bar(PCIDevice *dev) -{ - if (msix_present(dev)) { - msix_uninit(dev, &dev->msix_exclusive_bar, &dev->msix_exclusive_bar); - memory_region_destroy(&dev->msix_exclusive_bar); - } -} - -void msix_save(PCIDevice *dev, QEMUFile *f) -{ - unsigned n = dev->msix_entries_nr; - - if (!msix_present(dev)) { - return; - } - - qemu_put_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); - qemu_put_buffer(f, dev->msix_pba, (n + 7) / 8); -} - -/* Should be called after restoring the config space. */ -void msix_load(PCIDevice *dev, QEMUFile *f) -{ - unsigned n = dev->msix_entries_nr; - unsigned int vector; - - if (!msix_present(dev)) { - return; - } - - msix_clear_all_vectors(dev); - qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); - qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8); - msix_update_function_masked(dev); - - for (vector = 0; vector < n; vector++) { - msix_handle_mask_update(dev, vector, true); - } -} - -/* Does device support MSI-X? */ -int msix_present(PCIDevice *dev) -{ - return dev->cap_present & QEMU_PCI_CAP_MSIX; -} - -/* Is MSI-X enabled? */ -int msix_enabled(PCIDevice *dev) -{ - return (dev->cap_present & QEMU_PCI_CAP_MSIX) && - (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & - MSIX_ENABLE_MASK); -} - -/* Send an MSI-X message */ -void msix_notify(PCIDevice *dev, unsigned vector) -{ - MSIMessage msg; - - if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) - return; - if (msix_is_masked(dev, vector)) { - msix_set_pending(dev, vector); - return; - } - - msg = msix_get_message(dev, vector); - - stl_le_phys(msg.address, msg.data); -} - -void msix_reset(PCIDevice *dev) -{ - if (!msix_present(dev)) { - return; - } - msix_clear_all_vectors(dev); - dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &= - ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET]; - memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE); - memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8); - msix_mask_all(dev, dev->msix_entries_nr); -} - -/* PCI spec suggests that devices make it possible for software to configure - * less vectors than supported by the device, but does not specify a standard - * mechanism for devices to do so. - * - * We support this by asking devices to declare vectors software is going to - * actually use, and checking this on the notification path. Devices that - * don't want to follow the spec suggestion can declare all vectors as used. */ - -/* Mark vector as used. */ -int msix_vector_use(PCIDevice *dev, unsigned vector) -{ - if (vector >= dev->msix_entries_nr) - return -EINVAL; - dev->msix_entry_used[vector]++; - return 0; -} - -/* Mark vector as unused. */ -void msix_vector_unuse(PCIDevice *dev, unsigned vector) -{ - if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) { - return; - } - if (--dev->msix_entry_used[vector]) { - return; - } - msix_clr_pending(dev, vector); -} - -void msix_unuse_all_vectors(PCIDevice *dev) -{ - if (!msix_present(dev)) { - return; - } - msix_free_irq_entries(dev); -} - -unsigned int msix_nr_vectors_allocated(const PCIDevice *dev) -{ - return dev->msix_entries_nr; -} - -static int msix_set_notifier_for_vector(PCIDevice *dev, unsigned int vector) -{ - MSIMessage msg; - - if (msix_is_masked(dev, vector)) { - return 0; - } - msg = msix_get_message(dev, vector); - return dev->msix_vector_use_notifier(dev, vector, msg); -} - -static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector) -{ - if (msix_is_masked(dev, vector)) { - return; - } - dev->msix_vector_release_notifier(dev, vector); -} - -int msix_set_vector_notifiers(PCIDevice *dev, - MSIVectorUseNotifier use_notifier, - MSIVectorReleaseNotifier release_notifier) -{ - int vector, ret; - - assert(use_notifier && release_notifier); - - dev->msix_vector_use_notifier = use_notifier; - dev->msix_vector_release_notifier = release_notifier; - - if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & - (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { - for (vector = 0; vector < dev->msix_entries_nr; vector++) { - ret = msix_set_notifier_for_vector(dev, vector); - if (ret < 0) { - goto undo; - } - } - } - return 0; - -undo: - while (--vector >= 0) { - msix_unset_notifier_for_vector(dev, vector); - } - dev->msix_vector_use_notifier = NULL; - dev->msix_vector_release_notifier = NULL; - return ret; -} - -void msix_unset_vector_notifiers(PCIDevice *dev) -{ - int vector; - - assert(dev->msix_vector_use_notifier && - dev->msix_vector_release_notifier); - - if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & - (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { - for (vector = 0; vector < dev->msix_entries_nr; vector++) { - msix_unset_notifier_for_vector(dev, vector); - } - } - dev->msix_vector_use_notifier = NULL; - dev->msix_vector_release_notifier = NULL; -} diff --git a/hw/msix.h b/hw/msix.h deleted file mode 100644 index 15211cb..0000000 --- a/hw/msix.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef QEMU_MSIX_H -#define QEMU_MSIX_H - -#include "qemu-common.h" -#include "pci.h" - -void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg); -int msix_init(PCIDevice *dev, unsigned short nentries, - MemoryRegion *table_bar, uint8_t table_bar_nr, - unsigned table_offset, MemoryRegion *pba_bar, - uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos); -int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, - uint8_t bar_nr); - -void msix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len); - -void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, - MemoryRegion *pba_bar); -void msix_uninit_exclusive_bar(PCIDevice *dev); - -unsigned int msix_nr_vectors_allocated(const PCIDevice *dev); - -void msix_save(PCIDevice *dev, QEMUFile *f); -void msix_load(PCIDevice *dev, QEMUFile *f); - -int msix_enabled(PCIDevice *dev); -int msix_present(PCIDevice *dev); - -int msix_vector_use(PCIDevice *dev, unsigned vector); -void msix_vector_unuse(PCIDevice *dev, unsigned vector); -void msix_unuse_all_vectors(PCIDevice *dev); - -void msix_notify(PCIDevice *dev, unsigned vector); - -void msix_reset(PCIDevice *dev); - -int msix_set_vector_notifiers(PCIDevice *dev, - MSIVectorUseNotifier use_notifier, - MSIVectorReleaseNotifier release_notifier); -void msix_unset_vector_notifiers(PCIDevice *dev); -#endif diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c deleted file mode 100644 index 0ca5546..0000000 --- a/hw/pci-hotplug.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * QEMU PCI hotplug support - * - * Copyright (c) 2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw.h" -#include "boards.h" -#include "pci.h" -#include "net.h" -#include "pc.h" -#include "monitor.h" -#include "scsi.h" -#include "virtio-blk.h" -#include "qemu-config.h" -#include "blockdev.h" -#include "error.h" - -#if defined(TARGET_I386) -static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, - const char *devaddr, - const char *opts_str) -{ - Error *local_err = NULL; - QemuOpts *opts; - PCIBus *bus; - int ret, devfn; - - bus = pci_get_bus_devfn(&devfn, devaddr); - if (!bus) { - monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); - return NULL; - } - if (!((BusState*)bus)->allow_hotplug) { - monitor_printf(mon, "PCI bus doesn't support hotplug\n"); - return NULL; - } - - opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0); - if (!opts) { - return NULL; - } - - qemu_opt_set(opts, "type", "nic"); - - ret = net_client_init(opts, 0, &local_err); - if (error_is_set(&local_err)) { - qerror_report_err(local_err); - error_free(local_err); - return NULL; - } - if (nd_table[ret].devaddr) { - monitor_printf(mon, "Parameter addr not supported\n"); - return NULL; - } - return pci_nic_init(&nd_table[ret], "rtl8139", devaddr); -} - -static int scsi_hot_add(Monitor *mon, DeviceState *adapter, - DriveInfo *dinfo, int printinfo) -{ - SCSIBus *scsibus; - SCSIDevice *scsidev; - - scsibus = (SCSIBus *) - object_dynamic_cast(OBJECT(QLIST_FIRST(&adapter->child_bus)), - TYPE_SCSI_BUS); - if (!scsibus) { - error_report("Device is not a SCSI adapter"); - return -1; - } - - /* - * drive_init() tries to find a default for dinfo->unit. Doesn't - * work at all for hotplug though as we assign the device to a - * specific bus instead of the first bus with spare scsi ids. - * - * Ditch the calculated value and reload from option string (if - * specified). - */ - dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1); - dinfo->bus = scsibus->busnr; - scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, - false, -1); - if (!scsidev) { - return -1; - } - dinfo->unit = scsidev->id; - - if (printinfo) - monitor_printf(mon, "OK bus %d, unit %d\n", - scsibus->busnr, scsidev->id); - return 0; -} - -int pci_drive_hot_add(Monitor *mon, const QDict *qdict, - DriveInfo *dinfo, int type) -{ - int dom, pci_bus; - unsigned slot; - PCIDevice *dev; - const char *pci_addr = qdict_get_str(qdict, "pci_addr"); - - switch (type) { - case IF_SCSI: - if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) { - goto err; - } - dev = pci_find_device(pci_find_root_bus(dom), pci_bus, - PCI_DEVFN(slot, 0)); - if (!dev) { - monitor_printf(mon, "no pci device with address %s\n", pci_addr); - goto err; - } - if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) != 0) { - goto err; - } - break; - default: - monitor_printf(mon, "Can't hot-add drive to type %d\n", type); - goto err; - } - - return 0; -err: - return -1; -} - -static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, - const char *devaddr, - const char *opts) -{ - PCIDevice *dev; - DriveInfo *dinfo = NULL; - int type = -1; - char buf[128]; - PCIBus *bus; - int devfn; - - if (get_param_value(buf, sizeof(buf), "if", opts)) { - if (!strcmp(buf, "scsi")) - type = IF_SCSI; - else if (!strcmp(buf, "virtio")) { - type = IF_VIRTIO; - } else { - monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf); - return NULL; - } - } else { - monitor_printf(mon, "no if= specified\n"); - return NULL; - } - - if (get_param_value(buf, sizeof(buf), "file", opts)) { - dinfo = add_init_drive(opts); - if (!dinfo) - return NULL; - if (dinfo->devaddr) { - monitor_printf(mon, "Parameter addr not supported\n"); - return NULL; - } - } else { - dinfo = NULL; - } - - bus = pci_get_bus_devfn(&devfn, devaddr); - if (!bus) { - monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); - return NULL; - } - if (!((BusState*)bus)->allow_hotplug) { - monitor_printf(mon, "PCI bus doesn't support hotplug\n"); - return NULL; - } - - switch (type) { - case IF_SCSI: - dev = pci_create(bus, devfn, "lsi53c895a"); - if (qdev_init(&dev->qdev) < 0) - dev = NULL; - if (dev && dinfo) { - if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) { - qdev_unplug(&dev->qdev, NULL); - dev = NULL; - } - } - break; - case IF_VIRTIO: - if (!dinfo) { - monitor_printf(mon, "virtio requires a backing file/device.\n"); - return NULL; - } - dev = pci_create(bus, devfn, "virtio-blk-pci"); - if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) { - qdev_free(&dev->qdev); - dev = NULL; - break; - } - if (qdev_init(&dev->qdev) < 0) - dev = NULL; - break; - default: - dev = NULL; - } - return dev; -} - -void pci_device_hot_add(Monitor *mon, const QDict *qdict) -{ - PCIDevice *dev = NULL; - const char *pci_addr = qdict_get_str(qdict, "pci_addr"); - const char *type = qdict_get_str(qdict, "type"); - const char *opts = qdict_get_try_str(qdict, "opts"); - - /* strip legacy tag */ - if (!strncmp(pci_addr, "pci_addr=", 9)) { - pci_addr += 9; - } - - if (!opts) { - opts = ""; - } - - if (!strcmp(pci_addr, "auto")) - pci_addr = NULL; - - if (strcmp(type, "nic") == 0) { - dev = qemu_pci_hot_add_nic(mon, pci_addr, opts); - } else if (strcmp(type, "storage") == 0) { - dev = qemu_pci_hot_add_storage(mon, pci_addr, opts); - } else { - monitor_printf(mon, "invalid type: %s\n", type); - } - - if (dev) { - monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n", - pci_find_domain(dev->bus), - pci_bus_num(dev->bus), PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn)); - } else - monitor_printf(mon, "failed to add %s\n", opts); -} -#endif - -static int pci_device_hot_remove(Monitor *mon, const char *pci_addr) -{ - PCIDevice *d; - int dom, bus; - unsigned slot; - Error *local_err = NULL; - - if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) { - return -1; - } - - d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0)); - if (!d) { - monitor_printf(mon, "slot %d empty\n", slot); - return -1; - } - - qdev_unplug(&d->qdev, &local_err); - if (error_is_set(&local_err)) { - monitor_printf(mon, "%s\n", error_get_pretty(local_err)); - error_free(local_err); - return -1; - } - - return 0; -} - -void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict) -{ - pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr")); -} diff --git a/hw/pci-stub.c b/hw/pci-stub.c deleted file mode 100644 index 134c448..0000000 --- a/hw/pci-stub.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * PCI stubs for platforms that don't support pci bus. - * - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "sysemu.h" -#include "monitor.h" -#include "pci.h" -#include "qmp-commands.h" - -PciInfoList *qmp_query_pci(Error **errp) -{ - error_set(errp, QERR_UNSUPPORTED); - return NULL; -} - -static void pci_error_message(Monitor *mon) -{ - monitor_printf(mon, "PCI devices not supported\n"); -} - -int do_pcie_aer_inject_error(Monitor *mon, - const QDict *qdict, QObject **ret_data) -{ - pci_error_message(mon); - return -ENOSYS; -} - -void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) -{ - pci_error_message(mon); -} diff --git a/hw/pci.c b/hw/pci.c deleted file mode 100644 index 97a0cd7..0000000 --- a/hw/pci.c +++ /dev/null @@ -1,2168 +0,0 @@ -/* - * QEMU PCI bus manager - * - * Copyright (c) 2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw.h" -#include "pci.h" -#include "pci_bridge.h" -#include "pci_internals.h" -#include "monitor.h" -#include "net.h" -#include "sysemu.h" -#include "loader.h" -#include "range.h" -#include "qmp-commands.h" -#include "msi.h" -#include "msix.h" -#include "exec-memory.h" - -//#define DEBUG_PCI -#ifdef DEBUG_PCI -# define PCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) -#else -# define PCI_DPRINTF(format, ...) do { } while (0) -#endif - -static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); -static char *pcibus_get_dev_path(DeviceState *dev); -static char *pcibus_get_fw_dev_path(DeviceState *dev); -static int pcibus_reset(BusState *qbus); - -static Property pci_props[] = { - DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), - DEFINE_PROP_STRING("romfile", PCIDevice, romfile), - DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1), - DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present, - QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false), - DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present, - QEMU_PCI_CAP_SERR_BITNR, true), - DEFINE_PROP_END_OF_LIST() -}; - -static void pci_bus_class_init(ObjectClass *klass, void *data) -{ - BusClass *k = BUS_CLASS(klass); - - k->print_dev = pcibus_dev_print; - k->get_dev_path = pcibus_get_dev_path; - k->get_fw_dev_path = pcibus_get_fw_dev_path; - k->reset = pcibus_reset; -} - -static const TypeInfo pci_bus_info = { - .name = TYPE_PCI_BUS, - .parent = TYPE_BUS, - .instance_size = sizeof(PCIBus), - .class_init = pci_bus_class_init, -}; - -static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); -static void pci_update_mappings(PCIDevice *d); -static void pci_set_irq(void *opaque, int irq_num, int level); -static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom); -static void pci_del_option_rom(PCIDevice *pdev); - -static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET; -static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU; - -struct PCIHostBus { - int domain; - struct PCIBus *bus; - QLIST_ENTRY(PCIHostBus) next; -}; -static QLIST_HEAD(, PCIHostBus) host_buses; - -static const VMStateDescription vmstate_pcibus = { - .name = "PCIBUS", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_INT32_EQUAL(nirq, PCIBus), - VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32, int32_t), - VMSTATE_END_OF_LIST() - } -}; -static int pci_bar(PCIDevice *d, int reg) -{ - uint8_t type; - - if (reg != PCI_ROM_SLOT) - return PCI_BASE_ADDRESS_0 + reg * 4; - - type = d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; - return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; -} - -static inline int pci_irq_state(PCIDevice *d, int irq_num) -{ - return (d->irq_state >> irq_num) & 0x1; -} - -static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level) -{ - d->irq_state &= ~(0x1 << irq_num); - d->irq_state |= level << irq_num; -} - -static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) -{ - PCIBus *bus; - for (;;) { - bus = pci_dev->bus; - irq_num = bus->map_irq(pci_dev, irq_num); - if (bus->set_irq) - break; - pci_dev = bus->parent_dev; - } - bus->irq_count[irq_num] += change; - bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); -} - -int pci_bus_get_irq_level(PCIBus *bus, int irq_num) -{ - assert(irq_num >= 0); - assert(irq_num < bus->nirq); - return !!bus->irq_count[irq_num]; -} - -/* Update interrupt status bit in config space on interrupt - * state change. */ -static void pci_update_irq_status(PCIDevice *dev) -{ - if (dev->irq_state) { - dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT; - } else { - dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; - } -} - -void pci_device_deassert_intx(PCIDevice *dev) -{ - int i; - for (i = 0; i < PCI_NUM_PINS; ++i) { - qemu_set_irq(dev->irq[i], 0); - } -} - -/* - * This function is called on #RST and FLR. - * FLR if PCI_EXP_DEVCTL_BCR_FLR is set - */ -void pci_device_reset(PCIDevice *dev) -{ - int r; - - qdev_reset_all(&dev->qdev); - - dev->irq_state = 0; - pci_update_irq_status(dev); - pci_device_deassert_intx(dev); - /* Clear all writable bits */ - pci_word_test_and_clear_mask(dev->config + PCI_COMMAND, - pci_get_word(dev->wmask + PCI_COMMAND) | - pci_get_word(dev->w1cmask + PCI_COMMAND)); - pci_word_test_and_clear_mask(dev->config + PCI_STATUS, - pci_get_word(dev->wmask + PCI_STATUS) | - pci_get_word(dev->w1cmask + PCI_STATUS)); - dev->config[PCI_CACHE_LINE_SIZE] = 0x0; - dev->config[PCI_INTERRUPT_LINE] = 0x0; - for (r = 0; r < PCI_NUM_REGIONS; ++r) { - PCIIORegion *region = &dev->io_regions[r]; - if (!region->size) { - continue; - } - - if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) && - region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { - pci_set_quad(dev->config + pci_bar(dev, r), region->type); - } else { - pci_set_long(dev->config + pci_bar(dev, r), region->type); - } - } - pci_update_mappings(dev); - - msi_reset(dev); - msix_reset(dev); -} - -/* - * Trigger pci bus reset under a given bus. - * To be called on RST# assert. - */ -void pci_bus_reset(PCIBus *bus) -{ - int i; - - for (i = 0; i < bus->nirq; i++) { - bus->irq_count[i] = 0; - } - for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { - if (bus->devices[i]) { - pci_device_reset(bus->devices[i]); - } - } -} - -static int pcibus_reset(BusState *qbus) -{ - pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus)); - - /* topology traverse is done by pci_bus_reset(). - Tell qbus/qdev walker not to traverse the tree */ - return 1; -} - -static void pci_host_bus_register(int domain, PCIBus *bus) -{ - struct PCIHostBus *host; - host = g_malloc0(sizeof(*host)); - host->domain = domain; - host->bus = bus; - QLIST_INSERT_HEAD(&host_buses, host, next); -} - -PCIBus *pci_find_root_bus(int domain) -{ - struct PCIHostBus *host; - - QLIST_FOREACH(host, &host_buses, next) { - if (host->domain == domain) { - return host->bus; - } - } - - return NULL; -} - -int pci_find_domain(const PCIBus *bus) -{ - PCIDevice *d; - struct PCIHostBus *host; - - /* obtain root bus */ - while ((d = bus->parent_dev) != NULL) { - bus = d->bus; - } - - QLIST_FOREACH(host, &host_buses, next) { - if (host->bus == bus) { - return host->domain; - } - } - - abort(); /* should not be reached */ - return -1; -} - -void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, - const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - uint8_t devfn_min) -{ - qbus_create_inplace(&bus->qbus, TYPE_PCI_BUS, parent, name); - assert(PCI_FUNC(devfn_min) == 0); - bus->devfn_min = devfn_min; - bus->address_space_mem = address_space_mem; - bus->address_space_io = address_space_io; - - /* host bridge */ - QLIST_INIT(&bus->child); - pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */ - - vmstate_register(NULL, -1, &vmstate_pcibus, bus); -} - -PCIBus *pci_bus_new(DeviceState *parent, const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - uint8_t devfn_min) -{ - PCIBus *bus; - - bus = g_malloc0(sizeof(*bus)); - pci_bus_new_inplace(bus, parent, name, address_space_mem, - address_space_io, devfn_min); - OBJECT(bus)->free = g_free; - return bus; -} - -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *irq_opaque, int nirq) -{ - bus->set_irq = set_irq; - bus->map_irq = map_irq; - bus->irq_opaque = irq_opaque; - bus->nirq = nirq; - bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0])); -} - -void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev) -{ - bus->qbus.allow_hotplug = 1; - bus->hotplug = hotplug; - bus->hotplug_qdev = qdev; -} - -PCIBus *pci_register_bus(DeviceState *parent, const char *name, - pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *irq_opaque, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - uint8_t devfn_min, int nirq) -{ - PCIBus *bus; - - bus = pci_bus_new(parent, name, address_space_mem, - address_space_io, devfn_min); - pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq); - return bus; -} - -int pci_bus_num(PCIBus *s) -{ - if (!s->parent_dev) - return 0; /* pci host bridge */ - return s->parent_dev->config[PCI_SECONDARY_BUS]; -} - -static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) -{ - PCIDevice *s = container_of(pv, PCIDevice, config); - uint8_t *config; - int i; - - assert(size == pci_config_size(s)); - config = g_malloc(size); - - qemu_get_buffer(f, config, size); - for (i = 0; i < size; ++i) { - if ((config[i] ^ s->config[i]) & - s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) { - g_free(config); - return -EINVAL; - } - } - memcpy(s->config, config, size); - - pci_update_mappings(s); - - memory_region_set_enabled(&s->bus_master_enable_region, - pci_get_word(s->config + PCI_COMMAND) - & PCI_COMMAND_MASTER); - - g_free(config); - return 0; -} - -/* just put buffer */ -static void put_pci_config_device(QEMUFile *f, void *pv, size_t size) -{ - const uint8_t **v = pv; - assert(size == pci_config_size(container_of(pv, PCIDevice, config))); - qemu_put_buffer(f, *v, size); -} - -static VMStateInfo vmstate_info_pci_config = { - .name = "pci config", - .get = get_pci_config_device, - .put = put_pci_config_device, -}; - -static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) -{ - PCIDevice *s = container_of(pv, PCIDevice, irq_state); - uint32_t irq_state[PCI_NUM_PINS]; - int i; - for (i = 0; i < PCI_NUM_PINS; ++i) { - irq_state[i] = qemu_get_be32(f); - if (irq_state[i] != 0x1 && irq_state[i] != 0) { - fprintf(stderr, "irq state %d: must be 0 or 1.\n", - irq_state[i]); - return -EINVAL; - } - } - - for (i = 0; i < PCI_NUM_PINS; ++i) { - pci_set_irq_state(s, i, irq_state[i]); - } - - return 0; -} - -static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size) -{ - int i; - PCIDevice *s = container_of(pv, PCIDevice, irq_state); - - for (i = 0; i < PCI_NUM_PINS; ++i) { - qemu_put_be32(f, pci_irq_state(s, i)); - } -} - -static VMStateInfo vmstate_info_pci_irq_state = { - .name = "pci irq state", - .get = get_pci_irq_state, - .put = put_pci_irq_state, -}; - -const VMStateDescription vmstate_pci_device = { - .name = "PCIDevice", - .version_id = 2, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_INT32_LE(version_id, PCIDevice), - VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, - vmstate_info_pci_config, - PCI_CONFIG_SPACE_SIZE), - VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, - vmstate_info_pci_irq_state, - PCI_NUM_PINS * sizeof(int32_t)), - VMSTATE_END_OF_LIST() - } -}; - -const VMStateDescription vmstate_pcie_device = { - .name = "PCIEDevice", - .version_id = 2, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_INT32_LE(version_id, PCIDevice), - VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, - vmstate_info_pci_config, - PCIE_CONFIG_SPACE_SIZE), - VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, - vmstate_info_pci_irq_state, - PCI_NUM_PINS * sizeof(int32_t)), - VMSTATE_END_OF_LIST() - } -}; - -static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s) -{ - return pci_is_express(s) ? &vmstate_pcie_device : &vmstate_pci_device; -} - -void pci_device_save(PCIDevice *s, QEMUFile *f) -{ - /* Clear interrupt status bit: it is implicit - * in irq_state which we are saving. - * This makes us compatible with old devices - * which never set or clear this bit. */ - s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; - vmstate_save_state(f, pci_get_vmstate(s), s); - /* Restore the interrupt status bit. */ - pci_update_irq_status(s); -} - -int pci_device_load(PCIDevice *s, QEMUFile *f) -{ - int ret; - ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id); - /* Restore the interrupt status bit. */ - pci_update_irq_status(s); - return ret; -} - -static void pci_set_default_subsystem_id(PCIDevice *pci_dev) -{ - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, - pci_default_sub_vendor_id); - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, - pci_default_sub_device_id); -} - -/* - * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL - * [[<domain>:]<bus>:]<slot>.<func>, return -1 on error - */ -static int pci_parse_devaddr(const char *addr, int *domp, int *busp, - unsigned int *slotp, unsigned int *funcp) -{ - const char *p; - char *e; - unsigned long val; - unsigned long dom = 0, bus = 0; - unsigned int slot = 0; - unsigned int func = 0; - - p = addr; - val = strtoul(p, &e, 16); - if (e == p) - return -1; - if (*e == ':') { - bus = val; - p = e + 1; - val = strtoul(p, &e, 16); - if (e == p) - return -1; - if (*e == ':') { - dom = bus; - bus = val; - p = e + 1; - val = strtoul(p, &e, 16); - if (e == p) - return -1; - } - } - - slot = val; - - if (funcp != NULL) { - if (*e != '.') - return -1; - - p = e + 1; - val = strtoul(p, &e, 16); - if (e == p) - return -1; - - func = val; - } - - /* if funcp == NULL func is 0 */ - if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) - return -1; - - if (*e) - return -1; - - *domp = dom; - *busp = bus; - *slotp = slot; - if (funcp != NULL) - *funcp = func; - return 0; -} - -int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, - unsigned *slotp) -{ - /* strip legacy tag */ - if (!strncmp(addr, "pci_addr=", 9)) { - addr += 9; - } - if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) { - monitor_printf(mon, "Invalid pci address\n"); - return -1; - } - return 0; -} - -PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) -{ - int dom, bus; - unsigned slot; - - if (!devaddr) { - *devfnp = -1; - return pci_find_bus_nr(pci_find_root_bus(0), 0); - } - - if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) { - return NULL; - } - - *devfnp = PCI_DEVFN(slot, 0); - return pci_find_bus_nr(pci_find_root_bus(dom), bus); -} - -static void pci_init_cmask(PCIDevice *dev) -{ - pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff); - pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff); - dev->cmask[PCI_STATUS] = PCI_STATUS_CAP_LIST; - dev->cmask[PCI_REVISION_ID] = 0xff; - dev->cmask[PCI_CLASS_PROG] = 0xff; - pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff); - dev->cmask[PCI_HEADER_TYPE] = 0xff; - dev->cmask[PCI_CAPABILITY_LIST] = 0xff; -} - -static void pci_init_wmask(PCIDevice *dev) -{ - int config_size = pci_config_size(dev); - - dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff; - dev->wmask[PCI_INTERRUPT_LINE] = 0xff; - pci_set_word(dev->wmask + PCI_COMMAND, - PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | - PCI_COMMAND_INTX_DISABLE); - if (dev->cap_present & QEMU_PCI_CAP_SERR) { - pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR); - } - - memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff, - config_size - PCI_CONFIG_HEADER_SIZE); -} - -static void pci_init_w1cmask(PCIDevice *dev) -{ - /* - * Note: It's okay to set w1cmask even for readonly bits as - * long as their value is hardwired to 0. - */ - pci_set_word(dev->w1cmask + PCI_STATUS, - PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | - PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | - PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY); -} - -static void pci_init_mask_bridge(PCIDevice *d) -{ - /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and - PCI_SEC_LETENCY_TIMER */ - memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4); - - /* base and limit */ - d->wmask[PCI_IO_BASE] = PCI_IO_RANGE_MASK & 0xff; - d->wmask[PCI_IO_LIMIT] = PCI_IO_RANGE_MASK & 0xff; - pci_set_word(d->wmask + PCI_MEMORY_BASE, - PCI_MEMORY_RANGE_MASK & 0xffff); - pci_set_word(d->wmask + PCI_MEMORY_LIMIT, - PCI_MEMORY_RANGE_MASK & 0xffff); - pci_set_word(d->wmask + PCI_PREF_MEMORY_BASE, - PCI_PREF_RANGE_MASK & 0xffff); - pci_set_word(d->wmask + PCI_PREF_MEMORY_LIMIT, - PCI_PREF_RANGE_MASK & 0xffff); - - /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */ - memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8); - - /* Supported memory and i/o types */ - d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_16; - d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_16; - pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE, - PCI_PREF_RANGE_TYPE_64); - pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT, - PCI_PREF_RANGE_TYPE_64); - -/* TODO: add this define to pci_regs.h in linux and then in qemu. */ -#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ -#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */ -#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */ -#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ -#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ - pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, - PCI_BRIDGE_CTL_PARITY | - PCI_BRIDGE_CTL_SERR | - PCI_BRIDGE_CTL_ISA | - PCI_BRIDGE_CTL_VGA | - PCI_BRIDGE_CTL_VGA_16BIT | - PCI_BRIDGE_CTL_MASTER_ABORT | - PCI_BRIDGE_CTL_BUS_RESET | - PCI_BRIDGE_CTL_FAST_BACK | - PCI_BRIDGE_CTL_DISCARD | - PCI_BRIDGE_CTL_SEC_DISCARD | - PCI_BRIDGE_CTL_DISCARD_SERR); - /* Below does not do anything as we never set this bit, put here for - * completeness. */ - pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL, - PCI_BRIDGE_CTL_DISCARD_STATUS); - d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK; - d->cmask[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_MASK; - pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE, - PCI_PREF_RANGE_TYPE_MASK); - pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_LIMIT, - PCI_PREF_RANGE_TYPE_MASK); -} - -static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev) -{ - uint8_t slot = PCI_SLOT(dev->devfn); - uint8_t func; - - if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { - dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; - } - - /* - * multifunction bit is interpreted in two ways as follows. - * - all functions must set the bit to 1. - * Example: Intel X53 - * - function 0 must set the bit, but the rest function (> 0) - * is allowed to leave the bit to 0. - * Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10, - * - * So OS (at least Linux) checks the bit of only function 0, - * and doesn't see the bit of function > 0. - * - * The below check allows both interpretation. - */ - if (PCI_FUNC(dev->devfn)) { - PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)]; - if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) { - /* function 0 should set multifunction bit */ - error_report("PCI: single function device can't be populated " - "in function %x.%x", slot, PCI_FUNC(dev->devfn)); - return -1; - } - return 0; - } - - if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { - return 0; - } - /* function 0 indicates single function, so function > 0 must be NULL */ - for (func = 1; func < PCI_FUNC_MAX; ++func) { - if (bus->devices[PCI_DEVFN(slot, func)]) { - error_report("PCI: %x.0 indicates single function, " - "but %x.%x is already populated.", - slot, slot, func); - return -1; - } - } - return 0; -} - -static void pci_config_alloc(PCIDevice *pci_dev) -{ - int config_size = pci_config_size(pci_dev); - - pci_dev->config = g_malloc0(config_size); - pci_dev->cmask = g_malloc0(config_size); - pci_dev->wmask = g_malloc0(config_size); - pci_dev->w1cmask = g_malloc0(config_size); - pci_dev->used = g_malloc0(config_size); -} - -static void pci_config_free(PCIDevice *pci_dev) -{ - g_free(pci_dev->config); - g_free(pci_dev->cmask); - g_free(pci_dev->wmask); - g_free(pci_dev->w1cmask); - g_free(pci_dev->used); -} - -/* -1 for devfn means auto assign */ -static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, - const char *name, int devfn) -{ - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); - PCIConfigReadFunc *config_read = pc->config_read; - PCIConfigWriteFunc *config_write = pc->config_write; - - if (devfn < 0) { - for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices); - devfn += PCI_FUNC_MAX) { - if (!bus->devices[devfn]) - goto found; - } - error_report("PCI: no slot/function available for %s, all in use", name); - return NULL; - found: ; - } else if (bus->devices[devfn]) { - error_report("PCI: slot %d function %d not available for %s, in use by %s", - PCI_SLOT(devfn), PCI_FUNC(devfn), name, bus->devices[devfn]->name); - return NULL; - } - pci_dev->bus = bus; - if (bus->dma_context_fn) { - pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, devfn); - } else { - /* FIXME: Make dma_context_fn use MemoryRegions instead, so this path is - * taken unconditionally */ - /* FIXME: inherit memory region from bus creator */ - memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master", - get_system_memory(), 0, - memory_region_size(get_system_memory())); - memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); - address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region); - pci_dev->dma = g_new(DMAContext, 1); - dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL); - } - pci_dev->devfn = devfn; - pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); - pci_dev->irq_state = 0; - pci_config_alloc(pci_dev); - - pci_config_set_vendor_id(pci_dev->config, pc->vendor_id); - pci_config_set_device_id(pci_dev->config, pc->device_id); - pci_config_set_revision(pci_dev->config, pc->revision); - pci_config_set_class(pci_dev->config, pc->class_id); - - if (!pc->is_bridge) { - if (pc->subsystem_vendor_id || pc->subsystem_id) { - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, - pc->subsystem_vendor_id); - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, - pc->subsystem_id); - } else { - pci_set_default_subsystem_id(pci_dev); - } - } else { - /* subsystem_vendor_id/subsystem_id are only for header type 0 */ - assert(!pc->subsystem_vendor_id); - assert(!pc->subsystem_id); - } - pci_init_cmask(pci_dev); - pci_init_wmask(pci_dev); - pci_init_w1cmask(pci_dev); - if (pc->is_bridge) { - pci_init_mask_bridge(pci_dev); - } - if (pci_init_multifunction(bus, pci_dev)) { - pci_config_free(pci_dev); - return NULL; - } - - if (!config_read) - config_read = pci_default_read_config; - if (!config_write) - config_write = pci_default_write_config; - pci_dev->config_read = config_read; - pci_dev->config_write = config_write; - bus->devices[devfn] = pci_dev; - pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS); - pci_dev->version_id = 2; /* Current pci device vmstate version */ - return pci_dev; -} - -static void do_pci_unregister_device(PCIDevice *pci_dev) -{ - qemu_free_irqs(pci_dev->irq); - pci_dev->bus->devices[pci_dev->devfn] = NULL; - pci_config_free(pci_dev); - - if (!pci_dev->bus->dma_context_fn) { - address_space_destroy(&pci_dev->bus_master_as); - memory_region_destroy(&pci_dev->bus_master_enable_region); - g_free(pci_dev->dma); - pci_dev->dma = NULL; - } -} - -static void pci_unregister_io_regions(PCIDevice *pci_dev) -{ - PCIIORegion *r; - int i; - - for(i = 0; i < PCI_NUM_REGIONS; i++) { - r = &pci_dev->io_regions[i]; - if (!r->size || r->addr == PCI_BAR_UNMAPPED) - continue; - memory_region_del_subregion(r->address_space, r->memory); - } -} - -static int pci_unregister_device(DeviceState *dev) -{ - PCIDevice *pci_dev = PCI_DEVICE(dev); - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); - - pci_unregister_io_regions(pci_dev); - pci_del_option_rom(pci_dev); - - if (pc->exit) { - pc->exit(pci_dev); - } - - do_pci_unregister_device(pci_dev); - return 0; -} - -void pci_register_bar(PCIDevice *pci_dev, int region_num, - uint8_t type, MemoryRegion *memory) -{ - PCIIORegion *r; - uint32_t addr; - uint64_t wmask; - pcibus_t size = memory_region_size(memory); - - assert(region_num >= 0); - assert(region_num < PCI_NUM_REGIONS); - if (size & (size-1)) { - fprintf(stderr, "ERROR: PCI region size must be pow2 " - "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size); - exit(1); - } - - r = &pci_dev->io_regions[region_num]; - r->addr = PCI_BAR_UNMAPPED; - r->size = size; - r->type = type; - r->memory = NULL; - - wmask = ~(size - 1); - addr = pci_bar(pci_dev, region_num); - if (region_num == PCI_ROM_SLOT) { - /* ROM enable bit is writable */ - wmask |= PCI_ROM_ADDRESS_ENABLE; - } - pci_set_long(pci_dev->config + addr, type); - if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) && - r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { - pci_set_quad(pci_dev->wmask + addr, wmask); - pci_set_quad(pci_dev->cmask + addr, ~0ULL); - } else { - pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff); - pci_set_long(pci_dev->cmask + addr, 0xffffffff); - } - pci_dev->io_regions[region_num].memory = memory; - pci_dev->io_regions[region_num].address_space - = type & PCI_BASE_ADDRESS_SPACE_IO - ? pci_dev->bus->address_space_io - : pci_dev->bus->address_space_mem; -} - -pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num) -{ - return pci_dev->io_regions[region_num].addr; -} - -static pcibus_t pci_bar_address(PCIDevice *d, - int reg, uint8_t type, pcibus_t size) -{ - pcibus_t new_addr, last_addr; - int bar = pci_bar(d, reg); - uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); - - if (type & PCI_BASE_ADDRESS_SPACE_IO) { - if (!(cmd & PCI_COMMAND_IO)) { - return PCI_BAR_UNMAPPED; - } - new_addr = pci_get_long(d->config + bar) & ~(size - 1); - last_addr = new_addr + size - 1; - /* NOTE: we have only 64K ioports on PC */ - if (last_addr <= new_addr || new_addr == 0 || last_addr > UINT16_MAX) { - return PCI_BAR_UNMAPPED; - } - return new_addr; - } - - if (!(cmd & PCI_COMMAND_MEMORY)) { - return PCI_BAR_UNMAPPED; - } - if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { - new_addr = pci_get_quad(d->config + bar); - } else { - new_addr = pci_get_long(d->config + bar); - } - /* the ROM slot has a specific enable bit */ - if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) { - return PCI_BAR_UNMAPPED; - } - new_addr &= ~(size - 1); - last_addr = new_addr + size - 1; - /* NOTE: we do not support wrapping */ - /* XXX: as we cannot support really dynamic - mappings, we handle specific values as invalid - mappings. */ - if (last_addr <= new_addr || new_addr == 0 || - last_addr == PCI_BAR_UNMAPPED) { - return PCI_BAR_UNMAPPED; - } - - /* Now pcibus_t is 64bit. - * Check if 32 bit BAR wraps around explicitly. - * Without this, PC ide doesn't work well. - * TODO: remove this work around. - */ - if (!(type & PCI_BASE_ADDRESS_MEM_TYPE_64) && last_addr >= UINT32_MAX) { - return PCI_BAR_UNMAPPED; - } - - /* - * OS is allowed to set BAR beyond its addressable - * bits. For example, 32 bit OS can set 64bit bar - * to >4G. Check it. TODO: we might need to support - * it in the future for e.g. PAE. - */ - if (last_addr >= HWADDR_MAX) { - return PCI_BAR_UNMAPPED; - } - - return new_addr; -} - -static void pci_update_mappings(PCIDevice *d) -{ - PCIIORegion *r; - int i; - pcibus_t new_addr; - - for(i = 0; i < PCI_NUM_REGIONS; i++) { - r = &d->io_regions[i]; - - /* this region isn't registered */ - if (!r->size) - continue; - - new_addr = pci_bar_address(d, i, r->type, r->size); - - /* This bar isn't changed */ - if (new_addr == r->addr) - continue; - - /* now do the real mapping */ - if (r->addr != PCI_BAR_UNMAPPED) { - memory_region_del_subregion(r->address_space, r->memory); - } - r->addr = new_addr; - if (r->addr != PCI_BAR_UNMAPPED) { - memory_region_add_subregion_overlap(r->address_space, - r->addr, r->memory, 1); - } - } -} - -static inline int pci_irq_disabled(PCIDevice *d) -{ - return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE; -} - -/* Called after interrupt disabled field update in config space, - * assert/deassert interrupts if necessary. - * Gets original interrupt disable bit value (before update). */ -static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled) -{ - int i, disabled = pci_irq_disabled(d); - if (disabled == was_irq_disabled) - return; - for (i = 0; i < PCI_NUM_PINS; ++i) { - int state = pci_irq_state(d, i); - pci_change_irq_level(d, i, disabled ? -state : state); - } -} - -uint32_t pci_default_read_config(PCIDevice *d, - uint32_t address, int len) -{ - uint32_t val = 0; - - memcpy(&val, d->config + address, len); - return le32_to_cpu(val); -} - -void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) -{ - int i, was_irq_disabled = pci_irq_disabled(d); - - for (i = 0; i < l; val >>= 8, ++i) { - uint8_t wmask = d->wmask[addr + i]; - uint8_t w1cmask = d->w1cmask[addr + i]; - assert(!(wmask & w1cmask)); - d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask); - d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ - } - if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) || - ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) || - ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) || - range_covers_byte(addr, l, PCI_COMMAND)) - pci_update_mappings(d); - - if (range_covers_byte(addr, l, PCI_COMMAND)) { - pci_update_irq_disabled(d, was_irq_disabled); - memory_region_set_enabled(&d->bus_master_enable_region, - pci_get_word(d->config + PCI_COMMAND) - & PCI_COMMAND_MASTER); - } - - msi_write_config(d, addr, val, l); - msix_write_config(d, addr, val, l); -} - -/***********************************************************/ -/* generic PCI irq support */ - -/* 0 <= irq_num <= 3. level must be 0 or 1 */ -static void pci_set_irq(void *opaque, int irq_num, int level) -{ - PCIDevice *pci_dev = opaque; - int change; - - change = level - pci_irq_state(pci_dev, irq_num); - if (!change) - return; - - pci_set_irq_state(pci_dev, irq_num, level); - pci_update_irq_status(pci_dev); - if (pci_irq_disabled(pci_dev)) - return; - pci_change_irq_level(pci_dev, irq_num, change); -} - -/* Special hooks used by device assignment */ -void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq) -{ - assert(!bus->parent_dev); - bus->route_intx_to_irq = route_intx_to_irq; -} - -PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) -{ - PCIBus *bus; - - do { - bus = dev->bus; - pin = bus->map_irq(dev, pin); - dev = bus->parent_dev; - } while (dev); - - if (!bus->route_intx_to_irq) { - error_report("PCI: Bug - unimplemented PCI INTx routing (%s)\n", - object_get_typename(OBJECT(bus->qbus.parent))); - return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 }; - } - - return bus->route_intx_to_irq(bus->irq_opaque, pin); -} - -bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new) -{ - return old->mode != new->mode || old->irq != new->irq; -} - -void pci_bus_fire_intx_routing_notifier(PCIBus *bus) -{ - PCIDevice *dev; - PCIBus *sec; - int i; - - for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { - dev = bus->devices[i]; - if (dev && dev->intx_routing_notifier) { - dev->intx_routing_notifier(dev); - } - QLIST_FOREACH(sec, &bus->child, sibling) { - pci_bus_fire_intx_routing_notifier(sec); - } - } -} - -void pci_device_set_intx_routing_notifier(PCIDevice *dev, - PCIINTxRoutingNotifier notifier) -{ - dev->intx_routing_notifier = notifier; -} - -/* - * PCI-to-PCI bridge specification - * 9.1: Interrupt routing. Table 9-1 - * - * the PCI Express Base Specification, Revision 2.1 - * 2.2.8.1: INTx interrutp signaling - Rules - * the Implementation Note - * Table 2-20 - */ -/* - * 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD - * 0-origin unlike PCI interrupt pin register. - */ -int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) -{ - return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; -} - -/***********************************************************/ -/* monitor info on PCI */ - -typedef struct { - uint16_t class; - const char *desc; - const char *fw_name; - uint16_t fw_ign_bits; -} pci_class_desc; - -static const pci_class_desc pci_class_descriptions[] = -{ - { 0x0001, "VGA controller", "display"}, - { 0x0100, "SCSI controller", "scsi"}, - { 0x0101, "IDE controller", "ide"}, - { 0x0102, "Floppy controller", "fdc"}, - { 0x0103, "IPI controller", "ipi"}, - { 0x0104, "RAID controller", "raid"}, - { 0x0106, "SATA controller"}, - { 0x0107, "SAS controller"}, - { 0x0180, "Storage controller"}, - { 0x0200, "Ethernet controller", "ethernet"}, - { 0x0201, "Token Ring controller", "token-ring"}, - { 0x0202, "FDDI controller", "fddi"}, - { 0x0203, "ATM controller", "atm"}, - { 0x0280, "Network controller"}, - { 0x0300, "VGA controller", "display", 0x00ff}, - { 0x0301, "XGA controller"}, - { 0x0302, "3D controller"}, - { 0x0380, "Display controller"}, - { 0x0400, "Video controller", "video"}, - { 0x0401, "Audio controller", "sound"}, - { 0x0402, "Phone"}, - { 0x0403, "Audio controller", "sound"}, - { 0x0480, "Multimedia controller"}, - { 0x0500, "RAM controller", "memory"}, - { 0x0501, "Flash controller", "flash"}, - { 0x0580, "Memory controller"}, - { 0x0600, "Host bridge", "host"}, - { 0x0601, "ISA bridge", "isa"}, - { 0x0602, "EISA bridge", "eisa"}, - { 0x0603, "MC bridge", "mca"}, - { 0x0604, "PCI bridge", "pci"}, - { 0x0605, "PCMCIA bridge", "pcmcia"}, - { 0x0606, "NUBUS bridge", "nubus"}, - { 0x0607, "CARDBUS bridge", "cardbus"}, - { 0x0608, "RACEWAY bridge"}, - { 0x0680, "Bridge"}, - { 0x0700, "Serial port", "serial"}, - { 0x0701, "Parallel port", "parallel"}, - { 0x0800, "Interrupt controller", "interrupt-controller"}, - { 0x0801, "DMA controller", "dma-controller"}, - { 0x0802, "Timer", "timer"}, - { 0x0803, "RTC", "rtc"}, - { 0x0900, "Keyboard", "keyboard"}, - { 0x0901, "Pen", "pen"}, - { 0x0902, "Mouse", "mouse"}, - { 0x0A00, "Dock station", "dock", 0x00ff}, - { 0x0B00, "i386 cpu", "cpu", 0x00ff}, - { 0x0c00, "Fireware contorller", "fireware"}, - { 0x0c01, "Access bus controller", "access-bus"}, - { 0x0c02, "SSA controller", "ssa"}, - { 0x0c03, "USB controller", "usb"}, - { 0x0c04, "Fibre channel controller", "fibre-channel"}, - { 0x0c05, "SMBus"}, - { 0, NULL} -}; - -static void pci_for_each_device_under_bus(PCIBus *bus, - void (*fn)(PCIBus *b, PCIDevice *d, - void *opaque), - void *opaque) -{ - PCIDevice *d; - int devfn; - - for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { - d = bus->devices[devfn]; - if (d) { - fn(bus, d, opaque); - } - } -} - -void pci_for_each_device(PCIBus *bus, int bus_num, - void (*fn)(PCIBus *b, PCIDevice *d, void *opaque), - void *opaque) -{ - bus = pci_find_bus_nr(bus, bus_num); - - if (bus) { - pci_for_each_device_under_bus(bus, fn, opaque); - } -} - -static const pci_class_desc *get_class_desc(int class) -{ - const pci_class_desc *desc; - - desc = pci_class_descriptions; - while (desc->desc && class != desc->class) { - desc++; - } - - return desc; -} - -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num); - -static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev) -{ - PciMemoryRegionList *head = NULL, *cur_item = NULL; - int i; - - for (i = 0; i < PCI_NUM_REGIONS; i++) { - const PCIIORegion *r = &dev->io_regions[i]; - PciMemoryRegionList *region; - - if (!r->size) { - continue; - } - - region = g_malloc0(sizeof(*region)); - region->value = g_malloc0(sizeof(*region->value)); - - if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { - region->value->type = g_strdup("io"); - } else { - region->value->type = g_strdup("memory"); - region->value->has_prefetch = true; - region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH); - region->value->has_mem_type_64 = true; - region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64); - } - - region->value->bar = i; - region->value->address = r->addr; - region->value->size = r->size; - - /* XXX: waiting for the qapi to support GSList */ - if (!cur_item) { - head = cur_item = region; - } else { - cur_item->next = region; - cur_item = region; - } - } - - return head; -} - -static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus, - int bus_num) -{ - PciBridgeInfo *info; - - info = g_malloc0(sizeof(*info)); - - info->bus.number = dev->config[PCI_PRIMARY_BUS]; - info->bus.secondary = dev->config[PCI_SECONDARY_BUS]; - info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS]; - - info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range)); - info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); - info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO); - - info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range)); - info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); - info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); - - info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range)); - info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); - info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); - - if (dev->config[PCI_SECONDARY_BUS] != 0) { - PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]); - if (child_bus) { - info->has_devices = true; - info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]); - } - } - - return info; -} - -static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, - int bus_num) -{ - const pci_class_desc *desc; - PciDeviceInfo *info; - uint8_t type; - int class; - - info = g_malloc0(sizeof(*info)); - info->bus = bus_num; - info->slot = PCI_SLOT(dev->devfn); - info->function = PCI_FUNC(dev->devfn); - - class = pci_get_word(dev->config + PCI_CLASS_DEVICE); - info->class_info.class = class; - desc = get_class_desc(class); - if (desc->desc) { - info->class_info.has_desc = true; - info->class_info.desc = g_strdup(desc->desc); - } - - info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID); - info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID); - info->regions = qmp_query_pci_regions(dev); - info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : ""); - - if (dev->config[PCI_INTERRUPT_PIN] != 0) { - info->has_irq = true; - info->irq = dev->config[PCI_INTERRUPT_LINE]; - } - - type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; - if (type == PCI_HEADER_TYPE_BRIDGE) { - info->has_pci_bridge = true; - info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num); - } - - return info; -} - -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num) -{ - PciDeviceInfoList *info, *head = NULL, *cur_item = NULL; - PCIDevice *dev; - int devfn; - - for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { - dev = bus->devices[devfn]; - if (dev) { - info = g_malloc0(sizeof(*info)); - info->value = qmp_query_pci_device(dev, bus, bus_num); - - /* XXX: waiting for the qapi to support GSList */ - if (!cur_item) { - head = cur_item = info; - } else { - cur_item->next = info; - cur_item = info; - } - } - } - - return head; -} - -static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) -{ - PciInfo *info = NULL; - - bus = pci_find_bus_nr(bus, bus_num); - if (bus) { - info = g_malloc0(sizeof(*info)); - info->bus = bus_num; - info->devices = qmp_query_pci_devices(bus, bus_num); - } - - return info; -} - -PciInfoList *qmp_query_pci(Error **errp) -{ - PciInfoList *info, *head = NULL, *cur_item = NULL; - struct PCIHostBus *host; - - QLIST_FOREACH(host, &host_buses, next) { - info = g_malloc0(sizeof(*info)); - info->value = qmp_query_pci_bus(host->bus, 0); - - /* XXX: waiting for the qapi to support GSList */ - if (!cur_item) { - head = cur_item = info; - } else { - cur_item->next = info; - cur_item = info; - } - } - - return head; -} - -static const char * const pci_nic_models[] = { - "ne2k_pci", - "i82551", - "i82557b", - "i82559er", - "rtl8139", - "e1000", - "pcnet", - "virtio", - NULL -}; - -static const char * const pci_nic_names[] = { - "ne2k_pci", - "i82551", - "i82557b", - "i82559er", - "rtl8139", - "e1000", - "pcnet", - "virtio-net-pci", - NULL -}; - -/* Initialize a PCI NIC. */ -/* FIXME callers should check for failure, but don't */ -PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, - const char *default_devaddr) -{ - const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr; - PCIBus *bus; - int devfn; - PCIDevice *pci_dev; - DeviceState *dev; - int i; - - i = qemu_find_nic_model(nd, pci_nic_models, default_model); - if (i < 0) - return NULL; - - bus = pci_get_bus_devfn(&devfn, devaddr); - if (!bus) { - error_report("Invalid PCI device address %s for device %s", - devaddr, pci_nic_names[i]); - return NULL; - } - - pci_dev = pci_create(bus, devfn, pci_nic_names[i]); - dev = &pci_dev->qdev; - qdev_set_nic_properties(dev, nd); - if (qdev_init(dev) < 0) - return NULL; - return pci_dev; -} - -PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, - const char *default_devaddr) -{ - PCIDevice *res; - - if (qemu_show_nic_models(nd->model, pci_nic_models)) - exit(0); - - res = pci_nic_init(nd, default_model, default_devaddr); - if (!res) - exit(1); - return res; -} - -PCIDevice *pci_vga_init(PCIBus *bus) -{ - switch (vga_interface_type) { - case VGA_CIRRUS: - return pci_create_simple(bus, -1, "cirrus-vga"); - case VGA_QXL: - return pci_create_simple(bus, -1, "qxl-vga"); - case VGA_STD: - return pci_create_simple(bus, -1, "VGA"); - case VGA_VMWARE: - return pci_create_simple(bus, -1, "vmware-svga"); - case VGA_NONE: - default: /* Other non-PCI types. Checking for unsupported types is already - done in vl.c. */ - return NULL; - } -} - -/* Whether a given bus number is in range of the secondary - * bus of the given bridge device. */ -static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) -{ - return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) & - PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ && - dev->config[PCI_SECONDARY_BUS] < bus_num && - bus_num <= dev->config[PCI_SUBORDINATE_BUS]; -} - -static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) -{ - PCIBus *sec; - - if (!bus) { - return NULL; - } - - if (pci_bus_num(bus) == bus_num) { - return bus; - } - - /* Consider all bus numbers in range for the host pci bridge. */ - if (bus->parent_dev && - !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) { - return NULL; - } - - /* try child bus */ - for (; bus; bus = sec) { - QLIST_FOREACH(sec, &bus->child, sibling) { - assert(sec->parent_dev); - if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) { - return sec; - } - if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) { - break; - } - } - } - - return NULL; -} - -PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn) -{ - bus = pci_find_bus_nr(bus, bus_num); - - if (!bus) - return NULL; - - return bus->devices[devfn]; -} - -static int pci_qdev_init(DeviceState *qdev) -{ - PCIDevice *pci_dev = (PCIDevice *)qdev; - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); - PCIBus *bus; - int rc; - bool is_default_rom; - - /* initialize cap_present for pci_is_express() and pci_config_size() */ - if (pc->is_express) { - pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; - } - - bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); - pci_dev = do_pci_register_device(pci_dev, bus, - object_get_typename(OBJECT(qdev)), - pci_dev->devfn); - if (pci_dev == NULL) - return -1; - if (qdev->hotplugged && pc->no_hotplug) { - qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev))); - do_pci_unregister_device(pci_dev); - return -1; - } - if (pc->init) { - rc = pc->init(pci_dev); - if (rc != 0) { - do_pci_unregister_device(pci_dev); - return rc; - } - } - - /* rom loading */ - is_default_rom = false; - if (pci_dev->romfile == NULL && pc->romfile != NULL) { - pci_dev->romfile = g_strdup(pc->romfile); - is_default_rom = true; - } - pci_add_option_rom(pci_dev, is_default_rom); - - if (bus->hotplug) { - /* Let buses differentiate between hotplug and when device is - * enabled during qemu machine creation. */ - rc = bus->hotplug(bus->hotplug_qdev, pci_dev, - qdev->hotplugged ? PCI_HOTPLUG_ENABLED: - PCI_COLDPLUG_ENABLED); - if (rc != 0) { - int r = pci_unregister_device(&pci_dev->qdev); - assert(!r); - return rc; - } - } - return 0; -} - -static int pci_unplug_device(DeviceState *qdev) -{ - PCIDevice *dev = PCI_DEVICE(qdev); - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); - - if (pc->no_hotplug) { - qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev))); - return -1; - } - return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, - PCI_HOTPLUG_DISABLED); -} - -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, - const char *name) -{ - DeviceState *dev; - - dev = qdev_create(&bus->qbus, name); - qdev_prop_set_int32(dev, "addr", devfn); - qdev_prop_set_bit(dev, "multifunction", multifunction); - return PCI_DEVICE(dev); -} - -PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, - bool multifunction, - const char *name) -{ - PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction, name); - qdev_init_nofail(&dev->qdev); - return dev; -} - -PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name) -{ - return pci_create_multifunction(bus, devfn, false, name); -} - -PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) -{ - return pci_create_simple_multifunction(bus, devfn, false, name); -} - -static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size) -{ - int offset = PCI_CONFIG_HEADER_SIZE; - int i; - for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) { - if (pdev->used[i]) - offset = i + 1; - else if (i - offset + 1 == size) - return offset; - } - return 0; -} - -static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id, - uint8_t *prev_p) -{ - uint8_t next, prev; - - if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST)) - return 0; - - for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); - prev = next + PCI_CAP_LIST_NEXT) - if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id) - break; - - if (prev_p) - *prev_p = prev; - return next; -} - -static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset) -{ - uint8_t next, prev, found = 0; - - if (!(pdev->used[offset])) { - return 0; - } - - assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST); - - for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); - prev = next + PCI_CAP_LIST_NEXT) { - if (next <= offset && next > found) { - found = next; - } - } - return found; -} - -/* Patch the PCI vendor and device ids in a PCI rom image if necessary. - This is needed for an option rom which is used for more than one device. */ -static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size) -{ - uint16_t vendor_id; - uint16_t device_id; - uint16_t rom_vendor_id; - uint16_t rom_device_id; - uint16_t rom_magic; - uint16_t pcir_offset; - uint8_t checksum; - - /* Words in rom data are little endian (like in PCI configuration), - so they can be read / written with pci_get_word / pci_set_word. */ - - /* Only a valid rom will be patched. */ - rom_magic = pci_get_word(ptr); - if (rom_magic != 0xaa55) { - PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic); - return; - } - pcir_offset = pci_get_word(ptr + 0x18); - if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) { - PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset); - return; - } - - vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); - device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); - rom_vendor_id = pci_get_word(ptr + pcir_offset + 4); - rom_device_id = pci_get_word(ptr + pcir_offset + 6); - - PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile, - vendor_id, device_id, rom_vendor_id, rom_device_id); - - checksum = ptr[6]; - - if (vendor_id != rom_vendor_id) { - /* Patch vendor id and checksum (at offset 6 for etherboot roms). */ - checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8); - checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8); - PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); - ptr[6] = checksum; - pci_set_word(ptr + pcir_offset + 4, vendor_id); - } - - if (device_id != rom_device_id) { - /* Patch device id and checksum (at offset 6 for etherboot roms). */ - checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8); - checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8); - PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); - ptr[6] = checksum; - pci_set_word(ptr + pcir_offset + 6, device_id); - } -} - -/* Add an option rom for the device */ -static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) -{ - int size; - char *path; - void *ptr; - char name[32]; - const VMStateDescription *vmsd; - - if (!pdev->romfile) - return 0; - if (strlen(pdev->romfile) == 0) - return 0; - - if (!pdev->rom_bar) { - /* - * Load rom via fw_cfg instead of creating a rom bar, - * for 0.11 compatibility. - */ - int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE); - if (class == 0x0300) { - rom_add_vga(pdev->romfile); - } else { - rom_add_option(pdev->romfile, -1); - } - return 0; - } - - path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); - if (path == NULL) { - path = g_strdup(pdev->romfile); - } - - size = get_image_size(path); - if (size < 0) { - error_report("%s: failed to find romfile \"%s\"", - __FUNCTION__, pdev->romfile); - g_free(path); - return -1; - } - if (size & (size - 1)) { - size = 1 << qemu_fls(size); - } - - vmsd = qdev_get_vmsd(DEVICE(pdev)); - - if (vmsd) { - snprintf(name, sizeof(name), "%s.rom", vmsd->name); - } else { - snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev))); - } - pdev->has_rom = true; - memory_region_init_ram(&pdev->rom, name, size); - vmstate_register_ram(&pdev->rom, &pdev->qdev); - ptr = memory_region_get_ram_ptr(&pdev->rom); - load_image(path, ptr); - g_free(path); - - if (is_default_rom) { - /* Only the default rom images will be patched (if needed). */ - pci_patch_ids(pdev, ptr, size); - } - - qemu_put_ram_ptr(ptr); - - pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom); - - return 0; -} - -static void pci_del_option_rom(PCIDevice *pdev) -{ - if (!pdev->has_rom) - return; - - vmstate_unregister_ram(&pdev->rom, &pdev->qdev); - memory_region_destroy(&pdev->rom); - pdev->has_rom = false; -} - -/* - * if !offset - * Reserve space and add capability to the linked list in pci config space - * - * if offset = 0, - * Find and reserve space and add capability to the linked list - * in pci config space */ -int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, - uint8_t offset, uint8_t size) -{ - uint8_t *config; - int i, overlapping_cap; - - if (!offset) { - offset = pci_find_space(pdev, size); - if (!offset) { - return -ENOSPC; - } - } else { - /* Verify that capabilities don't overlap. Note: device assignment - * depends on this check to verify that the device is not broken. - * Should never trigger for emulated devices, but it's helpful - * for debugging these. */ - for (i = offset; i < offset + size; i++) { - overlapping_cap = pci_find_capability_at_offset(pdev, i); - if (overlapping_cap) { - fprintf(stderr, "ERROR: %04x:%02x:%02x.%x " - "Attempt to add PCI capability %x at offset " - "%x overlaps existing capability %x at offset %x\n", - pci_find_domain(pdev->bus), pci_bus_num(pdev->bus), - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - cap_id, offset, overlapping_cap, i); - return -EINVAL; - } - } - } - - config = pdev->config + offset; - config[PCI_CAP_LIST_ID] = cap_id; - config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST]; - pdev->config[PCI_CAPABILITY_LIST] = offset; - pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST; - memset(pdev->used + offset, 0xFF, QEMU_ALIGN_UP(size, 4)); - /* Make capability read-only by default */ - memset(pdev->wmask + offset, 0, size); - /* Check capability by default */ - memset(pdev->cmask + offset, 0xFF, size); - return offset; -} - -/* Unlink capability from the pci config space. */ -void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) -{ - uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev); - if (!offset) - return; - pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT]; - /* Make capability writable again */ - memset(pdev->wmask + offset, 0xff, size); - memset(pdev->w1cmask + offset, 0, size); - /* Clear cmask as device-specific registers can't be checked */ - memset(pdev->cmask + offset, 0, size); - memset(pdev->used + offset, 0, QEMU_ALIGN_UP(size, 4)); - - if (!pdev->config[PCI_CAPABILITY_LIST]) - pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST; -} - -uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id) -{ - return pci_find_capability_list(pdev, cap_id, NULL); -} - -static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) -{ - PCIDevice *d = (PCIDevice *)dev; - const pci_class_desc *desc; - char ctxt[64]; - PCIIORegion *r; - int i, class; - - class = pci_get_word(d->config + PCI_CLASS_DEVICE); - desc = pci_class_descriptions; - while (desc->desc && class != desc->class) - desc++; - if (desc->desc) { - snprintf(ctxt, sizeof(ctxt), "%s", desc->desc); - } else { - snprintf(ctxt, sizeof(ctxt), "Class %04x", class); - } - - monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " - "pci id %04x:%04x (sub %04x:%04x)\n", - indent, "", ctxt, pci_bus_num(d->bus), - PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), - pci_get_word(d->config + PCI_VENDOR_ID), - pci_get_word(d->config + PCI_DEVICE_ID), - pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID), - pci_get_word(d->config + PCI_SUBSYSTEM_ID)); - for (i = 0; i < PCI_NUM_REGIONS; i++) { - r = &d->io_regions[i]; - if (!r->size) - continue; - monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS - " [0x%"FMT_PCIBUS"]\n", - indent, "", - i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem", - r->addr, r->addr + r->size - 1); - } -} - -static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len) -{ - PCIDevice *d = (PCIDevice *)dev; - const char *name = NULL; - const pci_class_desc *desc = pci_class_descriptions; - int class = pci_get_word(d->config + PCI_CLASS_DEVICE); - - while (desc->desc && - (class & ~desc->fw_ign_bits) != - (desc->class & ~desc->fw_ign_bits)) { - desc++; - } - - if (desc->desc) { - name = desc->fw_name; - } - - if (name) { - pstrcpy(buf, len, name); - } else { - snprintf(buf, len, "pci%04x,%04x", - pci_get_word(d->config + PCI_VENDOR_ID), - pci_get_word(d->config + PCI_DEVICE_ID)); - } - - return buf; -} - -static char *pcibus_get_fw_dev_path(DeviceState *dev) -{ - PCIDevice *d = (PCIDevice *)dev; - char path[50], name[33]; - int off; - - off = snprintf(path, sizeof(path), "%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 = container_of(dev, PCIDevice, qdev); - PCIDevice *t; - int slot_depth; - /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function. - * 00 is added here to make this format compatible with - * domain:Bus:Slot.Func for systems without nested PCI bridges. - * Slot.Function list specifies the slot and function numbers for all - * devices on the path from root to the specific device. */ - char domain[] = "DDDD:00"; - char slot[] = ":SS.F"; - int domain_len = sizeof domain - 1 /* For '\0' */; - int slot_len = sizeof slot - 1 /* For '\0' */; - int path_len; - char *path, *p; - int s; - - /* Calculate # of slots on path between device and root. */; - slot_depth = 0; - for (t = d; t; t = t->bus->parent_dev) { - ++slot_depth; - } - - path_len = domain_len + slot_len * slot_depth; - - /* Allocate memory, fill in the terminating null byte. */ - path = g_malloc(path_len + 1 /* For '\0' */); - path[path_len] = '\0'; - - /* First field is the domain. */ - s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus)); - assert(s == domain_len); - memcpy(path, domain, domain_len); - - /* Fill in slot numbers. We walk up from device to root, so need to print - * them in the reverse order, last to first. */ - p = path + path_len; - for (t = d; t; t = t->bus->parent_dev) { - p -= slot_len; - s = snprintf(slot, sizeof slot, ":%02x.%x", - PCI_SLOT(t->devfn), PCI_FUNC(t->devfn)); - assert(s == slot_len); - memcpy(p, slot, slot_len); - } - - return path; -} - -static int pci_qdev_find_recursive(PCIBus *bus, - const char *id, PCIDevice **pdev) -{ - DeviceState *qdev = qdev_find_recursive(&bus->qbus, id); - if (!qdev) { - return -ENODEV; - } - - /* roughly check if given qdev is pci device */ - if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) { - *pdev = PCI_DEVICE(qdev); - return 0; - } - return -EINVAL; -} - -int pci_qdev_find_device(const char *id, PCIDevice **pdev) -{ - struct PCIHostBus *host; - int rc = -ENODEV; - - QLIST_FOREACH(host, &host_buses, next) { - int tmp = pci_qdev_find_recursive(host->bus, id, pdev); - if (!tmp) { - rc = 0; - break; - } - if (tmp != -ENODEV) { - rc = tmp; - } - } - - return rc; -} - -MemoryRegion *pci_address_space(PCIDevice *dev) -{ - return dev->bus->address_space_mem; -} - -MemoryRegion *pci_address_space_io(PCIDevice *dev) -{ - return dev->bus->address_space_io; -} - -static void pci_device_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *k = DEVICE_CLASS(klass); - k->init = pci_qdev_init; - k->unplug = pci_unplug_device; - k->exit = pci_unregister_device; - k->bus_type = TYPE_PCI_BUS; - k->props = pci_props; -} - -void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque) -{ - bus->dma_context_fn = fn; - bus->dma_context_opaque = opaque; -} - -static TypeInfo pci_device_type_info = { - .name = TYPE_PCI_DEVICE, - .parent = TYPE_DEVICE, - .instance_size = sizeof(PCIDevice), - .abstract = true, - .class_size = sizeof(PCIDeviceClass), - .class_init = pci_device_class_init, -}; - -static void pci_register_types(void) -{ - type_register_static(&pci_bus_info); - type_register_static(&pci_device_type_info); -} - -type_init(pci_register_types) diff --git a/hw/pci.h b/hw/pci.h deleted file mode 100644 index 4da0c2a..0000000 --- a/hw/pci.h +++ /dev/null @@ -1,684 +0,0 @@ -#ifndef QEMU_PCI_H -#define QEMU_PCI_H - -#include "qemu-common.h" - -#include "qdev.h" -#include "memory.h" -#include "dma.h" - -/* PCI includes legacy ISA access. */ -#include "isa.h" - -#include "pcie.h" - -/* PCI bus */ - -#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) -#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) -#define PCI_FUNC(devfn) ((devfn) & 0x07) -#define PCI_SLOT_MAX 32 -#define PCI_FUNC_MAX 8 - -/* Class, Vendor and Device IDs from Linux's pci_ids.h */ -#include "pci_ids.h" - -/* QEMU-specific Vendor and Device ID definitions */ - -/* IBM (0x1014) */ -#define PCI_DEVICE_ID_IBM_440GX 0x027f -#define PCI_DEVICE_ID_IBM_OPENPIC2 0xffff - -/* Hitachi (0x1054) */ -#define PCI_VENDOR_ID_HITACHI 0x1054 -#define PCI_DEVICE_ID_HITACHI_SH7751R 0x350e - -/* Apple (0x106b) */ -#define PCI_DEVICE_ID_APPLE_343S1201 0x0010 -#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI 0x001e -#define PCI_DEVICE_ID_APPLE_UNI_N_PCI 0x001f -#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL 0x0022 -#define PCI_DEVICE_ID_APPLE_IPID_USB 0x003f - -/* Realtek (0x10ec) */ -#define PCI_DEVICE_ID_REALTEK_8029 0x8029 - -/* Xilinx (0x10ee) */ -#define PCI_DEVICE_ID_XILINX_XC2VP30 0x0300 - -/* Marvell (0x11ab) */ -#define PCI_DEVICE_ID_MARVELL_GT6412X 0x4620 - -/* QEMU/Bochs VGA (0x1234) */ -#define PCI_VENDOR_ID_QEMU 0x1234 -#define PCI_DEVICE_ID_QEMU_VGA 0x1111 - -/* VMWare (0x15ad) */ -#define PCI_VENDOR_ID_VMWARE 0x15ad -#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 -#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 -#define PCI_DEVICE_ID_VMWARE_NET 0x0720 -#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 -#define PCI_DEVICE_ID_VMWARE_IDE 0x1729 - -/* Intel (0x8086) */ -#define PCI_DEVICE_ID_INTEL_82551IT 0x1209 -#define PCI_DEVICE_ID_INTEL_82557 0x1229 -#define PCI_DEVICE_ID_INTEL_82801IR 0x2922 - -/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */ -#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 -#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4 -#define PCI_SUBDEVICE_ID_QEMU 0x1100 - -#define PCI_DEVICE_ID_VIRTIO_NET 0x1000 -#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 -#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 -#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 -#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 -#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 - -#define FMT_PCIBUS PRIx64 - -typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, - uint32_t address, uint32_t data, int len); -typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, - uint32_t address, int len); -typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, - pcibus_t addr, pcibus_t size, int type); -typedef void PCIUnregisterFunc(PCIDevice *pci_dev); - -typedef struct PCIIORegion { - pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ -#define PCI_BAR_UNMAPPED (~(pcibus_t)0) - pcibus_t size; - uint8_t type; - MemoryRegion *memory; - MemoryRegion *address_space; -} PCIIORegion; - -#define PCI_ROM_SLOT 6 -#define PCI_NUM_REGIONS 7 - -#include "pci_regs.h" - -/* PCI HEADER_TYPE */ -#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 - -/* Size of the standard PCI config header */ -#define PCI_CONFIG_HEADER_SIZE 0x40 -/* Size of the standard PCI config space */ -#define PCI_CONFIG_SPACE_SIZE 0x100 -/* Size of the standart PCIe config space: 4KB */ -#define PCIE_CONFIG_SPACE_SIZE 0x1000 - -#define PCI_NUM_PINS 4 /* A-D */ - -/* Bits in cap_present field. */ -enum { - QEMU_PCI_CAP_MSI = 0x1, - QEMU_PCI_CAP_MSIX = 0x2, - QEMU_PCI_CAP_EXPRESS = 0x4, - - /* multifunction capable device */ -#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3 - QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR), - - /* command register SERR bit enabled */ -#define QEMU_PCI_CAP_SERR_BITNR 4 - QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR), - /* Standard hot plug controller. */ -#define QEMU_PCI_SHPC_BITNR 5 - QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR), -#define QEMU_PCI_SLOTID_BITNR 6 - QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_BITNR), -}; - -#define TYPE_PCI_DEVICE "pci-device" -#define PCI_DEVICE(obj) \ - OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE) -#define PCI_DEVICE_CLASS(klass) \ - OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE) -#define PCI_DEVICE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE) - -typedef struct PCIINTxRoute { - enum { - PCI_INTX_ENABLED, - PCI_INTX_INVERTED, - PCI_INTX_DISABLED, - } mode; - int irq; -} PCIINTxRoute; - -typedef struct PCIDeviceClass { - DeviceClass parent_class; - - int (*init)(PCIDevice *dev); - PCIUnregisterFunc *exit; - PCIConfigReadFunc *config_read; - PCIConfigWriteFunc *config_write; - - uint16_t vendor_id; - uint16_t device_id; - uint8_t revision; - uint16_t class_id; - uint16_t subsystem_vendor_id; /* only for header type = 0 */ - uint16_t subsystem_id; /* only for header type = 0 */ - - /* - * pci-to-pci bridge or normal device. - * This doesn't mean pci host switch. - * When card bus bridge is supported, this would be enhanced. - */ - int is_bridge; - - /* pcie stuff */ - int is_express; /* is this device pci express? */ - - /* device isn't hot-pluggable */ - int no_hotplug; - - /* rom bar */ - const char *romfile; -} PCIDeviceClass; - -typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev); -typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector, - MSIMessage msg); -typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector); - -struct PCIDevice { - DeviceState qdev; - - /* PCI config space */ - uint8_t *config; - - /* Used to enable config checks on load. Note that writable bits are - * never checked even if set in cmask. */ - uint8_t *cmask; - - /* Used to implement R/W bytes */ - uint8_t *wmask; - - /* Used to implement RW1C(Write 1 to Clear) bytes */ - uint8_t *w1cmask; - - /* Used to allocate config space for capabilities. */ - uint8_t *used; - - /* the following fields are read only */ - PCIBus *bus; - int32_t devfn; - char name[64]; - PCIIORegion io_regions[PCI_NUM_REGIONS]; - AddressSpace bus_master_as; - MemoryRegion bus_master_enable_region; - DMAContext *dma; - - /* do not access the following fields */ - PCIConfigReadFunc *config_read; - PCIConfigWriteFunc *config_write; - - /* IRQ objects for the INTA-INTD pins. */ - qemu_irq *irq; - - /* Current IRQ levels. Used internally by the generic PCI code. */ - uint8_t irq_state; - - /* Capability bits */ - uint32_t cap_present; - - /* Offset of MSI-X capability in config space */ - uint8_t msix_cap; - - /* MSI-X entries */ - int msix_entries_nr; - - /* Space to store MSIX table & pending bit array */ - uint8_t *msix_table; - uint8_t *msix_pba; - /* MemoryRegion container for msix exclusive BAR setup */ - MemoryRegion msix_exclusive_bar; - /* Memory Regions for MSIX table and pending bit entries. */ - MemoryRegion msix_table_mmio; - MemoryRegion msix_pba_mmio; - /* Reference-count for entries actually in use by driver. */ - unsigned *msix_entry_used; - /* MSIX function mask set or MSIX disabled */ - bool msix_function_masked; - /* Version id needed for VMState */ - int32_t version_id; - - /* Offset of MSI capability in config space */ - uint8_t msi_cap; - - /* PCI Express */ - PCIExpressDevice exp; - - /* SHPC */ - SHPCDevice *shpc; - - /* Location of option rom */ - char *romfile; - bool has_rom; - MemoryRegion rom; - uint32_t rom_bar; - - /* INTx routing notifier */ - PCIINTxRoutingNotifier intx_routing_notifier; - - /* MSI-X notifiers */ - MSIVectorUseNotifier msix_vector_use_notifier; - MSIVectorReleaseNotifier msix_vector_release_notifier; -}; - -void pci_register_bar(PCIDevice *pci_dev, int region_num, - uint8_t attr, MemoryRegion *memory); -pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num); - -int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, - uint8_t offset, uint8_t size); - -void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); - -uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id); - - -uint32_t pci_default_read_config(PCIDevice *d, - uint32_t address, int len); -void pci_default_write_config(PCIDevice *d, - uint32_t address, uint32_t val, int len); -void pci_device_save(PCIDevice *s, QEMUFile *f); -int pci_device_load(PCIDevice *s, QEMUFile *f); -MemoryRegion *pci_address_space(PCIDevice *dev); -MemoryRegion *pci_address_space_io(PCIDevice *dev); - -typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); -typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); -typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin); - -typedef enum { - PCI_HOTPLUG_DISABLED, - PCI_HOTPLUG_ENABLED, - PCI_COLDPLUG_ENABLED, -} PCIHotplugState; - -typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, - PCIHotplugState state); -void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, - const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - uint8_t devfn_min); -PCIBus *pci_bus_new(DeviceState *parent, const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - uint8_t devfn_min); -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *irq_opaque, int nirq); -int pci_bus_get_irq_level(PCIBus *bus, int irq_num); -void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev); -/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */ -int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin); -PCIBus *pci_register_bus(DeviceState *parent, const char *name, - pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *irq_opaque, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - uint8_t devfn_min, int nirq); -void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn); -PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin); -bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new); -void pci_bus_fire_intx_routing_notifier(PCIBus *bus); -void pci_device_set_intx_routing_notifier(PCIDevice *dev, - PCIINTxRoutingNotifier notifier); -void pci_device_reset(PCIDevice *dev); -void pci_bus_reset(PCIBus *bus); - -PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, - const char *default_devaddr); -PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, - const char *default_devaddr); - -PCIDevice *pci_vga_init(PCIBus *bus); - -int pci_bus_num(PCIBus *s); -void pci_for_each_device(PCIBus *bus, int bus_num, - void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque), - void *opaque); -PCIBus *pci_find_root_bus(int domain); -int pci_find_domain(const PCIBus *bus); -PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn); -int pci_qdev_find_device(const char *id, PCIDevice **pdev); -PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr); - -int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, - unsigned *slotp); - -void pci_device_deassert_intx(PCIDevice *dev); - -typedef DMAContext *(*PCIDMAContextFunc)(PCIBus *, void *, int); - -void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque); - -static inline void -pci_set_byte(uint8_t *config, uint8_t val) -{ - *config = val; -} - -static inline uint8_t -pci_get_byte(const uint8_t *config) -{ - return *config; -} - -static inline void -pci_set_word(uint8_t *config, uint16_t val) -{ - cpu_to_le16wu((uint16_t *)config, val); -} - -static inline uint16_t -pci_get_word(const uint8_t *config) -{ - return le16_to_cpupu((const uint16_t *)config); -} - -static inline void -pci_set_long(uint8_t *config, uint32_t val) -{ - cpu_to_le32wu((uint32_t *)config, val); -} - -static inline uint32_t -pci_get_long(const uint8_t *config) -{ - return le32_to_cpupu((const uint32_t *)config); -} - -static inline void -pci_set_quad(uint8_t *config, uint64_t val) -{ - cpu_to_le64w((uint64_t *)config, val); -} - -static inline uint64_t -pci_get_quad(const uint8_t *config) -{ - return le64_to_cpup((const uint64_t *)config); -} - -static inline void -pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val) -{ - pci_set_word(&pci_config[PCI_VENDOR_ID], val); -} - -static inline void -pci_config_set_device_id(uint8_t *pci_config, uint16_t val) -{ - pci_set_word(&pci_config[PCI_DEVICE_ID], val); -} - -static inline void -pci_config_set_revision(uint8_t *pci_config, uint8_t val) -{ - pci_set_byte(&pci_config[PCI_REVISION_ID], val); -} - -static inline void -pci_config_set_class(uint8_t *pci_config, uint16_t val) -{ - pci_set_word(&pci_config[PCI_CLASS_DEVICE], val); -} - -static inline void -pci_config_set_prog_interface(uint8_t *pci_config, uint8_t val) -{ - pci_set_byte(&pci_config[PCI_CLASS_PROG], val); -} - -static inline void -pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val) -{ - pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val); -} - -/* - * helper functions to do bit mask operation on configuration space. - * Just to set bit, use test-and-set and discard returned value. - * Just to clear bit, use test-and-clear and discard returned value. - * NOTE: They aren't atomic. - */ -static inline uint8_t -pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask) -{ - uint8_t val = pci_get_byte(config); - pci_set_byte(config, val & ~mask); - return val & mask; -} - -static inline uint8_t -pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask) -{ - uint8_t val = pci_get_byte(config); - pci_set_byte(config, val | mask); - return val & mask; -} - -static inline uint16_t -pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask) -{ - uint16_t val = pci_get_word(config); - pci_set_word(config, val & ~mask); - return val & mask; -} - -static inline uint16_t -pci_word_test_and_set_mask(uint8_t *config, uint16_t mask) -{ - uint16_t val = pci_get_word(config); - pci_set_word(config, val | mask); - return val & mask; -} - -static inline uint32_t -pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask) -{ - uint32_t val = pci_get_long(config); - pci_set_long(config, val & ~mask); - return val & mask; -} - -static inline uint32_t -pci_long_test_and_set_mask(uint8_t *config, uint32_t mask) -{ - uint32_t val = pci_get_long(config); - pci_set_long(config, val | mask); - return val & mask; -} - -static inline uint64_t -pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask) -{ - uint64_t val = pci_get_quad(config); - pci_set_quad(config, val & ~mask); - return val & mask; -} - -static inline uint64_t -pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask) -{ - uint64_t val = pci_get_quad(config); - pci_set_quad(config, val | mask); - return val & mask; -} - -/* Access a register specified by a mask */ -static inline void -pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg) -{ - uint8_t val = pci_get_byte(config); - uint8_t rval = reg << (ffs(mask) - 1); - pci_set_byte(config, (~mask & val) | (mask & rval)); -} - -static inline uint8_t -pci_get_byte_by_mask(uint8_t *config, uint8_t mask) -{ - uint8_t val = pci_get_byte(config); - return (val & mask) >> (ffs(mask) - 1); -} - -static inline void -pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg) -{ - uint16_t val = pci_get_word(config); - uint16_t rval = reg << (ffs(mask) - 1); - pci_set_word(config, (~mask & val) | (mask & rval)); -} - -static inline uint16_t -pci_get_word_by_mask(uint8_t *config, uint16_t mask) -{ - uint16_t val = pci_get_word(config); - return (val & mask) >> (ffs(mask) - 1); -} - -static inline void -pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg) -{ - uint32_t val = pci_get_long(config); - uint32_t rval = reg << (ffs(mask) - 1); - pci_set_long(config, (~mask & val) | (mask & rval)); -} - -static inline uint32_t -pci_get_long_by_mask(uint8_t *config, uint32_t mask) -{ - uint32_t val = pci_get_long(config); - return (val & mask) >> (ffs(mask) - 1); -} - -static inline void -pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg) -{ - uint64_t val = pci_get_quad(config); - uint64_t rval = reg << (ffs(mask) - 1); - pci_set_quad(config, (~mask & val) | (mask & rval)); -} - -static inline uint64_t -pci_get_quad_by_mask(uint8_t *config, uint64_t mask) -{ - uint64_t val = pci_get_quad(config); - return (val & mask) >> (ffs(mask) - 1); -} - -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, - const char *name); -PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, - bool multifunction, - const char *name); -PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); -PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name); - -static inline int pci_is_express(const PCIDevice *d) -{ - return d->cap_present & QEMU_PCI_CAP_EXPRESS; -} - -static inline uint32_t pci_config_size(const PCIDevice *d) -{ - return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; -} - -/* DMA access functions */ -static inline DMAContext *pci_dma_context(PCIDevice *dev) -{ - return dev->dma; -} - -static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, - void *buf, dma_addr_t len, DMADirection dir) -{ - dma_memory_rw(pci_dma_context(dev), addr, buf, len, dir); - return 0; -} - -static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr, - void *buf, dma_addr_t len) -{ - return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE); -} - -static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr, - const void *buf, dma_addr_t len) -{ - return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE); -} - -#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ - static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \ - dma_addr_t addr) \ - { \ - return ld##_l##_dma(pci_dma_context(dev), addr); \ - } \ - static inline void st##_s##_pci_dma(PCIDevice *dev, \ - dma_addr_t addr, uint##_bits##_t val) \ - { \ - st##_s##_dma(pci_dma_context(dev), addr, val); \ - } - -PCI_DMA_DEFINE_LDST(ub, b, 8); -PCI_DMA_DEFINE_LDST(uw_le, w_le, 16) -PCI_DMA_DEFINE_LDST(l_le, l_le, 32); -PCI_DMA_DEFINE_LDST(q_le, q_le, 64); -PCI_DMA_DEFINE_LDST(uw_be, w_be, 16) -PCI_DMA_DEFINE_LDST(l_be, l_be, 32); -PCI_DMA_DEFINE_LDST(q_be, q_be, 64); - -#undef PCI_DMA_DEFINE_LDST - -static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, - dma_addr_t *plen, DMADirection dir) -{ - void *buf; - - buf = dma_memory_map(pci_dma_context(dev), addr, plen, dir); - return buf; -} - -static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len, - DMADirection dir, dma_addr_t access_len) -{ - dma_memory_unmap(pci_dma_context(dev), buffer, len, dir, access_len); -} - -static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev, - int alloc_hint) -{ - qemu_sglist_init(qsg, alloc_hint, pci_dma_context(dev)); -} - -extern const VMStateDescription vmstate_pci_device; - -#define VMSTATE_PCI_DEVICE(_field, _state) { \ - .name = (stringify(_field)), \ - .size = sizeof(PCIDevice), \ - .vmsd = &vmstate_pci_device, \ - .flags = VMS_STRUCT, \ - .offset = vmstate_offset_value(_state, _field, PCIDevice), \ -} - -#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { \ - .name = (stringify(_field)), \ - .size = sizeof(PCIDevice), \ - .vmsd = &vmstate_pci_device, \ - .flags = VMS_STRUCT|VMS_POINTER, \ - .offset = vmstate_offset_pointer(_state, _field, PCIDevice), \ -} - -#endif diff --git a/hw/pci/Makefile.objs b/hw/pci/Makefile.objs new file mode 100644 index 0000000..9d21952 --- /dev/null +++ b/hw/pci/Makefile.objs @@ -0,0 +1,6 @@ +common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o +common-obj-$(CONFIG_PCI) += msix.o msi.o +common-obj-$(CONFIG_PCI) += shpc.o +common-obj-$(CONFIG_PCI) += slotid_cap.o +common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o +common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o diff --git a/hw/pci/msi.c b/hw/pci/msi.c new file mode 100644 index 0000000..33037a8 --- /dev/null +++ b/hw/pci/msi.c @@ -0,0 +1,395 @@ +/* + * msi.c + * + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "msi.h" +#include "range.h" + +/* Eventually those constants should go to Linux pci_regs.h */ +#define PCI_MSI_PENDING_32 0x10 +#define PCI_MSI_PENDING_64 0x14 + +/* PCI_MSI_ADDRESS_LO */ +#define PCI_MSI_ADDRESS_LO_MASK (~0x3) + +/* If we get rid of cap allocator, we won't need those. */ +#define PCI_MSI_32_SIZEOF 0x0a +#define PCI_MSI_64_SIZEOF 0x0e +#define PCI_MSI_32M_SIZEOF 0x14 +#define PCI_MSI_64M_SIZEOF 0x18 + +#define PCI_MSI_VECTORS_MAX 32 + +/* Flag for interrupt controller to declare MSI/MSI-X support */ +bool msi_supported; + +/* If we get rid of cap allocator, we won't need this. */ +static inline uint8_t msi_cap_sizeof(uint16_t flags) +{ + switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) { + case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT: + return PCI_MSI_64M_SIZEOF; + case PCI_MSI_FLAGS_64BIT: + return PCI_MSI_64_SIZEOF; + case PCI_MSI_FLAGS_MASKBIT: + return PCI_MSI_32M_SIZEOF; + case 0: + return PCI_MSI_32_SIZEOF; + default: + abort(); + break; + } + return 0; +} + +//#define MSI_DEBUG + +#ifdef MSI_DEBUG +# define MSI_DPRINTF(fmt, ...) \ + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) +#else +# define MSI_DPRINTF(fmt, ...) do { } while (0) +#endif +#define MSI_DEV_PRINTF(dev, fmt, ...) \ + MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) + +static inline unsigned int msi_nr_vectors(uint16_t flags) +{ + return 1U << + ((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1)); +} + +static inline uint8_t msi_flags_off(const PCIDevice* dev) +{ + return dev->msi_cap + PCI_MSI_FLAGS; +} + +static inline uint8_t msi_address_lo_off(const PCIDevice* dev) +{ + return dev->msi_cap + PCI_MSI_ADDRESS_LO; +} + +static inline uint8_t msi_address_hi_off(const PCIDevice* dev) +{ + return dev->msi_cap + PCI_MSI_ADDRESS_HI; +} + +static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit) +{ + return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32); +} + +static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit) +{ + return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32); +} + +static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit) +{ + return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_PENDING_32); +} + +/* + * Special API for POWER to configure the vectors through + * a side channel. Should never be used by devices. + */ +void msi_set_message(PCIDevice *dev, MSIMessage msg) +{ + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; + + if (msi64bit) { + pci_set_quad(dev->config + msi_address_lo_off(dev), msg.address); + } else { + pci_set_long(dev->config + msi_address_lo_off(dev), msg.address); + } + pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data); +} + +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) +{ + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; + unsigned int nr_vectors = msi_nr_vectors(flags); + MSIMessage msg; + + assert(vector < nr_vectors); + + if (msi64bit) { + msg.address = pci_get_quad(dev->config + msi_address_lo_off(dev)); + } else { + msg.address = pci_get_long(dev->config + msi_address_lo_off(dev)); + } + + /* upper bit 31:16 is zero */ + msg.data = pci_get_word(dev->config + msi_data_off(dev, msi64bit)); + if (nr_vectors > 1) { + msg.data &= ~(nr_vectors - 1); + msg.data |= vector; + } + + return msg; +} + +bool msi_enabled(const PCIDevice *dev) +{ + return msi_present(dev) && + (pci_get_word(dev->config + msi_flags_off(dev)) & + PCI_MSI_FLAGS_ENABLE); +} + +int msi_init(struct PCIDevice *dev, uint8_t offset, + unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask) +{ + unsigned int vectors_order; + uint16_t flags; + uint8_t cap_size; + int config_offset; + + if (!msi_supported) { + return -ENOTSUP; + } + + MSI_DEV_PRINTF(dev, + "init offset: 0x%"PRIx8" vector: %"PRId8 + " 64bit %d mask %d\n", + offset, nr_vectors, msi64bit, msi_per_vector_mask); + + assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */ + assert(nr_vectors > 0); + assert(nr_vectors <= PCI_MSI_VECTORS_MAX); + /* the nr of MSI vectors is up to 32 */ + vectors_order = ffs(nr_vectors) - 1; + + flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1); + if (msi64bit) { + flags |= PCI_MSI_FLAGS_64BIT; + } + if (msi_per_vector_mask) { + flags |= PCI_MSI_FLAGS_MASKBIT; + } + + cap_size = msi_cap_sizeof(flags); + config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size); + if (config_offset < 0) { + return config_offset; + } + + dev->msi_cap = config_offset; + dev->cap_present |= QEMU_PCI_CAP_MSI; + + pci_set_word(dev->config + msi_flags_off(dev), flags); + pci_set_word(dev->wmask + msi_flags_off(dev), + PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); + pci_set_long(dev->wmask + msi_address_lo_off(dev), + PCI_MSI_ADDRESS_LO_MASK); + if (msi64bit) { + pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff); + } + pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff); + + if (msi_per_vector_mask) { + /* Make mask bits 0 to nr_vectors - 1 writable. */ + pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit), + 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors)); + } + return config_offset; +} + +void msi_uninit(struct PCIDevice *dev) +{ + uint16_t flags; + uint8_t cap_size; + + if (!msi_present(dev)) { + return; + } + flags = pci_get_word(dev->config + msi_flags_off(dev)); + cap_size = msi_cap_sizeof(flags); + pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size); + dev->cap_present &= ~QEMU_PCI_CAP_MSI; + + MSI_DEV_PRINTF(dev, "uninit\n"); +} + +void msi_reset(PCIDevice *dev) +{ + uint16_t flags; + bool msi64bit; + + if (!msi_present(dev)) { + return; + } + + flags = pci_get_word(dev->config + msi_flags_off(dev)); + flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); + msi64bit = flags & PCI_MSI_FLAGS_64BIT; + + pci_set_word(dev->config + msi_flags_off(dev), flags); + pci_set_long(dev->config + msi_address_lo_off(dev), 0); + if (msi64bit) { + pci_set_long(dev->config + msi_address_hi_off(dev), 0); + } + pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0); + if (flags & PCI_MSI_FLAGS_MASKBIT) { + pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0); + pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0); + } + MSI_DEV_PRINTF(dev, "reset\n"); +} + +static bool msi_is_masked(const PCIDevice *dev, unsigned int vector) +{ + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); + uint32_t mask; + assert(vector < PCI_MSI_VECTORS_MAX); + + if (!(flags & PCI_MSI_FLAGS_MASKBIT)) { + return false; + } + + mask = pci_get_long(dev->config + + msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT)); + return mask & (1U << vector); +} + +void msi_notify(PCIDevice *dev, unsigned int vector) +{ + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; + unsigned int nr_vectors = msi_nr_vectors(flags); + MSIMessage msg; + + assert(vector < nr_vectors); + if (msi_is_masked(dev, vector)) { + assert(flags & PCI_MSI_FLAGS_MASKBIT); + pci_long_test_and_set_mask( + dev->config + msi_pending_off(dev, msi64bit), 1U << vector); + MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector); + return; + } + + msg = msi_get_message(dev, vector); + + MSI_DEV_PRINTF(dev, + "notify vector 0x%x" + " address: 0x%"PRIx64" data: 0x%"PRIx32"\n", + vector, msg.address, msg.data); + stl_le_phys(msg.address, msg.data); +} + +/* Normally called by pci_default_write_config(). */ +void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len) +{ + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; + bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT; + unsigned int nr_vectors; + uint8_t log_num_vecs; + uint8_t log_max_vecs; + unsigned int vector; + uint32_t pending; + + if (!msi_present(dev) || + !ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) { + return; + } + +#ifdef MSI_DEBUG + MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n", + addr, val, len); + MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32, + flags, + pci_get_long(dev->config + msi_address_lo_off(dev))); + if (msi64bit) { + fprintf(stderr, " address-hi: 0x%"PRIx32, + pci_get_long(dev->config + msi_address_hi_off(dev))); + } + fprintf(stderr, " data: 0x%"PRIx16, + pci_get_word(dev->config + msi_data_off(dev, msi64bit))); + if (flags & PCI_MSI_FLAGS_MASKBIT) { + fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32, + pci_get_long(dev->config + msi_mask_off(dev, msi64bit)), + pci_get_long(dev->config + msi_pending_off(dev, msi64bit))); + } + fprintf(stderr, "\n"); +#endif + + if (!(flags & PCI_MSI_FLAGS_ENABLE)) { + return; + } + + /* + * Now MSI is enabled, clear INTx# interrupts. + * the driver is prohibited from writing enable bit to mask + * a service request. But the guest OS could do this. + * So we just discard the interrupts as moderate fallback. + * + * 6.8.3.3. Enabling Operation + * While enabled for MSI or MSI-X operation, a function is prohibited + * from using its INTx# pin (if implemented) to request + * service (MSI, MSI-X, and INTx# are mutually exclusive). + */ + pci_device_deassert_intx(dev); + + /* + * nr_vectors might be set bigger than capable. So clamp it. + * This is not legal by spec, so we can do anything we like, + * just don't crash the host + */ + log_num_vecs = + (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1); + log_max_vecs = + (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1); + if (log_num_vecs > log_max_vecs) { + flags &= ~PCI_MSI_FLAGS_QSIZE; + flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1); + pci_set_word(dev->config + msi_flags_off(dev), flags); + } + + if (!msi_per_vector_mask) { + /* if per vector masking isn't supported, + there is no pending interrupt. */ + return; + } + + nr_vectors = msi_nr_vectors(flags); + + /* This will discard pending interrupts, if any. */ + pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit)); + pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors); + pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending); + + /* deliver pending interrupts which are unmasked */ + for (vector = 0; vector < nr_vectors; ++vector) { + if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) { + continue; + } + + pci_long_test_and_clear_mask( + dev->config + msi_pending_off(dev, msi64bit), 1U << vector); + msi_notify(dev, vector); + } +} + +unsigned int msi_nr_vectors_allocated(const PCIDevice *dev) +{ + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); + return msi_nr_vectors(flags); +} diff --git a/hw/pci/msi.h b/hw/pci/msi.h new file mode 100644 index 0000000..150b09a --- /dev/null +++ b/hw/pci/msi.h @@ -0,0 +1,50 @@ +/* + * msi.h + * + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_MSI_H +#define QEMU_MSI_H + +#include "qemu-common.h" +#include "pci.h" + +struct MSIMessage { + uint64_t address; + uint32_t data; +}; + +extern bool msi_supported; + +void msi_set_message(PCIDevice *dev, MSIMessage msg); +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector); +bool msi_enabled(const PCIDevice *dev); +int msi_init(struct PCIDevice *dev, uint8_t offset, + unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask); +void msi_uninit(struct PCIDevice *dev); +void msi_reset(PCIDevice *dev); +void msi_notify(PCIDevice *dev, unsigned int vector); +void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); +unsigned int msi_nr_vectors_allocated(const PCIDevice *dev); + +static inline bool msi_present(const PCIDevice *dev) +{ + return dev->cap_present & QEMU_PCI_CAP_MSI; +} + +#endif /* QEMU_MSI_H */ diff --git a/hw/pci/msix.c b/hw/pci/msix.c new file mode 100644 index 0000000..136ef09 --- /dev/null +++ b/hw/pci/msix.c @@ -0,0 +1,562 @@ +/* + * MSI-X device support + * + * This module includes support for MSI-X in pci devices. + * + * Author: Michael S. Tsirkin <mst@redhat.com> + * + * 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 the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "hw.h" +#include "msi.h" +#include "msix.h" +#include "pci.h" +#include "range.h" + +#define MSIX_CAP_LENGTH 12 + +/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */ +#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1) +#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8) +#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8) + +static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) +{ + uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; + MSIMessage msg; + + msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); + msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); + return msg; +} + +/* + * Special API for POWER to configure the vectors through + * a side channel. Should never be used by devices. + */ +void msix_set_message(PCIDevice *dev, int vector, struct MSIMessage msg) +{ + uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; + + pci_set_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR, msg.address); + pci_set_long(table_entry + PCI_MSIX_ENTRY_DATA, msg.data); + table_entry[PCI_MSIX_ENTRY_VECTOR_CTRL] &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; +} + +static uint8_t msix_pending_mask(int vector) +{ + return 1 << (vector % 8); +} + +static uint8_t *msix_pending_byte(PCIDevice *dev, int vector) +{ + return dev->msix_pba + vector / 8; +} + +static int msix_is_pending(PCIDevice *dev, int vector) +{ + return *msix_pending_byte(dev, vector) & msix_pending_mask(vector); +} + +static void msix_set_pending(PCIDevice *dev, int vector) +{ + *msix_pending_byte(dev, vector) |= msix_pending_mask(vector); +} + +static void msix_clr_pending(PCIDevice *dev, int vector) +{ + *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector); +} + +static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask) +{ + unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; + return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT; +} + +static bool msix_is_masked(PCIDevice *dev, int vector) +{ + return msix_vector_masked(dev, vector, dev->msix_function_masked); +} + +static void msix_fire_vector_notifier(PCIDevice *dev, + unsigned int vector, bool is_masked) +{ + MSIMessage msg; + int ret; + + if (!dev->msix_vector_use_notifier) { + return; + } + if (is_masked) { + dev->msix_vector_release_notifier(dev, vector); + } else { + msg = msix_get_message(dev, vector); + ret = dev->msix_vector_use_notifier(dev, vector, msg); + assert(ret >= 0); + } +} + +static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked) +{ + bool is_masked = msix_is_masked(dev, vector); + + if (is_masked == was_masked) { + return; + } + + msix_fire_vector_notifier(dev, vector, is_masked); + + if (!is_masked && msix_is_pending(dev, vector)) { + msix_clr_pending(dev, vector); + msix_notify(dev, vector); + } +} + +static void msix_update_function_masked(PCIDevice *dev) +{ + dev->msix_function_masked = !msix_enabled(dev) || + (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK); +} + +/* Handle MSI-X capability config write. */ +void msix_write_config(PCIDevice *dev, uint32_t addr, + uint32_t val, int len) +{ + unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET; + int vector; + bool was_masked; + + if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) { + return; + } + + was_masked = dev->msix_function_masked; + msix_update_function_masked(dev); + + if (!msix_enabled(dev)) { + return; + } + + pci_device_deassert_intx(dev); + + if (dev->msix_function_masked == was_masked) { + return; + } + + for (vector = 0; vector < dev->msix_entries_nr; ++vector) { + msix_handle_mask_update(dev, vector, + msix_vector_masked(dev, vector, was_masked)); + } +} + +static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr, + unsigned size) +{ + PCIDevice *dev = opaque; + + return pci_get_long(dev->msix_table + addr); +} + +static void msix_table_mmio_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + PCIDevice *dev = opaque; + int vector = addr / PCI_MSIX_ENTRY_SIZE; + bool was_masked; + + was_masked = msix_is_masked(dev, vector); + pci_set_long(dev->msix_table + addr, val); + msix_handle_mask_update(dev, vector, was_masked); +} + +static const MemoryRegionOps msix_table_mmio_ops = { + .read = msix_table_mmio_read, + .write = msix_table_mmio_write, + /* TODO: MSIX should be LITTLE_ENDIAN. */ + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, + unsigned size) +{ + PCIDevice *dev = opaque; + + return pci_get_long(dev->msix_pba + addr); +} + +static const MemoryRegionOps msix_pba_mmio_ops = { + .read = msix_pba_mmio_read, + /* TODO: MSIX should be LITTLE_ENDIAN. */ + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) +{ + int vector; + + for (vector = 0; vector < nentries; ++vector) { + unsigned offset = + vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; + bool was_masked = msix_is_masked(dev, vector); + + dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT; + msix_handle_mask_update(dev, vector, was_masked); + } +} + +/* Initialize the MSI-X structures */ +int msix_init(struct PCIDevice *dev, unsigned short nentries, + MemoryRegion *table_bar, uint8_t table_bar_nr, + unsigned table_offset, MemoryRegion *pba_bar, + uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos) +{ + int cap; + unsigned table_size, pba_size; + uint8_t *config; + + /* Nothing to do if MSI is not supported by interrupt controller */ + if (!msi_supported) { + return -ENOTSUP; + } + + if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) { + return -EINVAL; + } + + table_size = nentries * PCI_MSIX_ENTRY_SIZE; + pba_size = QEMU_ALIGN_UP(nentries, 64) / 8; + + /* Sanity test: table & pba don't overlap, fit within BARs, min aligned */ + if ((table_bar_nr == pba_bar_nr && + ranges_overlap(table_offset, table_size, pba_offset, pba_size)) || + table_offset + table_size > memory_region_size(table_bar) || + pba_offset + pba_size > memory_region_size(pba_bar) || + (table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) { + return -EINVAL; + } + + cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH); + if (cap < 0) { + return cap; + } + + dev->msix_cap = cap; + dev->cap_present |= QEMU_PCI_CAP_MSIX; + config = dev->config + cap; + + pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1); + dev->msix_entries_nr = nentries; + dev->msix_function_masked = true; + + pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_nr); + pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr); + + /* Make flags bit writable. */ + dev->wmask[cap + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK | + MSIX_MASKALL_MASK; + + dev->msix_table = g_malloc0(table_size); + dev->msix_pba = g_malloc0(pba_size); + dev->msix_entry_used = g_malloc0(nentries * sizeof *dev->msix_entry_used); + + msix_mask_all(dev, nentries); + + memory_region_init_io(&dev->msix_table_mmio, &msix_table_mmio_ops, dev, + "msix-table", table_size); + memory_region_add_subregion(table_bar, table_offset, &dev->msix_table_mmio); + memory_region_init_io(&dev->msix_pba_mmio, &msix_pba_mmio_ops, dev, + "msix-pba", pba_size); + memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio); + + return 0; +} + +int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, + uint8_t bar_nr) +{ + int ret; + char *name; + + /* + * Migration compatibility dictates that this remains a 4k + * BAR with the vector table in the lower half and PBA in + * the upper half. Do not use these elsewhere! + */ +#define MSIX_EXCLUSIVE_BAR_SIZE 4096 +#define MSIX_EXCLUSIVE_BAR_TABLE_OFFSET 0 +#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2) +#define MSIX_EXCLUSIVE_CAP_OFFSET 0 + + if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) { + return -EINVAL; + } + + name = g_strdup_printf("%s-msix", dev->name); + memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE); + g_free(name); + + ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr, + MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar, + bar_nr, MSIX_EXCLUSIVE_BAR_PBA_OFFSET, + MSIX_EXCLUSIVE_CAP_OFFSET); + if (ret) { + memory_region_destroy(&dev->msix_exclusive_bar); + return ret; + } + + pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY, + &dev->msix_exclusive_bar); + + return 0; +} + +static void msix_free_irq_entries(PCIDevice *dev) +{ + int vector; + + for (vector = 0; vector < dev->msix_entries_nr; ++vector) { + dev->msix_entry_used[vector] = 0; + msix_clr_pending(dev, vector); + } +} + +static void msix_clear_all_vectors(PCIDevice *dev) +{ + int vector; + + for (vector = 0; vector < dev->msix_entries_nr; ++vector) { + msix_clr_pending(dev, vector); + } +} + +/* Clean up resources for the device. */ +void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar) +{ + if (!msix_present(dev)) { + return; + } + pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH); + dev->msix_cap = 0; + msix_free_irq_entries(dev); + dev->msix_entries_nr = 0; + memory_region_del_subregion(pba_bar, &dev->msix_pba_mmio); + memory_region_destroy(&dev->msix_pba_mmio); + g_free(dev->msix_pba); + dev->msix_pba = NULL; + memory_region_del_subregion(table_bar, &dev->msix_table_mmio); + memory_region_destroy(&dev->msix_table_mmio); + g_free(dev->msix_table); + dev->msix_table = NULL; + g_free(dev->msix_entry_used); + dev->msix_entry_used = NULL; + dev->cap_present &= ~QEMU_PCI_CAP_MSIX; +} + +void msix_uninit_exclusive_bar(PCIDevice *dev) +{ + if (msix_present(dev)) { + msix_uninit(dev, &dev->msix_exclusive_bar, &dev->msix_exclusive_bar); + memory_region_destroy(&dev->msix_exclusive_bar); + } +} + +void msix_save(PCIDevice *dev, QEMUFile *f) +{ + unsigned n = dev->msix_entries_nr; + + if (!msix_present(dev)) { + return; + } + + qemu_put_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); + qemu_put_buffer(f, dev->msix_pba, (n + 7) / 8); +} + +/* Should be called after restoring the config space. */ +void msix_load(PCIDevice *dev, QEMUFile *f) +{ + unsigned n = dev->msix_entries_nr; + unsigned int vector; + + if (!msix_present(dev)) { + return; + } + + msix_clear_all_vectors(dev); + qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); + qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8); + msix_update_function_masked(dev); + + for (vector = 0; vector < n; vector++) { + msix_handle_mask_update(dev, vector, true); + } +} + +/* Does device support MSI-X? */ +int msix_present(PCIDevice *dev) +{ + return dev->cap_present & QEMU_PCI_CAP_MSIX; +} + +/* Is MSI-X enabled? */ +int msix_enabled(PCIDevice *dev) +{ + return (dev->cap_present & QEMU_PCI_CAP_MSIX) && + (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & + MSIX_ENABLE_MASK); +} + +/* Send an MSI-X message */ +void msix_notify(PCIDevice *dev, unsigned vector) +{ + MSIMessage msg; + + if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) + return; + if (msix_is_masked(dev, vector)) { + msix_set_pending(dev, vector); + return; + } + + msg = msix_get_message(dev, vector); + + stl_le_phys(msg.address, msg.data); +} + +void msix_reset(PCIDevice *dev) +{ + if (!msix_present(dev)) { + return; + } + msix_clear_all_vectors(dev); + dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &= + ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET]; + memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE); + memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8); + msix_mask_all(dev, dev->msix_entries_nr); +} + +/* PCI spec suggests that devices make it possible for software to configure + * less vectors than supported by the device, but does not specify a standard + * mechanism for devices to do so. + * + * We support this by asking devices to declare vectors software is going to + * actually use, and checking this on the notification path. Devices that + * don't want to follow the spec suggestion can declare all vectors as used. */ + +/* Mark vector as used. */ +int msix_vector_use(PCIDevice *dev, unsigned vector) +{ + if (vector >= dev->msix_entries_nr) + return -EINVAL; + dev->msix_entry_used[vector]++; + return 0; +} + +/* Mark vector as unused. */ +void msix_vector_unuse(PCIDevice *dev, unsigned vector) +{ + if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) { + return; + } + if (--dev->msix_entry_used[vector]) { + return; + } + msix_clr_pending(dev, vector); +} + +void msix_unuse_all_vectors(PCIDevice *dev) +{ + if (!msix_present(dev)) { + return; + } + msix_free_irq_entries(dev); +} + +unsigned int msix_nr_vectors_allocated(const PCIDevice *dev) +{ + return dev->msix_entries_nr; +} + +static int msix_set_notifier_for_vector(PCIDevice *dev, unsigned int vector) +{ + MSIMessage msg; + + if (msix_is_masked(dev, vector)) { + return 0; + } + msg = msix_get_message(dev, vector); + return dev->msix_vector_use_notifier(dev, vector, msg); +} + +static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector) +{ + if (msix_is_masked(dev, vector)) { + return; + } + dev->msix_vector_release_notifier(dev, vector); +} + +int msix_set_vector_notifiers(PCIDevice *dev, + MSIVectorUseNotifier use_notifier, + MSIVectorReleaseNotifier release_notifier) +{ + int vector, ret; + + assert(use_notifier && release_notifier); + + dev->msix_vector_use_notifier = use_notifier; + dev->msix_vector_release_notifier = release_notifier; + + if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & + (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { + for (vector = 0; vector < dev->msix_entries_nr; vector++) { + ret = msix_set_notifier_for_vector(dev, vector); + if (ret < 0) { + goto undo; + } + } + } + return 0; + +undo: + while (--vector >= 0) { + msix_unset_notifier_for_vector(dev, vector); + } + dev->msix_vector_use_notifier = NULL; + dev->msix_vector_release_notifier = NULL; + return ret; +} + +void msix_unset_vector_notifiers(PCIDevice *dev) +{ + int vector; + + assert(dev->msix_vector_use_notifier && + dev->msix_vector_release_notifier); + + if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & + (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { + for (vector = 0; vector < dev->msix_entries_nr; vector++) { + msix_unset_notifier_for_vector(dev, vector); + } + } + dev->msix_vector_use_notifier = NULL; + dev->msix_vector_release_notifier = NULL; +} diff --git a/hw/pci/msix.h b/hw/pci/msix.h new file mode 100644 index 0000000..15211cb --- /dev/null +++ b/hw/pci/msix.h @@ -0,0 +1,41 @@ +#ifndef QEMU_MSIX_H +#define QEMU_MSIX_H + +#include "qemu-common.h" +#include "pci.h" + +void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg); +int msix_init(PCIDevice *dev, unsigned short nentries, + MemoryRegion *table_bar, uint8_t table_bar_nr, + unsigned table_offset, MemoryRegion *pba_bar, + uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos); +int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, + uint8_t bar_nr); + +void msix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len); + +void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, + MemoryRegion *pba_bar); +void msix_uninit_exclusive_bar(PCIDevice *dev); + +unsigned int msix_nr_vectors_allocated(const PCIDevice *dev); + +void msix_save(PCIDevice *dev, QEMUFile *f); +void msix_load(PCIDevice *dev, QEMUFile *f); + +int msix_enabled(PCIDevice *dev); +int msix_present(PCIDevice *dev); + +int msix_vector_use(PCIDevice *dev, unsigned vector); +void msix_vector_unuse(PCIDevice *dev, unsigned vector); +void msix_unuse_all_vectors(PCIDevice *dev); + +void msix_notify(PCIDevice *dev, unsigned vector); + +void msix_reset(PCIDevice *dev); + +int msix_set_vector_notifiers(PCIDevice *dev, + MSIVectorUseNotifier use_notifier, + MSIVectorReleaseNotifier release_notifier); +void msix_unset_vector_notifiers(PCIDevice *dev); +#endif diff --git a/hw/pci/pci-hotplug.c b/hw/pci/pci-hotplug.c new file mode 100644 index 0000000..0ca5546 --- /dev/null +++ b/hw/pci/pci-hotplug.c @@ -0,0 +1,293 @@ +/* + * QEMU PCI hotplug support + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw.h" +#include "boards.h" +#include "pci.h" +#include "net.h" +#include "pc.h" +#include "monitor.h" +#include "scsi.h" +#include "virtio-blk.h" +#include "qemu-config.h" +#include "blockdev.h" +#include "error.h" + +#if defined(TARGET_I386) +static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, + const char *devaddr, + const char *opts_str) +{ + Error *local_err = NULL; + QemuOpts *opts; + PCIBus *bus; + int ret, devfn; + + bus = pci_get_bus_devfn(&devfn, devaddr); + if (!bus) { + monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); + return NULL; + } + if (!((BusState*)bus)->allow_hotplug) { + monitor_printf(mon, "PCI bus doesn't support hotplug\n"); + return NULL; + } + + opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0); + if (!opts) { + return NULL; + } + + qemu_opt_set(opts, "type", "nic"); + + ret = net_client_init(opts, 0, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); + return NULL; + } + if (nd_table[ret].devaddr) { + monitor_printf(mon, "Parameter addr not supported\n"); + return NULL; + } + return pci_nic_init(&nd_table[ret], "rtl8139", devaddr); +} + +static int scsi_hot_add(Monitor *mon, DeviceState *adapter, + DriveInfo *dinfo, int printinfo) +{ + SCSIBus *scsibus; + SCSIDevice *scsidev; + + scsibus = (SCSIBus *) + object_dynamic_cast(OBJECT(QLIST_FIRST(&adapter->child_bus)), + TYPE_SCSI_BUS); + if (!scsibus) { + error_report("Device is not a SCSI adapter"); + return -1; + } + + /* + * drive_init() tries to find a default for dinfo->unit. Doesn't + * work at all for hotplug though as we assign the device to a + * specific bus instead of the first bus with spare scsi ids. + * + * Ditch the calculated value and reload from option string (if + * specified). + */ + dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1); + dinfo->bus = scsibus->busnr; + scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, + false, -1); + if (!scsidev) { + return -1; + } + dinfo->unit = scsidev->id; + + if (printinfo) + monitor_printf(mon, "OK bus %d, unit %d\n", + scsibus->busnr, scsidev->id); + return 0; +} + +int pci_drive_hot_add(Monitor *mon, const QDict *qdict, + DriveInfo *dinfo, int type) +{ + int dom, pci_bus; + unsigned slot; + PCIDevice *dev; + const char *pci_addr = qdict_get_str(qdict, "pci_addr"); + + switch (type) { + case IF_SCSI: + if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) { + goto err; + } + dev = pci_find_device(pci_find_root_bus(dom), pci_bus, + PCI_DEVFN(slot, 0)); + if (!dev) { + monitor_printf(mon, "no pci device with address %s\n", pci_addr); + goto err; + } + if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) != 0) { + goto err; + } + break; + default: + monitor_printf(mon, "Can't hot-add drive to type %d\n", type); + goto err; + } + + return 0; +err: + return -1; +} + +static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, + const char *devaddr, + const char *opts) +{ + PCIDevice *dev; + DriveInfo *dinfo = NULL; + int type = -1; + char buf[128]; + PCIBus *bus; + int devfn; + + if (get_param_value(buf, sizeof(buf), "if", opts)) { + if (!strcmp(buf, "scsi")) + type = IF_SCSI; + else if (!strcmp(buf, "virtio")) { + type = IF_VIRTIO; + } else { + monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf); + return NULL; + } + } else { + monitor_printf(mon, "no if= specified\n"); + return NULL; + } + + if (get_param_value(buf, sizeof(buf), "file", opts)) { + dinfo = add_init_drive(opts); + if (!dinfo) + return NULL; + if (dinfo->devaddr) { + monitor_printf(mon, "Parameter addr not supported\n"); + return NULL; + } + } else { + dinfo = NULL; + } + + bus = pci_get_bus_devfn(&devfn, devaddr); + if (!bus) { + monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); + return NULL; + } + if (!((BusState*)bus)->allow_hotplug) { + monitor_printf(mon, "PCI bus doesn't support hotplug\n"); + return NULL; + } + + switch (type) { + case IF_SCSI: + dev = pci_create(bus, devfn, "lsi53c895a"); + if (qdev_init(&dev->qdev) < 0) + dev = NULL; + if (dev && dinfo) { + if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) { + qdev_unplug(&dev->qdev, NULL); + dev = NULL; + } + } + break; + case IF_VIRTIO: + if (!dinfo) { + monitor_printf(mon, "virtio requires a backing file/device.\n"); + return NULL; + } + dev = pci_create(bus, devfn, "virtio-blk-pci"); + if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) { + qdev_free(&dev->qdev); + dev = NULL; + break; + } + if (qdev_init(&dev->qdev) < 0) + dev = NULL; + break; + default: + dev = NULL; + } + return dev; +} + +void pci_device_hot_add(Monitor *mon, const QDict *qdict) +{ + PCIDevice *dev = NULL; + const char *pci_addr = qdict_get_str(qdict, "pci_addr"); + const char *type = qdict_get_str(qdict, "type"); + const char *opts = qdict_get_try_str(qdict, "opts"); + + /* strip legacy tag */ + if (!strncmp(pci_addr, "pci_addr=", 9)) { + pci_addr += 9; + } + + if (!opts) { + opts = ""; + } + + if (!strcmp(pci_addr, "auto")) + pci_addr = NULL; + + if (strcmp(type, "nic") == 0) { + dev = qemu_pci_hot_add_nic(mon, pci_addr, opts); + } else if (strcmp(type, "storage") == 0) { + dev = qemu_pci_hot_add_storage(mon, pci_addr, opts); + } else { + monitor_printf(mon, "invalid type: %s\n", type); + } + + if (dev) { + monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n", + pci_find_domain(dev->bus), + pci_bus_num(dev->bus), PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + } else + monitor_printf(mon, "failed to add %s\n", opts); +} +#endif + +static int pci_device_hot_remove(Monitor *mon, const char *pci_addr) +{ + PCIDevice *d; + int dom, bus; + unsigned slot; + Error *local_err = NULL; + + if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) { + return -1; + } + + d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0)); + if (!d) { + monitor_printf(mon, "slot %d empty\n", slot); + return -1; + } + + qdev_unplug(&d->qdev, &local_err); + if (error_is_set(&local_err)) { + monitor_printf(mon, "%s\n", error_get_pretty(local_err)); + error_free(local_err); + return -1; + } + + return 0; +} + +void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict) +{ + pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr")); +} diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c new file mode 100644 index 0000000..134c448 --- /dev/null +++ b/hw/pci/pci-stub.c @@ -0,0 +1,47 @@ +/* + * PCI stubs for platforms that don't support pci bus. + * + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "sysemu.h" +#include "monitor.h" +#include "pci.h" +#include "qmp-commands.h" + +PciInfoList *qmp_query_pci(Error **errp) +{ + error_set(errp, QERR_UNSUPPORTED); + return NULL; +} + +static void pci_error_message(Monitor *mon) +{ + monitor_printf(mon, "PCI devices not supported\n"); +} + +int do_pcie_aer_inject_error(Monitor *mon, + const QDict *qdict, QObject **ret_data) +{ + pci_error_message(mon); + return -ENOSYS; +} + +void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) +{ + pci_error_message(mon); +} diff --git a/hw/pci/pci.c b/hw/pci/pci.c new file mode 100644 index 0000000..97a0cd7 --- /dev/null +++ b/hw/pci/pci.c @@ -0,0 +1,2168 @@ +/* + * QEMU PCI bus manager + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw.h" +#include "pci.h" +#include "pci_bridge.h" +#include "pci_internals.h" +#include "monitor.h" +#include "net.h" +#include "sysemu.h" +#include "loader.h" +#include "range.h" +#include "qmp-commands.h" +#include "msi.h" +#include "msix.h" +#include "exec-memory.h" + +//#define DEBUG_PCI +#ifdef DEBUG_PCI +# define PCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +#else +# define PCI_DPRINTF(format, ...) do { } while (0) +#endif + +static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); +static char *pcibus_get_dev_path(DeviceState *dev); +static char *pcibus_get_fw_dev_path(DeviceState *dev); +static int pcibus_reset(BusState *qbus); + +static Property pci_props[] = { + DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), + DEFINE_PROP_STRING("romfile", PCIDevice, romfile), + DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1), + DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present, + QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false), + DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present, + QEMU_PCI_CAP_SERR_BITNR, true), + DEFINE_PROP_END_OF_LIST() +}; + +static void pci_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->print_dev = pcibus_dev_print; + k->get_dev_path = pcibus_get_dev_path; + k->get_fw_dev_path = pcibus_get_fw_dev_path; + k->reset = pcibus_reset; +} + +static const TypeInfo pci_bus_info = { + .name = TYPE_PCI_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(PCIBus), + .class_init = pci_bus_class_init, +}; + +static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); +static void pci_update_mappings(PCIDevice *d); +static void pci_set_irq(void *opaque, int irq_num, int level); +static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom); +static void pci_del_option_rom(PCIDevice *pdev); + +static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET; +static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU; + +struct PCIHostBus { + int domain; + struct PCIBus *bus; + QLIST_ENTRY(PCIHostBus) next; +}; +static QLIST_HEAD(, PCIHostBus) host_buses; + +static const VMStateDescription vmstate_pcibus = { + .name = "PCIBUS", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32_EQUAL(nirq, PCIBus), + VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32, int32_t), + VMSTATE_END_OF_LIST() + } +}; +static int pci_bar(PCIDevice *d, int reg) +{ + uint8_t type; + + if (reg != PCI_ROM_SLOT) + return PCI_BASE_ADDRESS_0 + reg * 4; + + type = d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; + return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; +} + +static inline int pci_irq_state(PCIDevice *d, int irq_num) +{ + return (d->irq_state >> irq_num) & 0x1; +} + +static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level) +{ + d->irq_state &= ~(0x1 << irq_num); + d->irq_state |= level << irq_num; +} + +static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) +{ + PCIBus *bus; + for (;;) { + bus = pci_dev->bus; + irq_num = bus->map_irq(pci_dev, irq_num); + if (bus->set_irq) + break; + pci_dev = bus->parent_dev; + } + bus->irq_count[irq_num] += change; + bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); +} + +int pci_bus_get_irq_level(PCIBus *bus, int irq_num) +{ + assert(irq_num >= 0); + assert(irq_num < bus->nirq); + return !!bus->irq_count[irq_num]; +} + +/* Update interrupt status bit in config space on interrupt + * state change. */ +static void pci_update_irq_status(PCIDevice *dev) +{ + if (dev->irq_state) { + dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT; + } else { + dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; + } +} + +void pci_device_deassert_intx(PCIDevice *dev) +{ + int i; + for (i = 0; i < PCI_NUM_PINS; ++i) { + qemu_set_irq(dev->irq[i], 0); + } +} + +/* + * This function is called on #RST and FLR. + * FLR if PCI_EXP_DEVCTL_BCR_FLR is set + */ +void pci_device_reset(PCIDevice *dev) +{ + int r; + + qdev_reset_all(&dev->qdev); + + dev->irq_state = 0; + pci_update_irq_status(dev); + pci_device_deassert_intx(dev); + /* Clear all writable bits */ + pci_word_test_and_clear_mask(dev->config + PCI_COMMAND, + pci_get_word(dev->wmask + PCI_COMMAND) | + pci_get_word(dev->w1cmask + PCI_COMMAND)); + pci_word_test_and_clear_mask(dev->config + PCI_STATUS, + pci_get_word(dev->wmask + PCI_STATUS) | + pci_get_word(dev->w1cmask + PCI_STATUS)); + dev->config[PCI_CACHE_LINE_SIZE] = 0x0; + dev->config[PCI_INTERRUPT_LINE] = 0x0; + for (r = 0; r < PCI_NUM_REGIONS; ++r) { + PCIIORegion *region = &dev->io_regions[r]; + if (!region->size) { + continue; + } + + if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) && + region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_set_quad(dev->config + pci_bar(dev, r), region->type); + } else { + pci_set_long(dev->config + pci_bar(dev, r), region->type); + } + } + pci_update_mappings(dev); + + msi_reset(dev); + msix_reset(dev); +} + +/* + * Trigger pci bus reset under a given bus. + * To be called on RST# assert. + */ +void pci_bus_reset(PCIBus *bus) +{ + int i; + + for (i = 0; i < bus->nirq; i++) { + bus->irq_count[i] = 0; + } + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { + if (bus->devices[i]) { + pci_device_reset(bus->devices[i]); + } + } +} + +static int pcibus_reset(BusState *qbus) +{ + pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus)); + + /* topology traverse is done by pci_bus_reset(). + Tell qbus/qdev walker not to traverse the tree */ + return 1; +} + +static void pci_host_bus_register(int domain, PCIBus *bus) +{ + struct PCIHostBus *host; + host = g_malloc0(sizeof(*host)); + host->domain = domain; + host->bus = bus; + QLIST_INSERT_HEAD(&host_buses, host, next); +} + +PCIBus *pci_find_root_bus(int domain) +{ + struct PCIHostBus *host; + + QLIST_FOREACH(host, &host_buses, next) { + if (host->domain == domain) { + return host->bus; + } + } + + return NULL; +} + +int pci_find_domain(const PCIBus *bus) +{ + PCIDevice *d; + struct PCIHostBus *host; + + /* obtain root bus */ + while ((d = bus->parent_dev) != NULL) { + bus = d->bus; + } + + QLIST_FOREACH(host, &host_buses, next) { + if (host->bus == bus) { + return host->domain; + } + } + + abort(); /* should not be reached */ + return -1; +} + +void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, + const char *name, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io, + uint8_t devfn_min) +{ + qbus_create_inplace(&bus->qbus, TYPE_PCI_BUS, parent, name); + assert(PCI_FUNC(devfn_min) == 0); + bus->devfn_min = devfn_min; + bus->address_space_mem = address_space_mem; + bus->address_space_io = address_space_io; + + /* host bridge */ + QLIST_INIT(&bus->child); + pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */ + + vmstate_register(NULL, -1, &vmstate_pcibus, bus); +} + +PCIBus *pci_bus_new(DeviceState *parent, const char *name, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io, + uint8_t devfn_min) +{ + PCIBus *bus; + + bus = g_malloc0(sizeof(*bus)); + pci_bus_new_inplace(bus, parent, name, address_space_mem, + address_space_io, devfn_min); + OBJECT(bus)->free = g_free; + return bus; +} + +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, + void *irq_opaque, int nirq) +{ + bus->set_irq = set_irq; + bus->map_irq = map_irq; + bus->irq_opaque = irq_opaque; + bus->nirq = nirq; + bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0])); +} + +void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev) +{ + bus->qbus.allow_hotplug = 1; + bus->hotplug = hotplug; + bus->hotplug_qdev = qdev; +} + +PCIBus *pci_register_bus(DeviceState *parent, const char *name, + pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, + void *irq_opaque, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io, + uint8_t devfn_min, int nirq) +{ + PCIBus *bus; + + bus = pci_bus_new(parent, name, address_space_mem, + address_space_io, devfn_min); + pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq); + return bus; +} + +int pci_bus_num(PCIBus *s) +{ + if (!s->parent_dev) + return 0; /* pci host bridge */ + return s->parent_dev->config[PCI_SECONDARY_BUS]; +} + +static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) +{ + PCIDevice *s = container_of(pv, PCIDevice, config); + uint8_t *config; + int i; + + assert(size == pci_config_size(s)); + config = g_malloc(size); + + qemu_get_buffer(f, config, size); + for (i = 0; i < size; ++i) { + if ((config[i] ^ s->config[i]) & + s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) { + g_free(config); + return -EINVAL; + } + } + memcpy(s->config, config, size); + + pci_update_mappings(s); + + memory_region_set_enabled(&s->bus_master_enable_region, + pci_get_word(s->config + PCI_COMMAND) + & PCI_COMMAND_MASTER); + + g_free(config); + return 0; +} + +/* just put buffer */ +static void put_pci_config_device(QEMUFile *f, void *pv, size_t size) +{ + const uint8_t **v = pv; + assert(size == pci_config_size(container_of(pv, PCIDevice, config))); + qemu_put_buffer(f, *v, size); +} + +static VMStateInfo vmstate_info_pci_config = { + .name = "pci config", + .get = get_pci_config_device, + .put = put_pci_config_device, +}; + +static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) +{ + PCIDevice *s = container_of(pv, PCIDevice, irq_state); + uint32_t irq_state[PCI_NUM_PINS]; + int i; + for (i = 0; i < PCI_NUM_PINS; ++i) { + irq_state[i] = qemu_get_be32(f); + if (irq_state[i] != 0x1 && irq_state[i] != 0) { + fprintf(stderr, "irq state %d: must be 0 or 1.\n", + irq_state[i]); + return -EINVAL; + } + } + + for (i = 0; i < PCI_NUM_PINS; ++i) { + pci_set_irq_state(s, i, irq_state[i]); + } + + return 0; +} + +static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size) +{ + int i; + PCIDevice *s = container_of(pv, PCIDevice, irq_state); + + for (i = 0; i < PCI_NUM_PINS; ++i) { + qemu_put_be32(f, pci_irq_state(s, i)); + } +} + +static VMStateInfo vmstate_info_pci_irq_state = { + .name = "pci irq state", + .get = get_pci_irq_state, + .put = put_pci_irq_state, +}; + +const VMStateDescription vmstate_pci_device = { + .name = "PCIDevice", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32_LE(version_id, PCIDevice), + VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, + vmstate_info_pci_config, + PCI_CONFIG_SPACE_SIZE), + VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, + vmstate_info_pci_irq_state, + PCI_NUM_PINS * sizeof(int32_t)), + VMSTATE_END_OF_LIST() + } +}; + +const VMStateDescription vmstate_pcie_device = { + .name = "PCIEDevice", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32_LE(version_id, PCIDevice), + VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, + vmstate_info_pci_config, + PCIE_CONFIG_SPACE_SIZE), + VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, + vmstate_info_pci_irq_state, + PCI_NUM_PINS * sizeof(int32_t)), + VMSTATE_END_OF_LIST() + } +}; + +static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s) +{ + return pci_is_express(s) ? &vmstate_pcie_device : &vmstate_pci_device; +} + +void pci_device_save(PCIDevice *s, QEMUFile *f) +{ + /* Clear interrupt status bit: it is implicit + * in irq_state which we are saving. + * This makes us compatible with old devices + * which never set or clear this bit. */ + s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; + vmstate_save_state(f, pci_get_vmstate(s), s); + /* Restore the interrupt status bit. */ + pci_update_irq_status(s); +} + +int pci_device_load(PCIDevice *s, QEMUFile *f) +{ + int ret; + ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id); + /* Restore the interrupt status bit. */ + pci_update_irq_status(s); + return ret; +} + +static void pci_set_default_subsystem_id(PCIDevice *pci_dev) +{ + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, + pci_default_sub_vendor_id); + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, + pci_default_sub_device_id); +} + +/* + * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL + * [[<domain>:]<bus>:]<slot>.<func>, return -1 on error + */ +static int pci_parse_devaddr(const char *addr, int *domp, int *busp, + unsigned int *slotp, unsigned int *funcp) +{ + const char *p; + char *e; + unsigned long val; + unsigned long dom = 0, bus = 0; + unsigned int slot = 0; + unsigned int func = 0; + + p = addr; + val = strtoul(p, &e, 16); + if (e == p) + return -1; + if (*e == ':') { + bus = val; + p = e + 1; + val = strtoul(p, &e, 16); + if (e == p) + return -1; + if (*e == ':') { + dom = bus; + bus = val; + p = e + 1; + val = strtoul(p, &e, 16); + if (e == p) + return -1; + } + } + + slot = val; + + if (funcp != NULL) { + if (*e != '.') + return -1; + + p = e + 1; + val = strtoul(p, &e, 16); + if (e == p) + return -1; + + func = val; + } + + /* if funcp == NULL func is 0 */ + if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) + return -1; + + if (*e) + return -1; + + *domp = dom; + *busp = bus; + *slotp = slot; + if (funcp != NULL) + *funcp = func; + return 0; +} + +int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, + unsigned *slotp) +{ + /* strip legacy tag */ + if (!strncmp(addr, "pci_addr=", 9)) { + addr += 9; + } + if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) { + monitor_printf(mon, "Invalid pci address\n"); + return -1; + } + return 0; +} + +PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) +{ + int dom, bus; + unsigned slot; + + if (!devaddr) { + *devfnp = -1; + return pci_find_bus_nr(pci_find_root_bus(0), 0); + } + + if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) { + return NULL; + } + + *devfnp = PCI_DEVFN(slot, 0); + return pci_find_bus_nr(pci_find_root_bus(dom), bus); +} + +static void pci_init_cmask(PCIDevice *dev) +{ + pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff); + pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff); + dev->cmask[PCI_STATUS] = PCI_STATUS_CAP_LIST; + dev->cmask[PCI_REVISION_ID] = 0xff; + dev->cmask[PCI_CLASS_PROG] = 0xff; + pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff); + dev->cmask[PCI_HEADER_TYPE] = 0xff; + dev->cmask[PCI_CAPABILITY_LIST] = 0xff; +} + +static void pci_init_wmask(PCIDevice *dev) +{ + int config_size = pci_config_size(dev); + + dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff; + dev->wmask[PCI_INTERRUPT_LINE] = 0xff; + pci_set_word(dev->wmask + PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_INTX_DISABLE); + if (dev->cap_present & QEMU_PCI_CAP_SERR) { + pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR); + } + + memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff, + config_size - PCI_CONFIG_HEADER_SIZE); +} + +static void pci_init_w1cmask(PCIDevice *dev) +{ + /* + * Note: It's okay to set w1cmask even for readonly bits as + * long as their value is hardwired to 0. + */ + pci_set_word(dev->w1cmask + PCI_STATUS, + PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | + PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY); +} + +static void pci_init_mask_bridge(PCIDevice *d) +{ + /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and + PCI_SEC_LETENCY_TIMER */ + memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4); + + /* base and limit */ + d->wmask[PCI_IO_BASE] = PCI_IO_RANGE_MASK & 0xff; + d->wmask[PCI_IO_LIMIT] = PCI_IO_RANGE_MASK & 0xff; + pci_set_word(d->wmask + PCI_MEMORY_BASE, + PCI_MEMORY_RANGE_MASK & 0xffff); + pci_set_word(d->wmask + PCI_MEMORY_LIMIT, + PCI_MEMORY_RANGE_MASK & 0xffff); + pci_set_word(d->wmask + PCI_PREF_MEMORY_BASE, + PCI_PREF_RANGE_MASK & 0xffff); + pci_set_word(d->wmask + PCI_PREF_MEMORY_LIMIT, + PCI_PREF_RANGE_MASK & 0xffff); + + /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */ + memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8); + + /* Supported memory and i/o types */ + d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_16; + d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_16; + pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE, + PCI_PREF_RANGE_TYPE_64); + pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT, + PCI_PREF_RANGE_TYPE_64); + +/* TODO: add this define to pci_regs.h in linux and then in qemu. */ +#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ +#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */ +#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */ +#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ +#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ + pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, + PCI_BRIDGE_CTL_PARITY | + PCI_BRIDGE_CTL_SERR | + PCI_BRIDGE_CTL_ISA | + PCI_BRIDGE_CTL_VGA | + PCI_BRIDGE_CTL_VGA_16BIT | + PCI_BRIDGE_CTL_MASTER_ABORT | + PCI_BRIDGE_CTL_BUS_RESET | + PCI_BRIDGE_CTL_FAST_BACK | + PCI_BRIDGE_CTL_DISCARD | + PCI_BRIDGE_CTL_SEC_DISCARD | + PCI_BRIDGE_CTL_DISCARD_SERR); + /* Below does not do anything as we never set this bit, put here for + * completeness. */ + pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL, + PCI_BRIDGE_CTL_DISCARD_STATUS); + d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK; + d->cmask[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_MASK; + pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE, + PCI_PREF_RANGE_TYPE_MASK); + pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_LIMIT, + PCI_PREF_RANGE_TYPE_MASK); +} + +static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev) +{ + uint8_t slot = PCI_SLOT(dev->devfn); + uint8_t func; + + if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { + dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; + } + + /* + * multifunction bit is interpreted in two ways as follows. + * - all functions must set the bit to 1. + * Example: Intel X53 + * - function 0 must set the bit, but the rest function (> 0) + * is allowed to leave the bit to 0. + * Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10, + * + * So OS (at least Linux) checks the bit of only function 0, + * and doesn't see the bit of function > 0. + * + * The below check allows both interpretation. + */ + if (PCI_FUNC(dev->devfn)) { + PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)]; + if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) { + /* function 0 should set multifunction bit */ + error_report("PCI: single function device can't be populated " + "in function %x.%x", slot, PCI_FUNC(dev->devfn)); + return -1; + } + return 0; + } + + if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { + return 0; + } + /* function 0 indicates single function, so function > 0 must be NULL */ + for (func = 1; func < PCI_FUNC_MAX; ++func) { + if (bus->devices[PCI_DEVFN(slot, func)]) { + error_report("PCI: %x.0 indicates single function, " + "but %x.%x is already populated.", + slot, slot, func); + return -1; + } + } + return 0; +} + +static void pci_config_alloc(PCIDevice *pci_dev) +{ + int config_size = pci_config_size(pci_dev); + + pci_dev->config = g_malloc0(config_size); + pci_dev->cmask = g_malloc0(config_size); + pci_dev->wmask = g_malloc0(config_size); + pci_dev->w1cmask = g_malloc0(config_size); + pci_dev->used = g_malloc0(config_size); +} + +static void pci_config_free(PCIDevice *pci_dev) +{ + g_free(pci_dev->config); + g_free(pci_dev->cmask); + g_free(pci_dev->wmask); + g_free(pci_dev->w1cmask); + g_free(pci_dev->used); +} + +/* -1 for devfn means auto assign */ +static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, + const char *name, int devfn) +{ + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); + PCIConfigReadFunc *config_read = pc->config_read; + PCIConfigWriteFunc *config_write = pc->config_write; + + if (devfn < 0) { + for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices); + devfn += PCI_FUNC_MAX) { + if (!bus->devices[devfn]) + goto found; + } + error_report("PCI: no slot/function available for %s, all in use", name); + return NULL; + found: ; + } else if (bus->devices[devfn]) { + error_report("PCI: slot %d function %d not available for %s, in use by %s", + PCI_SLOT(devfn), PCI_FUNC(devfn), name, bus->devices[devfn]->name); + return NULL; + } + pci_dev->bus = bus; + if (bus->dma_context_fn) { + pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, devfn); + } else { + /* FIXME: Make dma_context_fn use MemoryRegions instead, so this path is + * taken unconditionally */ + /* FIXME: inherit memory region from bus creator */ + memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master", + get_system_memory(), 0, + memory_region_size(get_system_memory())); + memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); + address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region); + pci_dev->dma = g_new(DMAContext, 1); + dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL); + } + pci_dev->devfn = devfn; + pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); + pci_dev->irq_state = 0; + pci_config_alloc(pci_dev); + + pci_config_set_vendor_id(pci_dev->config, pc->vendor_id); + pci_config_set_device_id(pci_dev->config, pc->device_id); + pci_config_set_revision(pci_dev->config, pc->revision); + pci_config_set_class(pci_dev->config, pc->class_id); + + if (!pc->is_bridge) { + if (pc->subsystem_vendor_id || pc->subsystem_id) { + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, + pc->subsystem_vendor_id); + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, + pc->subsystem_id); + } else { + pci_set_default_subsystem_id(pci_dev); + } + } else { + /* subsystem_vendor_id/subsystem_id are only for header type 0 */ + assert(!pc->subsystem_vendor_id); + assert(!pc->subsystem_id); + } + pci_init_cmask(pci_dev); + pci_init_wmask(pci_dev); + pci_init_w1cmask(pci_dev); + if (pc->is_bridge) { + pci_init_mask_bridge(pci_dev); + } + if (pci_init_multifunction(bus, pci_dev)) { + pci_config_free(pci_dev); + return NULL; + } + + if (!config_read) + config_read = pci_default_read_config; + if (!config_write) + config_write = pci_default_write_config; + pci_dev->config_read = config_read; + pci_dev->config_write = config_write; + bus->devices[devfn] = pci_dev; + pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS); + pci_dev->version_id = 2; /* Current pci device vmstate version */ + return pci_dev; +} + +static void do_pci_unregister_device(PCIDevice *pci_dev) +{ + qemu_free_irqs(pci_dev->irq); + pci_dev->bus->devices[pci_dev->devfn] = NULL; + pci_config_free(pci_dev); + + if (!pci_dev->bus->dma_context_fn) { + address_space_destroy(&pci_dev->bus_master_as); + memory_region_destroy(&pci_dev->bus_master_enable_region); + g_free(pci_dev->dma); + pci_dev->dma = NULL; + } +} + +static void pci_unregister_io_regions(PCIDevice *pci_dev) +{ + PCIIORegion *r; + int i; + + for(i = 0; i < PCI_NUM_REGIONS; i++) { + r = &pci_dev->io_regions[i]; + if (!r->size || r->addr == PCI_BAR_UNMAPPED) + continue; + memory_region_del_subregion(r->address_space, r->memory); + } +} + +static int pci_unregister_device(DeviceState *dev) +{ + PCIDevice *pci_dev = PCI_DEVICE(dev); + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); + + pci_unregister_io_regions(pci_dev); + pci_del_option_rom(pci_dev); + + if (pc->exit) { + pc->exit(pci_dev); + } + + do_pci_unregister_device(pci_dev); + return 0; +} + +void pci_register_bar(PCIDevice *pci_dev, int region_num, + uint8_t type, MemoryRegion *memory) +{ + PCIIORegion *r; + uint32_t addr; + uint64_t wmask; + pcibus_t size = memory_region_size(memory); + + assert(region_num >= 0); + assert(region_num < PCI_NUM_REGIONS); + if (size & (size-1)) { + fprintf(stderr, "ERROR: PCI region size must be pow2 " + "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size); + exit(1); + } + + r = &pci_dev->io_regions[region_num]; + r->addr = PCI_BAR_UNMAPPED; + r->size = size; + r->type = type; + r->memory = NULL; + + wmask = ~(size - 1); + addr = pci_bar(pci_dev, region_num); + if (region_num == PCI_ROM_SLOT) { + /* ROM enable bit is writable */ + wmask |= PCI_ROM_ADDRESS_ENABLE; + } + pci_set_long(pci_dev->config + addr, type); + if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) && + r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_set_quad(pci_dev->wmask + addr, wmask); + pci_set_quad(pci_dev->cmask + addr, ~0ULL); + } else { + pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff); + pci_set_long(pci_dev->cmask + addr, 0xffffffff); + } + pci_dev->io_regions[region_num].memory = memory; + pci_dev->io_regions[region_num].address_space + = type & PCI_BASE_ADDRESS_SPACE_IO + ? pci_dev->bus->address_space_io + : pci_dev->bus->address_space_mem; +} + +pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num) +{ + return pci_dev->io_regions[region_num].addr; +} + +static pcibus_t pci_bar_address(PCIDevice *d, + int reg, uint8_t type, pcibus_t size) +{ + pcibus_t new_addr, last_addr; + int bar = pci_bar(d, reg); + uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); + + if (type & PCI_BASE_ADDRESS_SPACE_IO) { + if (!(cmd & PCI_COMMAND_IO)) { + return PCI_BAR_UNMAPPED; + } + new_addr = pci_get_long(d->config + bar) & ~(size - 1); + last_addr = new_addr + size - 1; + /* NOTE: we have only 64K ioports on PC */ + if (last_addr <= new_addr || new_addr == 0 || last_addr > UINT16_MAX) { + return PCI_BAR_UNMAPPED; + } + return new_addr; + } + + if (!(cmd & PCI_COMMAND_MEMORY)) { + return PCI_BAR_UNMAPPED; + } + if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { + new_addr = pci_get_quad(d->config + bar); + } else { + new_addr = pci_get_long(d->config + bar); + } + /* the ROM slot has a specific enable bit */ + if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) { + return PCI_BAR_UNMAPPED; + } + new_addr &= ~(size - 1); + last_addr = new_addr + size - 1; + /* NOTE: we do not support wrapping */ + /* XXX: as we cannot support really dynamic + mappings, we handle specific values as invalid + mappings. */ + if (last_addr <= new_addr || new_addr == 0 || + last_addr == PCI_BAR_UNMAPPED) { + return PCI_BAR_UNMAPPED; + } + + /* Now pcibus_t is 64bit. + * Check if 32 bit BAR wraps around explicitly. + * Without this, PC ide doesn't work well. + * TODO: remove this work around. + */ + if (!(type & PCI_BASE_ADDRESS_MEM_TYPE_64) && last_addr >= UINT32_MAX) { + return PCI_BAR_UNMAPPED; + } + + /* + * OS is allowed to set BAR beyond its addressable + * bits. For example, 32 bit OS can set 64bit bar + * to >4G. Check it. TODO: we might need to support + * it in the future for e.g. PAE. + */ + if (last_addr >= HWADDR_MAX) { + return PCI_BAR_UNMAPPED; + } + + return new_addr; +} + +static void pci_update_mappings(PCIDevice *d) +{ + PCIIORegion *r; + int i; + pcibus_t new_addr; + + for(i = 0; i < PCI_NUM_REGIONS; i++) { + r = &d->io_regions[i]; + + /* this region isn't registered */ + if (!r->size) + continue; + + new_addr = pci_bar_address(d, i, r->type, r->size); + + /* This bar isn't changed */ + if (new_addr == r->addr) + continue; + + /* now do the real mapping */ + if (r->addr != PCI_BAR_UNMAPPED) { + memory_region_del_subregion(r->address_space, r->memory); + } + r->addr = new_addr; + if (r->addr != PCI_BAR_UNMAPPED) { + memory_region_add_subregion_overlap(r->address_space, + r->addr, r->memory, 1); + } + } +} + +static inline int pci_irq_disabled(PCIDevice *d) +{ + return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE; +} + +/* Called after interrupt disabled field update in config space, + * assert/deassert interrupts if necessary. + * Gets original interrupt disable bit value (before update). */ +static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled) +{ + int i, disabled = pci_irq_disabled(d); + if (disabled == was_irq_disabled) + return; + for (i = 0; i < PCI_NUM_PINS; ++i) { + int state = pci_irq_state(d, i); + pci_change_irq_level(d, i, disabled ? -state : state); + } +} + +uint32_t pci_default_read_config(PCIDevice *d, + uint32_t address, int len) +{ + uint32_t val = 0; + + memcpy(&val, d->config + address, len); + return le32_to_cpu(val); +} + +void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) +{ + int i, was_irq_disabled = pci_irq_disabled(d); + + for (i = 0; i < l; val >>= 8, ++i) { + uint8_t wmask = d->wmask[addr + i]; + uint8_t w1cmask = d->w1cmask[addr + i]; + assert(!(wmask & w1cmask)); + d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask); + d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ + } + if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) || + ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) || + ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) || + range_covers_byte(addr, l, PCI_COMMAND)) + pci_update_mappings(d); + + if (range_covers_byte(addr, l, PCI_COMMAND)) { + pci_update_irq_disabled(d, was_irq_disabled); + memory_region_set_enabled(&d->bus_master_enable_region, + pci_get_word(d->config + PCI_COMMAND) + & PCI_COMMAND_MASTER); + } + + msi_write_config(d, addr, val, l); + msix_write_config(d, addr, val, l); +} + +/***********************************************************/ +/* generic PCI irq support */ + +/* 0 <= irq_num <= 3. level must be 0 or 1 */ +static void pci_set_irq(void *opaque, int irq_num, int level) +{ + PCIDevice *pci_dev = opaque; + int change; + + change = level - pci_irq_state(pci_dev, irq_num); + if (!change) + return; + + pci_set_irq_state(pci_dev, irq_num, level); + pci_update_irq_status(pci_dev); + if (pci_irq_disabled(pci_dev)) + return; + pci_change_irq_level(pci_dev, irq_num, change); +} + +/* Special hooks used by device assignment */ +void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq) +{ + assert(!bus->parent_dev); + bus->route_intx_to_irq = route_intx_to_irq; +} + +PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) +{ + PCIBus *bus; + + do { + bus = dev->bus; + pin = bus->map_irq(dev, pin); + dev = bus->parent_dev; + } while (dev); + + if (!bus->route_intx_to_irq) { + error_report("PCI: Bug - unimplemented PCI INTx routing (%s)\n", + object_get_typename(OBJECT(bus->qbus.parent))); + return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 }; + } + + return bus->route_intx_to_irq(bus->irq_opaque, pin); +} + +bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new) +{ + return old->mode != new->mode || old->irq != new->irq; +} + +void pci_bus_fire_intx_routing_notifier(PCIBus *bus) +{ + PCIDevice *dev; + PCIBus *sec; + int i; + + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { + dev = bus->devices[i]; + if (dev && dev->intx_routing_notifier) { + dev->intx_routing_notifier(dev); + } + QLIST_FOREACH(sec, &bus->child, sibling) { + pci_bus_fire_intx_routing_notifier(sec); + } + } +} + +void pci_device_set_intx_routing_notifier(PCIDevice *dev, + PCIINTxRoutingNotifier notifier) +{ + dev->intx_routing_notifier = notifier; +} + +/* + * PCI-to-PCI bridge specification + * 9.1: Interrupt routing. Table 9-1 + * + * the PCI Express Base Specification, Revision 2.1 + * 2.2.8.1: INTx interrutp signaling - Rules + * the Implementation Note + * Table 2-20 + */ +/* + * 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD + * 0-origin unlike PCI interrupt pin register. + */ +int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) +{ + return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; +} + +/***********************************************************/ +/* monitor info on PCI */ + +typedef struct { + uint16_t class; + const char *desc; + const char *fw_name; + uint16_t fw_ign_bits; +} pci_class_desc; + +static const pci_class_desc pci_class_descriptions[] = +{ + { 0x0001, "VGA controller", "display"}, + { 0x0100, "SCSI controller", "scsi"}, + { 0x0101, "IDE controller", "ide"}, + { 0x0102, "Floppy controller", "fdc"}, + { 0x0103, "IPI controller", "ipi"}, + { 0x0104, "RAID controller", "raid"}, + { 0x0106, "SATA controller"}, + { 0x0107, "SAS controller"}, + { 0x0180, "Storage controller"}, + { 0x0200, "Ethernet controller", "ethernet"}, + { 0x0201, "Token Ring controller", "token-ring"}, + { 0x0202, "FDDI controller", "fddi"}, + { 0x0203, "ATM controller", "atm"}, + { 0x0280, "Network controller"}, + { 0x0300, "VGA controller", "display", 0x00ff}, + { 0x0301, "XGA controller"}, + { 0x0302, "3D controller"}, + { 0x0380, "Display controller"}, + { 0x0400, "Video controller", "video"}, + { 0x0401, "Audio controller", "sound"}, + { 0x0402, "Phone"}, + { 0x0403, "Audio controller", "sound"}, + { 0x0480, "Multimedia controller"}, + { 0x0500, "RAM controller", "memory"}, + { 0x0501, "Flash controller", "flash"}, + { 0x0580, "Memory controller"}, + { 0x0600, "Host bridge", "host"}, + { 0x0601, "ISA bridge", "isa"}, + { 0x0602, "EISA bridge", "eisa"}, + { 0x0603, "MC bridge", "mca"}, + { 0x0604, "PCI bridge", "pci"}, + { 0x0605, "PCMCIA bridge", "pcmcia"}, + { 0x0606, "NUBUS bridge", "nubus"}, + { 0x0607, "CARDBUS bridge", "cardbus"}, + { 0x0608, "RACEWAY bridge"}, + { 0x0680, "Bridge"}, + { 0x0700, "Serial port", "serial"}, + { 0x0701, "Parallel port", "parallel"}, + { 0x0800, "Interrupt controller", "interrupt-controller"}, + { 0x0801, "DMA controller", "dma-controller"}, + { 0x0802, "Timer", "timer"}, + { 0x0803, "RTC", "rtc"}, + { 0x0900, "Keyboard", "keyboard"}, + { 0x0901, "Pen", "pen"}, + { 0x0902, "Mouse", "mouse"}, + { 0x0A00, "Dock station", "dock", 0x00ff}, + { 0x0B00, "i386 cpu", "cpu", 0x00ff}, + { 0x0c00, "Fireware contorller", "fireware"}, + { 0x0c01, "Access bus controller", "access-bus"}, + { 0x0c02, "SSA controller", "ssa"}, + { 0x0c03, "USB controller", "usb"}, + { 0x0c04, "Fibre channel controller", "fibre-channel"}, + { 0x0c05, "SMBus"}, + { 0, NULL} +}; + +static void pci_for_each_device_under_bus(PCIBus *bus, + void (*fn)(PCIBus *b, PCIDevice *d, + void *opaque), + void *opaque) +{ + PCIDevice *d; + int devfn; + + for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + d = bus->devices[devfn]; + if (d) { + fn(bus, d, opaque); + } + } +} + +void pci_for_each_device(PCIBus *bus, int bus_num, + void (*fn)(PCIBus *b, PCIDevice *d, void *opaque), + void *opaque) +{ + bus = pci_find_bus_nr(bus, bus_num); + + if (bus) { + pci_for_each_device_under_bus(bus, fn, opaque); + } +} + +static const pci_class_desc *get_class_desc(int class) +{ + const pci_class_desc *desc; + + desc = pci_class_descriptions; + while (desc->desc && class != desc->class) { + desc++; + } + + return desc; +} + +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num); + +static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev) +{ + PciMemoryRegionList *head = NULL, *cur_item = NULL; + int i; + + for (i = 0; i < PCI_NUM_REGIONS; i++) { + const PCIIORegion *r = &dev->io_regions[i]; + PciMemoryRegionList *region; + + if (!r->size) { + continue; + } + + region = g_malloc0(sizeof(*region)); + region->value = g_malloc0(sizeof(*region->value)); + + if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { + region->value->type = g_strdup("io"); + } else { + region->value->type = g_strdup("memory"); + region->value->has_prefetch = true; + region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH); + region->value->has_mem_type_64 = true; + region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64); + } + + region->value->bar = i; + region->value->address = r->addr; + region->value->size = r->size; + + /* XXX: waiting for the qapi to support GSList */ + if (!cur_item) { + head = cur_item = region; + } else { + cur_item->next = region; + cur_item = region; + } + } + + return head; +} + +static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus, + int bus_num) +{ + PciBridgeInfo *info; + + info = g_malloc0(sizeof(*info)); + + info->bus.number = dev->config[PCI_PRIMARY_BUS]; + info->bus.secondary = dev->config[PCI_SECONDARY_BUS]; + info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS]; + + info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range)); + info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); + info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO); + + info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range)); + info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); + info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); + + info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range)); + info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); + info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); + + if (dev->config[PCI_SECONDARY_BUS] != 0) { + PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]); + if (child_bus) { + info->has_devices = true; + info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]); + } + } + + return info; +} + +static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, + int bus_num) +{ + const pci_class_desc *desc; + PciDeviceInfo *info; + uint8_t type; + int class; + + info = g_malloc0(sizeof(*info)); + info->bus = bus_num; + info->slot = PCI_SLOT(dev->devfn); + info->function = PCI_FUNC(dev->devfn); + + class = pci_get_word(dev->config + PCI_CLASS_DEVICE); + info->class_info.class = class; + desc = get_class_desc(class); + if (desc->desc) { + info->class_info.has_desc = true; + info->class_info.desc = g_strdup(desc->desc); + } + + info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID); + info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID); + info->regions = qmp_query_pci_regions(dev); + info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : ""); + + if (dev->config[PCI_INTERRUPT_PIN] != 0) { + info->has_irq = true; + info->irq = dev->config[PCI_INTERRUPT_LINE]; + } + + type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; + if (type == PCI_HEADER_TYPE_BRIDGE) { + info->has_pci_bridge = true; + info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num); + } + + return info; +} + +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num) +{ + PciDeviceInfoList *info, *head = NULL, *cur_item = NULL; + PCIDevice *dev; + int devfn; + + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + dev = bus->devices[devfn]; + if (dev) { + info = g_malloc0(sizeof(*info)); + info->value = qmp_query_pci_device(dev, bus, bus_num); + + /* XXX: waiting for the qapi to support GSList */ + if (!cur_item) { + head = cur_item = info; + } else { + cur_item->next = info; + cur_item = info; + } + } + } + + return head; +} + +static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) +{ + PciInfo *info = NULL; + + bus = pci_find_bus_nr(bus, bus_num); + if (bus) { + info = g_malloc0(sizeof(*info)); + info->bus = bus_num; + info->devices = qmp_query_pci_devices(bus, bus_num); + } + + return info; +} + +PciInfoList *qmp_query_pci(Error **errp) +{ + PciInfoList *info, *head = NULL, *cur_item = NULL; + struct PCIHostBus *host; + + QLIST_FOREACH(host, &host_buses, next) { + info = g_malloc0(sizeof(*info)); + info->value = qmp_query_pci_bus(host->bus, 0); + + /* XXX: waiting for the qapi to support GSList */ + if (!cur_item) { + head = cur_item = info; + } else { + cur_item->next = info; + cur_item = info; + } + } + + return head; +} + +static const char * const pci_nic_models[] = { + "ne2k_pci", + "i82551", + "i82557b", + "i82559er", + "rtl8139", + "e1000", + "pcnet", + "virtio", + NULL +}; + +static const char * const pci_nic_names[] = { + "ne2k_pci", + "i82551", + "i82557b", + "i82559er", + "rtl8139", + "e1000", + "pcnet", + "virtio-net-pci", + NULL +}; + +/* Initialize a PCI NIC. */ +/* FIXME callers should check for failure, but don't */ +PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, + const char *default_devaddr) +{ + const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr; + PCIBus *bus; + int devfn; + PCIDevice *pci_dev; + DeviceState *dev; + int i; + + i = qemu_find_nic_model(nd, pci_nic_models, default_model); + if (i < 0) + return NULL; + + bus = pci_get_bus_devfn(&devfn, devaddr); + if (!bus) { + error_report("Invalid PCI device address %s for device %s", + devaddr, pci_nic_names[i]); + return NULL; + } + + pci_dev = pci_create(bus, devfn, pci_nic_names[i]); + dev = &pci_dev->qdev; + qdev_set_nic_properties(dev, nd); + if (qdev_init(dev) < 0) + return NULL; + return pci_dev; +} + +PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, + const char *default_devaddr) +{ + PCIDevice *res; + + if (qemu_show_nic_models(nd->model, pci_nic_models)) + exit(0); + + res = pci_nic_init(nd, default_model, default_devaddr); + if (!res) + exit(1); + return res; +} + +PCIDevice *pci_vga_init(PCIBus *bus) +{ + switch (vga_interface_type) { + case VGA_CIRRUS: + return pci_create_simple(bus, -1, "cirrus-vga"); + case VGA_QXL: + return pci_create_simple(bus, -1, "qxl-vga"); + case VGA_STD: + return pci_create_simple(bus, -1, "VGA"); + case VGA_VMWARE: + return pci_create_simple(bus, -1, "vmware-svga"); + case VGA_NONE: + default: /* Other non-PCI types. Checking for unsupported types is already + done in vl.c. */ + return NULL; + } +} + +/* Whether a given bus number is in range of the secondary + * bus of the given bridge device. */ +static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) +{ + return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) & + PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ && + dev->config[PCI_SECONDARY_BUS] < bus_num && + bus_num <= dev->config[PCI_SUBORDINATE_BUS]; +} + +static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) +{ + PCIBus *sec; + + if (!bus) { + return NULL; + } + + if (pci_bus_num(bus) == bus_num) { + return bus; + } + + /* Consider all bus numbers in range for the host pci bridge. */ + if (bus->parent_dev && + !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) { + return NULL; + } + + /* try child bus */ + for (; bus; bus = sec) { + QLIST_FOREACH(sec, &bus->child, sibling) { + assert(sec->parent_dev); + if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) { + return sec; + } + if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) { + break; + } + } + } + + return NULL; +} + +PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn) +{ + bus = pci_find_bus_nr(bus, bus_num); + + if (!bus) + return NULL; + + return bus->devices[devfn]; +} + +static int pci_qdev_init(DeviceState *qdev) +{ + PCIDevice *pci_dev = (PCIDevice *)qdev; + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); + PCIBus *bus; + int rc; + bool is_default_rom; + + /* initialize cap_present for pci_is_express() and pci_config_size() */ + if (pc->is_express) { + pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; + } + + bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); + pci_dev = do_pci_register_device(pci_dev, bus, + object_get_typename(OBJECT(qdev)), + pci_dev->devfn); + if (pci_dev == NULL) + return -1; + if (qdev->hotplugged && pc->no_hotplug) { + qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev))); + do_pci_unregister_device(pci_dev); + return -1; + } + if (pc->init) { + rc = pc->init(pci_dev); + if (rc != 0) { + do_pci_unregister_device(pci_dev); + return rc; + } + } + + /* rom loading */ + is_default_rom = false; + if (pci_dev->romfile == NULL && pc->romfile != NULL) { + pci_dev->romfile = g_strdup(pc->romfile); + is_default_rom = true; + } + pci_add_option_rom(pci_dev, is_default_rom); + + if (bus->hotplug) { + /* Let buses differentiate between hotplug and when device is + * enabled during qemu machine creation. */ + rc = bus->hotplug(bus->hotplug_qdev, pci_dev, + qdev->hotplugged ? PCI_HOTPLUG_ENABLED: + PCI_COLDPLUG_ENABLED); + if (rc != 0) { + int r = pci_unregister_device(&pci_dev->qdev); + assert(!r); + return rc; + } + } + return 0; +} + +static int pci_unplug_device(DeviceState *qdev) +{ + PCIDevice *dev = PCI_DEVICE(qdev); + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); + + if (pc->no_hotplug) { + qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev))); + return -1; + } + return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, + PCI_HOTPLUG_DISABLED); +} + +PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, + const char *name) +{ + DeviceState *dev; + + dev = qdev_create(&bus->qbus, name); + qdev_prop_set_int32(dev, "addr", devfn); + qdev_prop_set_bit(dev, "multifunction", multifunction); + return PCI_DEVICE(dev); +} + +PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, + bool multifunction, + const char *name) +{ + PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction, name); + qdev_init_nofail(&dev->qdev); + return dev; +} + +PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name) +{ + return pci_create_multifunction(bus, devfn, false, name); +} + +PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) +{ + return pci_create_simple_multifunction(bus, devfn, false, name); +} + +static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size) +{ + int offset = PCI_CONFIG_HEADER_SIZE; + int i; + for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) { + if (pdev->used[i]) + offset = i + 1; + else if (i - offset + 1 == size) + return offset; + } + return 0; +} + +static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id, + uint8_t *prev_p) +{ + uint8_t next, prev; + + if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST)) + return 0; + + for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); + prev = next + PCI_CAP_LIST_NEXT) + if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id) + break; + + if (prev_p) + *prev_p = prev; + return next; +} + +static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset) +{ + uint8_t next, prev, found = 0; + + if (!(pdev->used[offset])) { + return 0; + } + + assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST); + + for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); + prev = next + PCI_CAP_LIST_NEXT) { + if (next <= offset && next > found) { + found = next; + } + } + return found; +} + +/* Patch the PCI vendor and device ids in a PCI rom image if necessary. + This is needed for an option rom which is used for more than one device. */ +static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size) +{ + uint16_t vendor_id; + uint16_t device_id; + uint16_t rom_vendor_id; + uint16_t rom_device_id; + uint16_t rom_magic; + uint16_t pcir_offset; + uint8_t checksum; + + /* Words in rom data are little endian (like in PCI configuration), + so they can be read / written with pci_get_word / pci_set_word. */ + + /* Only a valid rom will be patched. */ + rom_magic = pci_get_word(ptr); + if (rom_magic != 0xaa55) { + PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic); + return; + } + pcir_offset = pci_get_word(ptr + 0x18); + if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) { + PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset); + return; + } + + vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); + device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); + rom_vendor_id = pci_get_word(ptr + pcir_offset + 4); + rom_device_id = pci_get_word(ptr + pcir_offset + 6); + + PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile, + vendor_id, device_id, rom_vendor_id, rom_device_id); + + checksum = ptr[6]; + + if (vendor_id != rom_vendor_id) { + /* Patch vendor id and checksum (at offset 6 for etherboot roms). */ + checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8); + checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8); + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); + ptr[6] = checksum; + pci_set_word(ptr + pcir_offset + 4, vendor_id); + } + + if (device_id != rom_device_id) { + /* Patch device id and checksum (at offset 6 for etherboot roms). */ + checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8); + checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8); + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); + ptr[6] = checksum; + pci_set_word(ptr + pcir_offset + 6, device_id); + } +} + +/* Add an option rom for the device */ +static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) +{ + int size; + char *path; + void *ptr; + char name[32]; + const VMStateDescription *vmsd; + + if (!pdev->romfile) + return 0; + if (strlen(pdev->romfile) == 0) + return 0; + + if (!pdev->rom_bar) { + /* + * Load rom via fw_cfg instead of creating a rom bar, + * for 0.11 compatibility. + */ + int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE); + if (class == 0x0300) { + rom_add_vga(pdev->romfile); + } else { + rom_add_option(pdev->romfile, -1); + } + return 0; + } + + path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); + if (path == NULL) { + path = g_strdup(pdev->romfile); + } + + size = get_image_size(path); + if (size < 0) { + error_report("%s: failed to find romfile \"%s\"", + __FUNCTION__, pdev->romfile); + g_free(path); + return -1; + } + if (size & (size - 1)) { + size = 1 << qemu_fls(size); + } + + vmsd = qdev_get_vmsd(DEVICE(pdev)); + + if (vmsd) { + snprintf(name, sizeof(name), "%s.rom", vmsd->name); + } else { + snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev))); + } + pdev->has_rom = true; + memory_region_init_ram(&pdev->rom, name, size); + vmstate_register_ram(&pdev->rom, &pdev->qdev); + ptr = memory_region_get_ram_ptr(&pdev->rom); + load_image(path, ptr); + g_free(path); + + if (is_default_rom) { + /* Only the default rom images will be patched (if needed). */ + pci_patch_ids(pdev, ptr, size); + } + + qemu_put_ram_ptr(ptr); + + pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom); + + return 0; +} + +static void pci_del_option_rom(PCIDevice *pdev) +{ + if (!pdev->has_rom) + return; + + vmstate_unregister_ram(&pdev->rom, &pdev->qdev); + memory_region_destroy(&pdev->rom); + pdev->has_rom = false; +} + +/* + * if !offset + * Reserve space and add capability to the linked list in pci config space + * + * if offset = 0, + * Find and reserve space and add capability to the linked list + * in pci config space */ +int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, + uint8_t offset, uint8_t size) +{ + uint8_t *config; + int i, overlapping_cap; + + if (!offset) { + offset = pci_find_space(pdev, size); + if (!offset) { + return -ENOSPC; + } + } else { + /* Verify that capabilities don't overlap. Note: device assignment + * depends on this check to verify that the device is not broken. + * Should never trigger for emulated devices, but it's helpful + * for debugging these. */ + for (i = offset; i < offset + size; i++) { + overlapping_cap = pci_find_capability_at_offset(pdev, i); + if (overlapping_cap) { + fprintf(stderr, "ERROR: %04x:%02x:%02x.%x " + "Attempt to add PCI capability %x at offset " + "%x overlaps existing capability %x at offset %x\n", + pci_find_domain(pdev->bus), pci_bus_num(pdev->bus), + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + cap_id, offset, overlapping_cap, i); + return -EINVAL; + } + } + } + + config = pdev->config + offset; + config[PCI_CAP_LIST_ID] = cap_id; + config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST]; + pdev->config[PCI_CAPABILITY_LIST] = offset; + pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST; + memset(pdev->used + offset, 0xFF, QEMU_ALIGN_UP(size, 4)); + /* Make capability read-only by default */ + memset(pdev->wmask + offset, 0, size); + /* Check capability by default */ + memset(pdev->cmask + offset, 0xFF, size); + return offset; +} + +/* Unlink capability from the pci config space. */ +void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) +{ + uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev); + if (!offset) + return; + pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT]; + /* Make capability writable again */ + memset(pdev->wmask + offset, 0xff, size); + memset(pdev->w1cmask + offset, 0, size); + /* Clear cmask as device-specific registers can't be checked */ + memset(pdev->cmask + offset, 0, size); + memset(pdev->used + offset, 0, QEMU_ALIGN_UP(size, 4)); + + if (!pdev->config[PCI_CAPABILITY_LIST]) + pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST; +} + +uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id) +{ + return pci_find_capability_list(pdev, cap_id, NULL); +} + +static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) +{ + PCIDevice *d = (PCIDevice *)dev; + const pci_class_desc *desc; + char ctxt[64]; + PCIIORegion *r; + int i, class; + + class = pci_get_word(d->config + PCI_CLASS_DEVICE); + desc = pci_class_descriptions; + while (desc->desc && class != desc->class) + desc++; + if (desc->desc) { + snprintf(ctxt, sizeof(ctxt), "%s", desc->desc); + } else { + snprintf(ctxt, sizeof(ctxt), "Class %04x", class); + } + + monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " + "pci id %04x:%04x (sub %04x:%04x)\n", + indent, "", ctxt, pci_bus_num(d->bus), + PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), + pci_get_word(d->config + PCI_VENDOR_ID), + pci_get_word(d->config + PCI_DEVICE_ID), + pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID), + pci_get_word(d->config + PCI_SUBSYSTEM_ID)); + for (i = 0; i < PCI_NUM_REGIONS; i++) { + r = &d->io_regions[i]; + if (!r->size) + continue; + monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS + " [0x%"FMT_PCIBUS"]\n", + indent, "", + i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem", + r->addr, r->addr + r->size - 1); + } +} + +static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len) +{ + PCIDevice *d = (PCIDevice *)dev; + const char *name = NULL; + const pci_class_desc *desc = pci_class_descriptions; + int class = pci_get_word(d->config + PCI_CLASS_DEVICE); + + while (desc->desc && + (class & ~desc->fw_ign_bits) != + (desc->class & ~desc->fw_ign_bits)) { + desc++; + } + + if (desc->desc) { + name = desc->fw_name; + } + + if (name) { + pstrcpy(buf, len, name); + } else { + snprintf(buf, len, "pci%04x,%04x", + pci_get_word(d->config + PCI_VENDOR_ID), + pci_get_word(d->config + PCI_DEVICE_ID)); + } + + return buf; +} + +static char *pcibus_get_fw_dev_path(DeviceState *dev) +{ + PCIDevice *d = (PCIDevice *)dev; + char path[50], name[33]; + int off; + + off = snprintf(path, sizeof(path), "%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 = container_of(dev, PCIDevice, qdev); + PCIDevice *t; + int slot_depth; + /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function. + * 00 is added here to make this format compatible with + * domain:Bus:Slot.Func for systems without nested PCI bridges. + * Slot.Function list specifies the slot and function numbers for all + * devices on the path from root to the specific device. */ + char domain[] = "DDDD:00"; + char slot[] = ":SS.F"; + int domain_len = sizeof domain - 1 /* For '\0' */; + int slot_len = sizeof slot - 1 /* For '\0' */; + int path_len; + char *path, *p; + int s; + + /* Calculate # of slots on path between device and root. */; + slot_depth = 0; + for (t = d; t; t = t->bus->parent_dev) { + ++slot_depth; + } + + path_len = domain_len + slot_len * slot_depth; + + /* Allocate memory, fill in the terminating null byte. */ + path = g_malloc(path_len + 1 /* For '\0' */); + path[path_len] = '\0'; + + /* First field is the domain. */ + s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus)); + assert(s == domain_len); + memcpy(path, domain, domain_len); + + /* Fill in slot numbers. We walk up from device to root, so need to print + * them in the reverse order, last to first. */ + p = path + path_len; + for (t = d; t; t = t->bus->parent_dev) { + p -= slot_len; + s = snprintf(slot, sizeof slot, ":%02x.%x", + PCI_SLOT(t->devfn), PCI_FUNC(t->devfn)); + assert(s == slot_len); + memcpy(p, slot, slot_len); + } + + return path; +} + +static int pci_qdev_find_recursive(PCIBus *bus, + const char *id, PCIDevice **pdev) +{ + DeviceState *qdev = qdev_find_recursive(&bus->qbus, id); + if (!qdev) { + return -ENODEV; + } + + /* roughly check if given qdev is pci device */ + if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) { + *pdev = PCI_DEVICE(qdev); + return 0; + } + return -EINVAL; +} + +int pci_qdev_find_device(const char *id, PCIDevice **pdev) +{ + struct PCIHostBus *host; + int rc = -ENODEV; + + QLIST_FOREACH(host, &host_buses, next) { + int tmp = pci_qdev_find_recursive(host->bus, id, pdev); + if (!tmp) { + rc = 0; + break; + } + if (tmp != -ENODEV) { + rc = tmp; + } + } + + return rc; +} + +MemoryRegion *pci_address_space(PCIDevice *dev) +{ + return dev->bus->address_space_mem; +} + +MemoryRegion *pci_address_space_io(PCIDevice *dev) +{ + return dev->bus->address_space_io; +} + +static void pci_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->init = pci_qdev_init; + k->unplug = pci_unplug_device; + k->exit = pci_unregister_device; + k->bus_type = TYPE_PCI_BUS; + k->props = pci_props; +} + +void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque) +{ + bus->dma_context_fn = fn; + bus->dma_context_opaque = opaque; +} + +static TypeInfo pci_device_type_info = { + .name = TYPE_PCI_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(PCIDevice), + .abstract = true, + .class_size = sizeof(PCIDeviceClass), + .class_init = pci_device_class_init, +}; + +static void pci_register_types(void) +{ + type_register_static(&pci_bus_info); + type_register_static(&pci_device_type_info); +} + +type_init(pci_register_types) diff --git a/hw/pci/pci.h b/hw/pci/pci.h new file mode 100644 index 0000000..4da0c2a --- /dev/null +++ b/hw/pci/pci.h @@ -0,0 +1,684 @@ +#ifndef QEMU_PCI_H +#define QEMU_PCI_H + +#include "qemu-common.h" + +#include "qdev.h" +#include "memory.h" +#include "dma.h" + +/* PCI includes legacy ISA access. */ +#include "isa.h" + +#include "pcie.h" + +/* PCI bus */ + +#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) +#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) +#define PCI_FUNC(devfn) ((devfn) & 0x07) +#define PCI_SLOT_MAX 32 +#define PCI_FUNC_MAX 8 + +/* Class, Vendor and Device IDs from Linux's pci_ids.h */ +#include "pci_ids.h" + +/* QEMU-specific Vendor and Device ID definitions */ + +/* IBM (0x1014) */ +#define PCI_DEVICE_ID_IBM_440GX 0x027f +#define PCI_DEVICE_ID_IBM_OPENPIC2 0xffff + +/* Hitachi (0x1054) */ +#define PCI_VENDOR_ID_HITACHI 0x1054 +#define PCI_DEVICE_ID_HITACHI_SH7751R 0x350e + +/* Apple (0x106b) */ +#define PCI_DEVICE_ID_APPLE_343S1201 0x0010 +#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI 0x001e +#define PCI_DEVICE_ID_APPLE_UNI_N_PCI 0x001f +#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL 0x0022 +#define PCI_DEVICE_ID_APPLE_IPID_USB 0x003f + +/* Realtek (0x10ec) */ +#define PCI_DEVICE_ID_REALTEK_8029 0x8029 + +/* Xilinx (0x10ee) */ +#define PCI_DEVICE_ID_XILINX_XC2VP30 0x0300 + +/* Marvell (0x11ab) */ +#define PCI_DEVICE_ID_MARVELL_GT6412X 0x4620 + +/* QEMU/Bochs VGA (0x1234) */ +#define PCI_VENDOR_ID_QEMU 0x1234 +#define PCI_DEVICE_ID_QEMU_VGA 0x1111 + +/* VMWare (0x15ad) */ +#define PCI_VENDOR_ID_VMWARE 0x15ad +#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 +#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 +#define PCI_DEVICE_ID_VMWARE_NET 0x0720 +#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 +#define PCI_DEVICE_ID_VMWARE_IDE 0x1729 + +/* Intel (0x8086) */ +#define PCI_DEVICE_ID_INTEL_82551IT 0x1209 +#define PCI_DEVICE_ID_INTEL_82557 0x1229 +#define PCI_DEVICE_ID_INTEL_82801IR 0x2922 + +/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */ +#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 +#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4 +#define PCI_SUBDEVICE_ID_QEMU 0x1100 + +#define PCI_DEVICE_ID_VIRTIO_NET 0x1000 +#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 +#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 +#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 +#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 +#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 + +#define FMT_PCIBUS PRIx64 + +typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, + uint32_t address, uint32_t data, int len); +typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, + uint32_t address, int len); +typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, + pcibus_t addr, pcibus_t size, int type); +typedef void PCIUnregisterFunc(PCIDevice *pci_dev); + +typedef struct PCIIORegion { + pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ +#define PCI_BAR_UNMAPPED (~(pcibus_t)0) + pcibus_t size; + uint8_t type; + MemoryRegion *memory; + MemoryRegion *address_space; +} PCIIORegion; + +#define PCI_ROM_SLOT 6 +#define PCI_NUM_REGIONS 7 + +#include "pci_regs.h" + +/* PCI HEADER_TYPE */ +#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 + +/* Size of the standard PCI config header */ +#define PCI_CONFIG_HEADER_SIZE 0x40 +/* Size of the standard PCI config space */ +#define PCI_CONFIG_SPACE_SIZE 0x100 +/* Size of the standart PCIe config space: 4KB */ +#define PCIE_CONFIG_SPACE_SIZE 0x1000 + +#define PCI_NUM_PINS 4 /* A-D */ + +/* Bits in cap_present field. */ +enum { + QEMU_PCI_CAP_MSI = 0x1, + QEMU_PCI_CAP_MSIX = 0x2, + QEMU_PCI_CAP_EXPRESS = 0x4, + + /* multifunction capable device */ +#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3 + QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR), + + /* command register SERR bit enabled */ +#define QEMU_PCI_CAP_SERR_BITNR 4 + QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR), + /* Standard hot plug controller. */ +#define QEMU_PCI_SHPC_BITNR 5 + QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR), +#define QEMU_PCI_SLOTID_BITNR 6 + QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_BITNR), +}; + +#define TYPE_PCI_DEVICE "pci-device" +#define PCI_DEVICE(obj) \ + OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE) +#define PCI_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE) +#define PCI_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE) + +typedef struct PCIINTxRoute { + enum { + PCI_INTX_ENABLED, + PCI_INTX_INVERTED, + PCI_INTX_DISABLED, + } mode; + int irq; +} PCIINTxRoute; + +typedef struct PCIDeviceClass { + DeviceClass parent_class; + + int (*init)(PCIDevice *dev); + PCIUnregisterFunc *exit; + PCIConfigReadFunc *config_read; + PCIConfigWriteFunc *config_write; + + uint16_t vendor_id; + uint16_t device_id; + uint8_t revision; + uint16_t class_id; + uint16_t subsystem_vendor_id; /* only for header type = 0 */ + uint16_t subsystem_id; /* only for header type = 0 */ + + /* + * pci-to-pci bridge or normal device. + * This doesn't mean pci host switch. + * When card bus bridge is supported, this would be enhanced. + */ + int is_bridge; + + /* pcie stuff */ + int is_express; /* is this device pci express? */ + + /* device isn't hot-pluggable */ + int no_hotplug; + + /* rom bar */ + const char *romfile; +} PCIDeviceClass; + +typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev); +typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector, + MSIMessage msg); +typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector); + +struct PCIDevice { + DeviceState qdev; + + /* PCI config space */ + uint8_t *config; + + /* Used to enable config checks on load. Note that writable bits are + * never checked even if set in cmask. */ + uint8_t *cmask; + + /* Used to implement R/W bytes */ + uint8_t *wmask; + + /* Used to implement RW1C(Write 1 to Clear) bytes */ + uint8_t *w1cmask; + + /* Used to allocate config space for capabilities. */ + uint8_t *used; + + /* the following fields are read only */ + PCIBus *bus; + int32_t devfn; + char name[64]; + PCIIORegion io_regions[PCI_NUM_REGIONS]; + AddressSpace bus_master_as; + MemoryRegion bus_master_enable_region; + DMAContext *dma; + + /* do not access the following fields */ + PCIConfigReadFunc *config_read; + PCIConfigWriteFunc *config_write; + + /* IRQ objects for the INTA-INTD pins. */ + qemu_irq *irq; + + /* Current IRQ levels. Used internally by the generic PCI code. */ + uint8_t irq_state; + + /* Capability bits */ + uint32_t cap_present; + + /* Offset of MSI-X capability in config space */ + uint8_t msix_cap; + + /* MSI-X entries */ + int msix_entries_nr; + + /* Space to store MSIX table & pending bit array */ + uint8_t *msix_table; + uint8_t *msix_pba; + /* MemoryRegion container for msix exclusive BAR setup */ + MemoryRegion msix_exclusive_bar; + /* Memory Regions for MSIX table and pending bit entries. */ + MemoryRegion msix_table_mmio; + MemoryRegion msix_pba_mmio; + /* Reference-count for entries actually in use by driver. */ + unsigned *msix_entry_used; + /* MSIX function mask set or MSIX disabled */ + bool msix_function_masked; + /* Version id needed for VMState */ + int32_t version_id; + + /* Offset of MSI capability in config space */ + uint8_t msi_cap; + + /* PCI Express */ + PCIExpressDevice exp; + + /* SHPC */ + SHPCDevice *shpc; + + /* Location of option rom */ + char *romfile; + bool has_rom; + MemoryRegion rom; + uint32_t rom_bar; + + /* INTx routing notifier */ + PCIINTxRoutingNotifier intx_routing_notifier; + + /* MSI-X notifiers */ + MSIVectorUseNotifier msix_vector_use_notifier; + MSIVectorReleaseNotifier msix_vector_release_notifier; +}; + +void pci_register_bar(PCIDevice *pci_dev, int region_num, + uint8_t attr, MemoryRegion *memory); +pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num); + +int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, + uint8_t offset, uint8_t size); + +void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); + +uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id); + + +uint32_t pci_default_read_config(PCIDevice *d, + uint32_t address, int len); +void pci_default_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len); +void pci_device_save(PCIDevice *s, QEMUFile *f); +int pci_device_load(PCIDevice *s, QEMUFile *f); +MemoryRegion *pci_address_space(PCIDevice *dev); +MemoryRegion *pci_address_space_io(PCIDevice *dev); + +typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); +typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); +typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin); + +typedef enum { + PCI_HOTPLUG_DISABLED, + PCI_HOTPLUG_ENABLED, + PCI_COLDPLUG_ENABLED, +} PCIHotplugState; + +typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, + PCIHotplugState state); +void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, + const char *name, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io, + uint8_t devfn_min); +PCIBus *pci_bus_new(DeviceState *parent, const char *name, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io, + uint8_t devfn_min); +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, + void *irq_opaque, int nirq); +int pci_bus_get_irq_level(PCIBus *bus, int irq_num); +void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev); +/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */ +int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin); +PCIBus *pci_register_bus(DeviceState *parent, const char *name, + pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, + void *irq_opaque, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io, + uint8_t devfn_min, int nirq); +void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn); +PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin); +bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new); +void pci_bus_fire_intx_routing_notifier(PCIBus *bus); +void pci_device_set_intx_routing_notifier(PCIDevice *dev, + PCIINTxRoutingNotifier notifier); +void pci_device_reset(PCIDevice *dev); +void pci_bus_reset(PCIBus *bus); + +PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, + const char *default_devaddr); +PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, + const char *default_devaddr); + +PCIDevice *pci_vga_init(PCIBus *bus); + +int pci_bus_num(PCIBus *s); +void pci_for_each_device(PCIBus *bus, int bus_num, + void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque), + void *opaque); +PCIBus *pci_find_root_bus(int domain); +int pci_find_domain(const PCIBus *bus); +PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn); +int pci_qdev_find_device(const char *id, PCIDevice **pdev); +PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr); + +int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, + unsigned *slotp); + +void pci_device_deassert_intx(PCIDevice *dev); + +typedef DMAContext *(*PCIDMAContextFunc)(PCIBus *, void *, int); + +void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque); + +static inline void +pci_set_byte(uint8_t *config, uint8_t val) +{ + *config = val; +} + +static inline uint8_t +pci_get_byte(const uint8_t *config) +{ + return *config; +} + +static inline void +pci_set_word(uint8_t *config, uint16_t val) +{ + cpu_to_le16wu((uint16_t *)config, val); +} + +static inline uint16_t +pci_get_word(const uint8_t *config) +{ + return le16_to_cpupu((const uint16_t *)config); +} + +static inline void +pci_set_long(uint8_t *config, uint32_t val) +{ + cpu_to_le32wu((uint32_t *)config, val); +} + +static inline uint32_t +pci_get_long(const uint8_t *config) +{ + return le32_to_cpupu((const uint32_t *)config); +} + +static inline void +pci_set_quad(uint8_t *config, uint64_t val) +{ + cpu_to_le64w((uint64_t *)config, val); +} + +static inline uint64_t +pci_get_quad(const uint8_t *config) +{ + return le64_to_cpup((const uint64_t *)config); +} + +static inline void +pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val) +{ + pci_set_word(&pci_config[PCI_VENDOR_ID], val); +} + +static inline void +pci_config_set_device_id(uint8_t *pci_config, uint16_t val) +{ + pci_set_word(&pci_config[PCI_DEVICE_ID], val); +} + +static inline void +pci_config_set_revision(uint8_t *pci_config, uint8_t val) +{ + pci_set_byte(&pci_config[PCI_REVISION_ID], val); +} + +static inline void +pci_config_set_class(uint8_t *pci_config, uint16_t val) +{ + pci_set_word(&pci_config[PCI_CLASS_DEVICE], val); +} + +static inline void +pci_config_set_prog_interface(uint8_t *pci_config, uint8_t val) +{ + pci_set_byte(&pci_config[PCI_CLASS_PROG], val); +} + +static inline void +pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val) +{ + pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val); +} + +/* + * helper functions to do bit mask operation on configuration space. + * Just to set bit, use test-and-set and discard returned value. + * Just to clear bit, use test-and-clear and discard returned value. + * NOTE: They aren't atomic. + */ +static inline uint8_t +pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask) +{ + uint8_t val = pci_get_byte(config); + pci_set_byte(config, val & ~mask); + return val & mask; +} + +static inline uint8_t +pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask) +{ + uint8_t val = pci_get_byte(config); + pci_set_byte(config, val | mask); + return val & mask; +} + +static inline uint16_t +pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask) +{ + uint16_t val = pci_get_word(config); + pci_set_word(config, val & ~mask); + return val & mask; +} + +static inline uint16_t +pci_word_test_and_set_mask(uint8_t *config, uint16_t mask) +{ + uint16_t val = pci_get_word(config); + pci_set_word(config, val | mask); + return val & mask; +} + +static inline uint32_t +pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask) +{ + uint32_t val = pci_get_long(config); + pci_set_long(config, val & ~mask); + return val & mask; +} + +static inline uint32_t +pci_long_test_and_set_mask(uint8_t *config, uint32_t mask) +{ + uint32_t val = pci_get_long(config); + pci_set_long(config, val | mask); + return val & mask; +} + +static inline uint64_t +pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask) +{ + uint64_t val = pci_get_quad(config); + pci_set_quad(config, val & ~mask); + return val & mask; +} + +static inline uint64_t +pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask) +{ + uint64_t val = pci_get_quad(config); + pci_set_quad(config, val | mask); + return val & mask; +} + +/* Access a register specified by a mask */ +static inline void +pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg) +{ + uint8_t val = pci_get_byte(config); + uint8_t rval = reg << (ffs(mask) - 1); + pci_set_byte(config, (~mask & val) | (mask & rval)); +} + +static inline uint8_t +pci_get_byte_by_mask(uint8_t *config, uint8_t mask) +{ + uint8_t val = pci_get_byte(config); + return (val & mask) >> (ffs(mask) - 1); +} + +static inline void +pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg) +{ + uint16_t val = pci_get_word(config); + uint16_t rval = reg << (ffs(mask) - 1); + pci_set_word(config, (~mask & val) | (mask & rval)); +} + +static inline uint16_t +pci_get_word_by_mask(uint8_t *config, uint16_t mask) +{ + uint16_t val = pci_get_word(config); + return (val & mask) >> (ffs(mask) - 1); +} + +static inline void +pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg) +{ + uint32_t val = pci_get_long(config); + uint32_t rval = reg << (ffs(mask) - 1); + pci_set_long(config, (~mask & val) | (mask & rval)); +} + +static inline uint32_t +pci_get_long_by_mask(uint8_t *config, uint32_t mask) +{ + uint32_t val = pci_get_long(config); + return (val & mask) >> (ffs(mask) - 1); +} + +static inline void +pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg) +{ + uint64_t val = pci_get_quad(config); + uint64_t rval = reg << (ffs(mask) - 1); + pci_set_quad(config, (~mask & val) | (mask & rval)); +} + +static inline uint64_t +pci_get_quad_by_mask(uint8_t *config, uint64_t mask) +{ + uint64_t val = pci_get_quad(config); + return (val & mask) >> (ffs(mask) - 1); +} + +PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, + const char *name); +PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, + bool multifunction, + const char *name); +PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); +PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name); + +static inline int pci_is_express(const PCIDevice *d) +{ + return d->cap_present & QEMU_PCI_CAP_EXPRESS; +} + +static inline uint32_t pci_config_size(const PCIDevice *d) +{ + return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; +} + +/* DMA access functions */ +static inline DMAContext *pci_dma_context(PCIDevice *dev) +{ + return dev->dma; +} + +static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, + void *buf, dma_addr_t len, DMADirection dir) +{ + dma_memory_rw(pci_dma_context(dev), addr, buf, len, dir); + return 0; +} + +static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr, + void *buf, dma_addr_t len) +{ + return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE); +} + +static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr, + const void *buf, dma_addr_t len) +{ + return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE); +} + +#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ + static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr) \ + { \ + return ld##_l##_dma(pci_dma_context(dev), addr); \ + } \ + static inline void st##_s##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr, uint##_bits##_t val) \ + { \ + st##_s##_dma(pci_dma_context(dev), addr, val); \ + } + +PCI_DMA_DEFINE_LDST(ub, b, 8); +PCI_DMA_DEFINE_LDST(uw_le, w_le, 16) +PCI_DMA_DEFINE_LDST(l_le, l_le, 32); +PCI_DMA_DEFINE_LDST(q_le, q_le, 64); +PCI_DMA_DEFINE_LDST(uw_be, w_be, 16) +PCI_DMA_DEFINE_LDST(l_be, l_be, 32); +PCI_DMA_DEFINE_LDST(q_be, q_be, 64); + +#undef PCI_DMA_DEFINE_LDST + +static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, + dma_addr_t *plen, DMADirection dir) +{ + void *buf; + + buf = dma_memory_map(pci_dma_context(dev), addr, plen, dir); + return buf; +} + +static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len, + DMADirection dir, dma_addr_t access_len) +{ + dma_memory_unmap(pci_dma_context(dev), buffer, len, dir, access_len); +} + +static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev, + int alloc_hint) +{ + qemu_sglist_init(qsg, alloc_hint, pci_dma_context(dev)); +} + +extern const VMStateDescription vmstate_pci_device; + +#define VMSTATE_PCI_DEVICE(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(PCIDevice), \ + .vmsd = &vmstate_pci_device, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, PCIDevice), \ +} + +#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(PCIDevice), \ + .vmsd = &vmstate_pci_device, \ + .flags = VMS_STRUCT|VMS_POINTER, \ + .offset = vmstate_offset_pointer(_state, _field, PCIDevice), \ +} + +#endif diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c new file mode 100644 index 0000000..4680501 --- /dev/null +++ b/hw/pci/pci_bridge.c @@ -0,0 +1,363 @@ +/* + * QEMU PCI bus manager + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to dea + + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM + + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/* + * split out from pci.c + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + */ + +#include "pci_bridge.h" +#include "pci_internals.h" +#include "range.h" + +/* PCI bridge subsystem vendor ID helper functions */ +#define PCI_SSVID_SIZEOF 8 +#define PCI_SSVID_SVID 4 +#define PCI_SSVID_SSID 6 + +int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, + uint16_t svid, uint16_t ssid) +{ + int pos; + pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF); + if (pos < 0) { + return pos; + } + + pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid); + pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid); + return pos; +} + +/* Accessor function to get parent bridge device from pci bus. */ +PCIDevice *pci_bridge_get_device(PCIBus *bus) +{ + return bus->parent_dev; +} + +/* Accessor function to get secondary bus from pci-to-pci bridge device */ +PCIBus *pci_bridge_get_sec_bus(PCIBridge *br) +{ + return &br->sec_bus; +} + +static uint32_t pci_config_get_io_base(const PCIDevice *d, + uint32_t base, uint32_t base_upper16) +{ + uint32_t val; + + val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8; + if (d->config[base] & PCI_IO_RANGE_TYPE_32) { + val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16; + } + return val; +} + +static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base) +{ + return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) + << 16; +} + +static pcibus_t pci_config_get_pref_base(const PCIDevice *d, + uint32_t base, uint32_t upper) +{ + pcibus_t tmp; + pcibus_t val; + + tmp = (pcibus_t)pci_get_word(d->config + base); + val = (tmp & PCI_PREF_RANGE_MASK) << 16; + if (tmp & PCI_PREF_RANGE_TYPE_64) { + val |= (pcibus_t)pci_get_long(d->config + upper) << 32; + } + return val; +} + +/* accessor function to get bridge filtering base address */ +pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type) +{ + pcibus_t base; + if (type & PCI_BASE_ADDRESS_SPACE_IO) { + base = pci_config_get_io_base(bridge, + PCI_IO_BASE, PCI_IO_BASE_UPPER16); + } else { + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { + base = pci_config_get_pref_base( + bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32); + } else { + base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE); + } + } + + return base; +} + +/* accessor funciton to get bridge filtering limit */ +pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type) +{ + pcibus_t limit; + if (type & PCI_BASE_ADDRESS_SPACE_IO) { + limit = pci_config_get_io_base(bridge, + PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16); + limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */ + } else { + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { + limit = pci_config_get_pref_base( + bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32); + } else { + limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT); + } + limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */ + } + return limit; +} + +static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, + uint8_t type, const char *name, + MemoryRegion *space, + MemoryRegion *parent_space, + bool enabled) +{ + pcibus_t base = pci_bridge_get_base(&bridge->dev, type); + pcibus_t limit = pci_bridge_get_limit(&bridge->dev, type); + /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly. + * Apparently no way to do this with existing memory APIs. */ + pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0; + + memory_region_init_alias(alias, name, space, base, size); + memory_region_add_subregion_overlap(parent_space, base, alias, 1); +} + +static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) +{ + PCIBus *parent = br->dev.bus; + PCIBridgeWindows *w = g_new(PCIBridgeWindows, 1); + uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND); + + pci_bridge_init_alias(br, &w->alias_pref_mem, + PCI_BASE_ADDRESS_MEM_PREFETCH, + "pci_bridge_pref_mem", + &br->address_space_mem, + parent->address_space_mem, + cmd & PCI_COMMAND_MEMORY); + pci_bridge_init_alias(br, &w->alias_mem, + PCI_BASE_ADDRESS_SPACE_MEMORY, + "pci_bridge_mem", + &br->address_space_mem, + parent->address_space_mem, + cmd & PCI_COMMAND_MEMORY); + pci_bridge_init_alias(br, &w->alias_io, + PCI_BASE_ADDRESS_SPACE_IO, + "pci_bridge_io", + &br->address_space_io, + parent->address_space_io, + cmd & PCI_COMMAND_IO); + /* TODO: optinal VGA and VGA palette snooping support. */ + + return w; +} + +static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w) +{ + PCIBus *parent = br->dev.bus; + + memory_region_del_subregion(parent->address_space_io, &w->alias_io); + memory_region_del_subregion(parent->address_space_mem, &w->alias_mem); + memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem); +} + +static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w) +{ + memory_region_destroy(&w->alias_io); + memory_region_destroy(&w->alias_mem); + memory_region_destroy(&w->alias_pref_mem); + g_free(w); +} + +static void pci_bridge_update_mappings(PCIBridge *br) +{ + PCIBridgeWindows *w = br->windows; + + /* Make updates atomic to: handle the case of one VCPU updating the bridge + * while another accesses an unaffected region. */ + memory_region_transaction_begin(); + pci_bridge_region_del(br, br->windows); + br->windows = pci_bridge_region_init(br); + memory_region_transaction_commit(); + pci_bridge_region_cleanup(br, w); +} + +/* default write_config function for PCI-to-PCI bridge */ +void pci_bridge_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + PCIBridge *s = container_of(d, PCIBridge, dev); + uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); + uint16_t newctl; + + pci_default_write_config(d, address, val, len); + + if (ranges_overlap(address, len, PCI_COMMAND, 2) || + + /* io base/limit */ + ranges_overlap(address, len, PCI_IO_BASE, 2) || + + /* memory base/limit, prefetchable base/limit and + io base/limit upper 16 */ + ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { + pci_bridge_update_mappings(s); + } + + newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); + if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) { + /* Trigger hot reset on 0->1 transition. */ + pci_bus_reset(&s->sec_bus); + } +} + +void pci_bridge_disable_base_limit(PCIDevice *dev) +{ + uint8_t *conf = dev->config; + + pci_byte_test_and_set_mask(conf + PCI_IO_BASE, + PCI_IO_RANGE_MASK & 0xff); + pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, + PCI_IO_RANGE_MASK & 0xff); + pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE, + PCI_MEMORY_RANGE_MASK & 0xffff); + pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, + PCI_MEMORY_RANGE_MASK & 0xffff); + pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE, + PCI_PREF_RANGE_MASK & 0xffff); + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, + PCI_PREF_RANGE_MASK & 0xffff); + pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); + pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); +} + +/* reset bridge specific configuration registers */ +void pci_bridge_reset(DeviceState *qdev) +{ + PCIDevice *dev = PCI_DEVICE(qdev); + uint8_t *conf = dev->config; + + conf[PCI_PRIMARY_BUS] = 0; + conf[PCI_SECONDARY_BUS] = 0; + conf[PCI_SUBORDINATE_BUS] = 0; + conf[PCI_SEC_LATENCY_TIMER] = 0; + + /* + * the default values for base/limit registers aren't specified + * in the PCI-to-PCI-bridge spec. So we don't thouch them here. + * Each implementation can override it. + * typical implementation does + * zero base/limit registers or + * disable forwarding: pci_bridge_disable_base_limit() + * If disable forwarding is wanted, call pci_bridge_disable_base_limit() + * after this function. + */ + pci_byte_test_and_clear_mask(conf + PCI_IO_BASE, + PCI_IO_RANGE_MASK & 0xff); + pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, + PCI_IO_RANGE_MASK & 0xff); + pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE, + PCI_MEMORY_RANGE_MASK & 0xffff); + pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, + PCI_MEMORY_RANGE_MASK & 0xffff); + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE, + PCI_PREF_RANGE_MASK & 0xffff); + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, + PCI_PREF_RANGE_MASK & 0xffff); + pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); + pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); + + pci_set_word(conf + PCI_BRIDGE_CONTROL, 0); +} + +/* default qdev initialization function for PCI-to-PCI bridge */ +int pci_bridge_initfn(PCIDevice *dev) +{ + PCIBus *parent = dev->bus; + PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); + PCIBus *sec_bus = &br->sec_bus; + + pci_word_test_and_set_mask(dev->config + PCI_STATUS, + PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); + pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI); + dev->config[PCI_HEADER_TYPE] = + (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) | + PCI_HEADER_TYPE_BRIDGE; + pci_set_word(dev->config + PCI_SEC_STATUS, + PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); + + /* + * If we don't specify the name, the bus will be addressed as <id>.0, where + * id is the device id. + * Since PCI Bridge devices have a single bus each, we don't need the index: + * let users address the bus using the device name. + */ + if (!br->bus_name && dev->qdev.id && *dev->qdev.id) { + br->bus_name = dev->qdev.id; + } + + qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev, + br->bus_name); + sec_bus->parent_dev = dev; + sec_bus->map_irq = br->map_irq; + sec_bus->address_space_mem = &br->address_space_mem; + memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX); + sec_bus->address_space_io = &br->address_space_io; + memory_region_init(&br->address_space_io, "pci_bridge_io", 65536); + br->windows = pci_bridge_region_init(br); + QLIST_INIT(&sec_bus->child); + QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); + return 0; +} + +/* default qdev clean up function for PCI-to-PCI bridge */ +void pci_bridge_exitfn(PCIDevice *pci_dev) +{ + PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); + assert(QLIST_EMPTY(&s->sec_bus.child)); + QLIST_REMOVE(&s->sec_bus, sibling); + pci_bridge_region_del(s, s->windows); + pci_bridge_region_cleanup(s, s->windows); + memory_region_destroy(&s->address_space_mem); + memory_region_destroy(&s->address_space_io); + /* qbus_free() is called automatically by qdev_free() */ +} + +/* + * before qdev initialization(qdev_init()), this function sets bus_name and + * map_irq callback which are necessry for pci_bridge_initfn() to + * initialize bus. + */ +void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, + pci_map_irq_fn map_irq) +{ + br->map_irq = map_irq; + br->bus_name = bus_name; +} diff --git a/hw/pci/pci_bridge.h b/hw/pci/pci_bridge.h new file mode 100644 index 0000000..a00accc --- /dev/null +++ b/hw/pci/pci_bridge.h @@ -0,0 +1,66 @@ +/* + * QEMU PCI bridge + * + * Copyright (c) 2004 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc] + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + */ + +#ifndef QEMU_PCI_BRIDGE_H +#define QEMU_PCI_BRIDGE_H + +#include "pci.h" + +int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, + uint16_t svid, uint16_t ssid); + +PCIDevice *pci_bridge_get_device(PCIBus *bus); +PCIBus *pci_bridge_get_sec_bus(PCIBridge *br); + +pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type); +pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type); + +void pci_bridge_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len); +void pci_bridge_disable_base_limit(PCIDevice *dev); +void pci_bridge_reset_reg(PCIDevice *dev); +void pci_bridge_reset(DeviceState *qdev); + +int pci_bridge_initfn(PCIDevice *pci_dev); +void pci_bridge_exitfn(PCIDevice *pci_dev); + + +/* + * before qdev initialization(qdev_init()), this function sets bus_name and + * map_irq callback which are necessry for pci_bridge_initfn() to + * initialize bus. + */ +void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, + pci_map_irq_fn map_irq); + +#endif /* QEMU_PCI_BRIDGE_H */ +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * indent-tab-mode: nil + * End: + */ diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c new file mode 100644 index 0000000..68e328c --- /dev/null +++ b/hw/pci/pci_host.c @@ -0,0 +1,180 @@ +/* + * pci_host.c + * + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "pci.h" +#include "pci_host.h" + +/* debug PCI */ +//#define DEBUG_PCI + +#ifdef DEBUG_PCI +#define PCI_DPRINTF(fmt, ...) \ +do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0) +#else +#define PCI_DPRINTF(fmt, ...) +#endif + +/* + * PCI address + * bit 16 - 24: bus number + * bit 8 - 15: devfun number + * bit 0 - 7: offset in configuration space of a given pci device + */ + +/* the helper functio to get a PCIDeice* for a given pci address */ +static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr) +{ + uint8_t bus_num = addr >> 16; + uint8_t devfn = addr >> 8; + + return pci_find_device(bus, bus_num, devfn); +} + +void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, + uint32_t limit, uint32_t val, uint32_t len) +{ + assert(len <= 4); + pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr)); +} + +uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, + uint32_t limit, uint32_t len) +{ + assert(len <= 4); + return pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr)); +} + +void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len) +{ + PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); + uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); + + if (!pci_dev) { + return; + } + + PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n", + __func__, pci_dev->name, config_addr, val, len); + pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE, + val, len); +} + +uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) +{ + PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); + uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); + uint32_t val; + + if (!pci_dev) { + return ~0x0; + } + + val = pci_host_config_read_common(pci_dev, config_addr, + PCI_CONFIG_SPACE_SIZE, len); + PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n", + __func__, pci_dev->name, config_addr, val, len); + + return val; +} + +static void pci_host_config_write(void *opaque, hwaddr addr, + uint64_t val, unsigned len) +{ + PCIHostState *s = opaque; + + PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", + __func__, addr, len, val); + if (addr != 0 || len != 4) { + return; + } + s->config_reg = val; +} + +static uint64_t pci_host_config_read(void *opaque, hwaddr addr, + unsigned len) +{ + PCIHostState *s = opaque; + uint32_t val = s->config_reg; + + PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n", + __func__, addr, len, val); + return val; +} + +static void pci_host_data_write(void *opaque, hwaddr addr, + uint64_t val, unsigned len) +{ + PCIHostState *s = opaque; + PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n", + addr, len, (unsigned)val); + if (s->config_reg & (1u << 31)) + pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); +} + +static uint64_t pci_host_data_read(void *opaque, + hwaddr addr, unsigned len) +{ + PCIHostState *s = opaque; + uint32_t val; + if (!(s->config_reg & (1 << 31))) + return 0xffffffff; + val = pci_data_read(s->bus, s->config_reg | (addr & 3), len); + PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n", + addr, len, val); + return val; +} + +const MemoryRegionOps pci_host_conf_le_ops = { + .read = pci_host_config_read, + .write = pci_host_config_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +const MemoryRegionOps pci_host_conf_be_ops = { + .read = pci_host_config_read, + .write = pci_host_config_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +const MemoryRegionOps pci_host_data_le_ops = { + .read = pci_host_data_read, + .write = pci_host_data_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +const MemoryRegionOps pci_host_data_be_ops = { + .read = pci_host_data_read, + .write = pci_host_data_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static const TypeInfo pci_host_type_info = { + .name = TYPE_PCI_HOST_BRIDGE, + .parent = TYPE_SYS_BUS_DEVICE, + .abstract = true, + .instance_size = sizeof(PCIHostState), +}; + +static void pci_host_register_types(void) +{ + type_register_static(&pci_host_type_info); +} + +type_init(pci_host_register_types) diff --git a/hw/pci/pci_host.h b/hw/pci/pci_host.h new file mode 100644 index 0000000..4b9c300 --- /dev/null +++ b/hw/pci/pci_host.h @@ -0,0 +1,62 @@ +/* + * QEMU Common PCI Host bridge configuration data space access routines. + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* Worker routines for a PCI host controller that uses an {address,data} + register pair to access PCI configuration space. */ + +#ifndef PCI_HOST_H +#define PCI_HOST_H + +#include "sysbus.h" + +#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge" +#define PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE) + +struct PCIHostState { + SysBusDevice busdev; + + MemoryRegion conf_mem; + MemoryRegion data_mem; + MemoryRegion mmcfg; + MemoryRegion *address_space; + uint32_t config_reg; + PCIBus *bus; +}; + +/* common internal helpers for PCI/PCIe hosts, cut off overflows */ +void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, + uint32_t limit, uint32_t val, uint32_t len); +uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, + uint32_t limit, uint32_t len); + +void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len); +uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len); + +extern const MemoryRegionOps pci_host_conf_le_ops; +extern const MemoryRegionOps pci_host_conf_be_ops; +extern const MemoryRegionOps pci_host_data_le_ops; +extern const MemoryRegionOps pci_host_data_be_ops; + +#endif /* PCI_HOST_H */ diff --git a/hw/pci/pci_ids.h b/hw/pci/pci_ids.h new file mode 100644 index 0000000..5df7245 --- /dev/null +++ b/hw/pci/pci_ids.h @@ -0,0 +1,147 @@ +/* + * PCI Class, Vendor and Device IDs + * + * Please keep sorted. + * + * Abbreviated version of linux/pci_ids.h + * + * QEMU-specific definitions belong in pci.h + */ + +/* Device classes and subclasses */ + +#define PCI_BASE_CLASS_STORAGE 0x01 +#define PCI_BASE_CLASS_NETWORK 0x02 + +#define PCI_CLASS_STORAGE_SCSI 0x0100 +#define PCI_CLASS_STORAGE_IDE 0x0101 +#define PCI_CLASS_STORAGE_RAID 0x0104 +#define PCI_CLASS_STORAGE_SATA 0x0106 +#define PCI_CLASS_STORAGE_OTHER 0x0180 + +#define PCI_CLASS_NETWORK_ETHERNET 0x0200 + +#define PCI_CLASS_DISPLAY_VGA 0x0300 +#define PCI_CLASS_DISPLAY_OTHER 0x0380 + +#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 + +#define PCI_CLASS_MEMORY_RAM 0x0500 + +#define PCI_CLASS_SYSTEM_OTHER 0x0880 + +#define PCI_CLASS_SERIAL_USB 0x0c03 +#define PCI_CLASS_SERIAL_SMBUS 0x0c05 + +#define PCI_CLASS_BRIDGE_HOST 0x0600 +#define PCI_CLASS_BRIDGE_ISA 0x0601 +#define PCI_CLASS_BRIDGE_PCI 0x0604 +#define PCI_CLASS_BRDIGE_PCI_INF_SUB 0x01 +#define PCI_CLASS_BRIDGE_OTHER 0x0680 + +#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 +#define PCI_CLASS_COMMUNICATION_OTHER 0x0780 + +#define PCI_CLASS_PROCESSOR_CO 0x0b40 +#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20 + +#define PCI_CLASS_OTHERS 0xff + +/* Vendors and devices. Sort key: vendor first, device next. */ + +#define PCI_VENDOR_ID_LSI_LOGIC 0x1000 +#define PCI_DEVICE_ID_LSI_53C895A 0x0012 +#define PCI_DEVICE_ID_LSI_SAS1078 0x0060 + +#define PCI_VENDOR_ID_DEC 0x1011 +#define PCI_DEVICE_ID_DEC_21154 0x0026 + +#define PCI_VENDOR_ID_CIRRUS 0x1013 + +#define PCI_VENDOR_ID_IBM 0x1014 + +#define PCI_VENDOR_ID_AMD 0x1022 +#define PCI_DEVICE_ID_AMD_LANCE 0x2000 +#define PCI_DEVICE_ID_AMD_SCSI 0x2020 + +#define PCI_VENDOR_ID_TI 0x104c + +#define PCI_VENDOR_ID_MOTOROLA 0x1057 +#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 +#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 + +#define PCI_VENDOR_ID_APPLE 0x106b +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 +#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b + +#define PCI_VENDOR_ID_SUN 0x108e +#define PCI_DEVICE_ID_SUN_EBUS 0x1000 +#define PCI_DEVICE_ID_SUN_SIMBA 0x5000 +#define PCI_DEVICE_ID_SUN_SABRE 0xa000 + +#define PCI_VENDOR_ID_CMD 0x1095 +#define PCI_DEVICE_ID_CMD_646 0x0646 + +#define PCI_VENDOR_ID_REALTEK 0x10ec +#define PCI_DEVICE_ID_REALTEK_8139 0x8139 + +#define PCI_VENDOR_ID_XILINX 0x10ee + +#define PCI_VENDOR_ID_VIA 0x1106 +#define PCI_DEVICE_ID_VIA_ISA_BRIDGE 0x0686 +#define PCI_DEVICE_ID_VIA_IDE 0x0571 +#define PCI_DEVICE_ID_VIA_UHCI 0x3038 +#define PCI_DEVICE_ID_VIA_ACPI 0x3057 +#define PCI_DEVICE_ID_VIA_AC97 0x3058 +#define PCI_DEVICE_ID_VIA_MC97 0x3068 + +#define PCI_VENDOR_ID_MARVELL 0x11ab + +#define PCI_VENDOR_ID_ENSONIQ 0x1274 +#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 + +#define PCI_VENDOR_ID_FREESCALE 0x1957 +#define PCI_DEVICE_ID_MPC8533E 0x0030 + +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL_82378 0x0484 +#define PCI_DEVICE_ID_INTEL_82441 0x1237 +#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 +#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e +#define PCI_DEVICE_ID_INTEL_82801D 0x24CD +#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab +#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 +#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 +#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 +#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 +#define PCI_DEVICE_ID_INTEL_82371AB 0x7111 +#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 +#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 + +#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 +#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 +#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 +#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 +#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 +#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 +#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 +#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 +#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 + +#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939 +#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a +#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c +#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed + +#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 + +#define PCI_VENDOR_ID_XEN 0x5853 +#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 + +#define PCI_VENDOR_ID_NEC 0x1033 +#define PCI_DEVICE_ID_NEC_UPD720200 0x0194 diff --git a/hw/pci/pci_internals.h b/hw/pci/pci_internals.h new file mode 100644 index 0000000..21d0ce6 --- /dev/null +++ b/hw/pci/pci_internals.h @@ -0,0 +1,78 @@ +#ifndef QEMU_PCI_INTERNALS_H +#define QEMU_PCI_INTERNALS_H + +/* + * This header files is private to pci.c and pci_bridge.c + * So following structures are opaque to others and shouldn't be + * accessed. + * + * For pci-to-pci bridge needs to include this header file to embed + * PCIBridge in its structure or to get sizeof(PCIBridge), + * However, they shouldn't access those following members directly. + * Use accessor function in pci.h, pci_bridge.h + */ + +#define TYPE_PCI_BUS "PCI" +#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) + +struct PCIBus { + BusState qbus; + PCIDMAContextFunc dma_context_fn; + void *dma_context_opaque; + uint8_t devfn_min; + pci_set_irq_fn set_irq; + pci_map_irq_fn map_irq; + pci_route_irq_fn route_intx_to_irq; + pci_hotplug_fn hotplug; + DeviceState *hotplug_qdev; + void *irq_opaque; + PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; + PCIDevice *parent_dev; + MemoryRegion *address_space_mem; + MemoryRegion *address_space_io; + + QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ + QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ + + /* The bus IRQ state is the logical OR of the connected devices. + Keep a count of the number of devices with raised IRQs. */ + int nirq; + int *irq_count; +}; + +typedef struct PCIBridgeWindows PCIBridgeWindows; + +/* + * Aliases for each of the address space windows that the bridge + * can forward. Mapped into the bridge's parent's address space, + * as subregions. + */ +struct PCIBridgeWindows { + MemoryRegion alias_pref_mem; + MemoryRegion alias_mem; + MemoryRegion alias_io; +}; + +struct PCIBridge { + PCIDevice dev; + + /* private member */ + PCIBus sec_bus; + /* + * Memory regions for the bridge's address spaces. These regions are not + * directly added to system_memory/system_io or its descendants. + * Bridge's secondary bus points to these, so that devices + * under the bridge see these regions as its address spaces. + * The regions are as large as the entire address space - + * they don't take into account any windows. + */ + MemoryRegion address_space_mem; + MemoryRegion address_space_io; + + PCIBridgeWindows *windows; + + pci_map_irq_fn map_irq; + const char *bus_name; +}; + +#endif /* QEMU_PCI_INTERNALS_H */ diff --git a/hw/pci/pci_regs.h b/hw/pci/pci_regs.h new file mode 100644 index 0000000..56a404b --- /dev/null +++ b/hw/pci/pci_regs.h @@ -0,0 +1,717 @@ +/* + * pci_regs.h + * + * PCI standard defines + * Copyright 1994, Drew Eckhardt + * Copyright 1997--1999 Martin Mares <mj@ucw.cz> + * + * For more information, please consult the following manuals (look at + * http://www.pcisig.com/ for how to get them): + * + * PCI BIOS Specification + * PCI Local Bus Specification + * PCI to PCI Bridge Specification + * PCI System Design Guide + * + * For hypertransport information, please consult the following manuals + * from http://www.hypertransport.org + * + * The Hypertransport I/O Link Specification + */ + +#ifndef LINUX_PCI_REGS_H +#define LINUX_PCI_REGS_H + +/* + * Under PCI, each device has 256 bytes of configuration address space, + * of which the first 64 bytes are standardized as follows: + */ +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ +#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ +#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ +#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ +#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ +#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ +#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ +#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ +#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ + +#define PCI_STATUS 0x06 /* 16 bits */ +#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */ +#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ +#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ +#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ +#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ +#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ +#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ +#define PCI_STATUS_DEVSEL_FAST 0x000 +#define PCI_STATUS_DEVSEL_MEDIUM 0x200 +#define PCI_STATUS_DEVSEL_SLOW 0x400 +#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ +#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ +#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ +#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ +#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ + +#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ +#define PCI_REVISION_ID 0x08 /* Revision ID */ +#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ +#define PCI_CLASS_DEVICE 0x0a /* Device class */ + +#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ +#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ +#define PCI_HEADER_TYPE 0x0e /* 8 bits */ +#define PCI_HEADER_TYPE_NORMAL 0 +#define PCI_HEADER_TYPE_BRIDGE 1 +#define PCI_HEADER_TYPE_CARDBUS 2 + +#define PCI_BIST 0x0f /* 8 bits */ +#define PCI_BIST_CODE_MASK 0x0f /* Return result */ +#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ +#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ + +/* + * Base addresses specify locations in memory or I/O space. + * Decoded size can be determined by writing a value of + * 0xffffffff to the register, and reading it back. Only + * 1 bits are decoded. + */ +#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ +#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ +#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ +#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ +#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ +#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ +#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ +#define PCI_BASE_ADDRESS_SPACE_IO 0x01 +#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 +#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 +#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ +#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ +#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ +#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ +#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) +#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) +/* bit 1 is reserved if address_space = 1 */ + +/* Header type 0 (normal devices) */ +#define PCI_CARDBUS_CIS 0x28 +#define PCI_SUBSYSTEM_VENDOR_ID 0x2c +#define PCI_SUBSYSTEM_ID 0x2e +#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ +#define PCI_ROM_ADDRESS_ENABLE 0x01 +#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) + +#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ + +/* 0x35-0x3b are reserved */ +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ +#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ +#define PCI_MIN_GNT 0x3e /* 8 bits */ +#define PCI_MAX_LAT 0x3f /* 8 bits */ + +/* Header type 1 (PCI-to-PCI bridges) */ +#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ +#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ +#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ +#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ +#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ +#define PCI_IO_LIMIT 0x1d +#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ +#define PCI_IO_RANGE_TYPE_16 0x00 +#define PCI_IO_RANGE_TYPE_32 0x01 +#define PCI_IO_RANGE_MASK (~0x0fUL) +#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ +#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ +#define PCI_MEMORY_LIMIT 0x22 +#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL +#define PCI_MEMORY_RANGE_MASK (~0x0fUL) +#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ +#define PCI_PREF_MEMORY_LIMIT 0x26 +#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL +#define PCI_PREF_RANGE_TYPE_32 0x00 +#define PCI_PREF_RANGE_TYPE_64 0x01 +#define PCI_PREF_RANGE_MASK (~0x0fUL) +#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ +#define PCI_PREF_LIMIT_UPPER32 0x2c +#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ +#define PCI_IO_LIMIT_UPPER16 0x32 +/* 0x34 same as for htype 0 */ +/* 0x35-0x3b is reserved */ +#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ +/* 0x3c-0x3d are same as for htype 0 */ +#define PCI_BRIDGE_CONTROL 0x3e +#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ +#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ +#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */ +#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ +#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ +#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ +#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ + +/* Header type 2 (CardBus bridges) */ +#define PCI_CB_CAPABILITY_LIST 0x14 +/* 0x15 reserved */ +#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */ +#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */ +#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */ +#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */ +#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ +#define PCI_CB_MEMORY_BASE_0 0x1c +#define PCI_CB_MEMORY_LIMIT_0 0x20 +#define PCI_CB_MEMORY_BASE_1 0x24 +#define PCI_CB_MEMORY_LIMIT_1 0x28 +#define PCI_CB_IO_BASE_0 0x2c +#define PCI_CB_IO_BASE_0_HI 0x2e +#define PCI_CB_IO_LIMIT_0 0x30 +#define PCI_CB_IO_LIMIT_0_HI 0x32 +#define PCI_CB_IO_BASE_1 0x34 +#define PCI_CB_IO_BASE_1_HI 0x36 +#define PCI_CB_IO_LIMIT_1 0x38 +#define PCI_CB_IO_LIMIT_1_HI 0x3a +#define PCI_CB_IO_RANGE_MASK (~0x03UL) +/* 0x3c-0x3d are same as for htype 0 */ +#define PCI_CB_BRIDGE_CONTROL 0x3e +#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */ +#define PCI_CB_BRIDGE_CTL_SERR 0x02 +#define PCI_CB_BRIDGE_CTL_ISA 0x04 +#define PCI_CB_BRIDGE_CTL_VGA 0x08 +#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20 +#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */ +#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */ +#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */ +#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200 +#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400 +#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 +#define PCI_CB_SUBSYSTEM_ID 0x42 +#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */ +/* 0x48-0x7f reserved */ + +/* Capability lists */ + +#define PCI_CAP_LIST_ID 0 /* Capability ID */ +#define PCI_CAP_ID_PM 0x01 /* Power Management */ +#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ +#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ +#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ +#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ +#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ +#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ +#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */ +#define PCI_CAP_ID_DBG 0x0A /* Debug port */ +#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ +#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ +#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ +#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ +#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define PCI_CAP_ID_SATA 0x12 /* Serial ATA */ +#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ +#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ +#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ +#define PCI_CAP_SIZEOF 4 + +/* Power Management Registers */ + +#define PCI_PM_PMC 2 /* PM Capabilities Register */ +#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ +#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ +#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ +#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ +#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */ +#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ +#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ +#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ +#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ +#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ +#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ +#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ +#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ +#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ +#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */ +#define PCI_PM_CTRL 4 /* PM control and status register */ +#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ +#define PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */ +#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ +#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ +#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ +#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ +#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ +#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ +#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ +#define PCI_PM_DATA_REGISTER 7 /* (??) */ +#define PCI_PM_SIZEOF 8 + +/* AGP registers */ + +#define PCI_AGP_VERSION 2 /* BCD version number */ +#define PCI_AGP_RFU 3 /* Rest of capability flags */ +#define PCI_AGP_STATUS 4 /* Status register */ +#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ +#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ +#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ +#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ +#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ +#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ +#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ +#define PCI_AGP_COMMAND 8 /* Control register */ +#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ +#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ +#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ +#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ +#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ +#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ +#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ +#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ +#define PCI_AGP_SIZEOF 12 + +/* Vital Product Data */ + +#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */ +#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */ +#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */ +#define PCI_VPD_DATA 4 /* 32-bits of data returned here */ + +/* Slot Identification */ + +#define PCI_SID_ESR 2 /* Expansion Slot Register */ +#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ +#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ +#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ + +/* Message Signalled Interrupts registers */ + +#define PCI_MSI_FLAGS 2 /* Various flags */ +#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */ +#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */ +#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */ +#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */ +#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */ +#define PCI_MSI_RFU 3 /* Rest of capability flags */ +#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ +#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ +#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ +#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */ +#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ +#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ + +/* MSI-X registers */ +#define PCI_MSIX_FLAGS 2 +#define PCI_MSIX_FLAGS_QSIZE 0x7FF +#define PCI_MSIX_FLAGS_ENABLE (1 << 15) +#define PCI_MSIX_FLAGS_MASKALL (1 << 14) +#define PCI_MSIX_TABLE 4 +#define PCI_MSIX_PBA 8 +#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) + +/* MSI-X entry's format */ +#define PCI_MSIX_ENTRY_SIZE 16 +#define PCI_MSIX_ENTRY_LOWER_ADDR 0 +#define PCI_MSIX_ENTRY_UPPER_ADDR 4 +#define PCI_MSIX_ENTRY_DATA 8 +#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 +#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 + +/* CompactPCI Hotswap Register */ + +#define PCI_CHSWP_CSR 2 /* Control and Status Register */ +#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */ +#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */ +#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */ +#define PCI_CHSWP_LOO 0x08 /* LED On / Off */ +#define PCI_CHSWP_PI 0x30 /* Programming Interface */ +#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ +#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ + +/* PCI Advanced Feature registers */ + +#define PCI_AF_LENGTH 2 +#define PCI_AF_CAP 3 +#define PCI_AF_CAP_TP 0x01 +#define PCI_AF_CAP_FLR 0x02 +#define PCI_AF_CTRL 4 +#define PCI_AF_CTRL_FLR 0x01 +#define PCI_AF_STATUS 5 +#define PCI_AF_STATUS_TP 0x01 + +/* PCI-X registers */ + +#define PCI_X_CMD 2 /* Modes & Features */ +#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ +#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ +#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ +#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ +#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ +#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ +#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ + /* Max # of outstanding split transactions */ +#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */ +#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */ +#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */ +#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */ +#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */ +#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */ +#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */ +#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */ +#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ +#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */ +#define PCI_X_STATUS 4 /* PCI-X capabilities */ +#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */ +#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */ +#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */ +#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */ +#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */ +#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */ +#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */ +#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count */ +#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */ +#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */ +#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ +#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ +#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ + +/* PCI Bridge Subsystem ID registers */ + +#define PCI_SSVID_VENDOR_ID 4 /* PCI-Bridge subsystem vendor id register */ +#define PCI_SSVID_DEVICE_ID 6 /* PCI-Bridge subsystem device id register */ + +/* PCI Express capability registers */ + +#define PCI_EXP_FLAGS 2 /* Capabilities register */ +#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ +#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ +#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ +#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ +#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ +#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ +#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ +#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ +#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */ +#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ +#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ +#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ +#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ +#define PCI_EXP_DEVCAP 4 /* Device capabilities */ +#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */ +#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */ +#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */ +#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */ +#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */ +#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ +#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ +#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ +#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ +#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ +#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ +#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ +#define PCI_EXP_DEVCTL 8 /* Device Control */ +#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ +#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ +#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ +#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ +#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */ +#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ +#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ +#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ +#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ +#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ +#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ +#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ +#define PCI_EXP_DEVSTA 10 /* Device Status */ +#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ +#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ +#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */ +#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */ +#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ +#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ +#define PCI_EXP_LNKCAP 12 /* Link Capabilities */ +#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */ +#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */ +#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */ +#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */ +#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */ +#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* L1 Clock Power Management */ +#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Reporting Capable */ +#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link Active Reporting Capable */ +#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notification Capability */ +#define PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */ +#define PCI_EXP_LNKCTL 16 /* Link Control */ +#define PCI_EXP_LNKCTL_ASPMC 0x0003 /* ASPM Control */ +#define PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */ +#define PCI_EXP_LNKCTL_LD 0x0010 /* Link Disable */ +#define PCI_EXP_LNKCTL_RL 0x0020 /* Retrain Link */ +#define PCI_EXP_LNKCTL_CCC 0x0040 /* Common Clock Configuration */ +#define PCI_EXP_LNKCTL_ES 0x0080 /* Extended Synch */ +#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ +#define PCI_EXP_LNKCTL_HAWD 0x0200 /* Hardware Autonomous Width Disable */ +#define PCI_EXP_LNKCTL_LBMIE 0x0400 /* Link Bandwidth Management Interrupt Enable */ +#define PCI_EXP_LNKCTL_LABIE 0x0800 /* Lnk Autonomous Bandwidth Interrupt Enable */ +#define PCI_EXP_LNKSTA 18 /* Link Status */ +#define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */ +#define PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */ +#define PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */ +#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Nogotiated Link Width */ +#define PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */ +#define PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */ +#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ +#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ +#define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ +#define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */ +#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ +#define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */ +#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */ +#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */ +#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Present */ +#define PCI_EXP_SLTCAP_PIP 0x00000010 /* Power Indicator Present */ +#define PCI_EXP_SLTCAP_HPS 0x00000020 /* Hot-Plug Surprise */ +#define PCI_EXP_SLTCAP_HPC 0x00000040 /* Hot-Plug Capable */ +#define PCI_EXP_SLTCAP_SPLV 0x00007f80 /* Slot Power Limit Value */ +#define PCI_EXP_SLTCAP_SPLS 0x00018000 /* Slot Power Limit Scale */ +#define PCI_EXP_SLTCAP_EIP 0x00020000 /* Electromechanical Interlock Present */ +#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Support */ +#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ +#define PCI_EXP_SLTCTL 24 /* Slot Control */ +#define PCI_EXP_SLTCTL_ABPE 0x0001 /* Attention Button Pressed Enable */ +#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enable */ +#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable */ +#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed Enable */ +#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable */ +#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */ +#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */ +#define PCI_EXP_SLTCTL_PIC 0x0300 /* Power Indicator Control */ +#define PCI_EXP_SLTCTL_PCC 0x0400 /* Power Controller Control */ +#define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */ +#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */ +#define PCI_EXP_SLTSTA 26 /* Slot Status */ +#define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */ +#define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */ +#define PCI_EXP_SLTSTA_MRLSC 0x0004 /* MRL Sensor Changed */ +#define PCI_EXP_SLTSTA_PDC 0x0008 /* Presence Detect Changed */ +#define PCI_EXP_SLTSTA_CC 0x0010 /* Command Completed */ +#define PCI_EXP_SLTSTA_MRLSS 0x0020 /* MRL Sensor State */ +#define PCI_EXP_SLTSTA_PDS 0x0040 /* Presence Detect State */ +#define PCI_EXP_SLTSTA_EIS 0x0080 /* Electromechanical Interlock Status */ +#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Changed */ +#define PCI_EXP_RTCTL 28 /* Root Control */ +#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctable Error */ +#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal Error */ +#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Error */ +#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */ +#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */ +#define PCI_EXP_RTCAP 30 /* Root Capabilities */ +#define PCI_EXP_RTSTA 32 /* Root Status */ +#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ +#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ +#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ +#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ +#define PCI_EXP_DEVCAP2_LTR 0x800 /* Latency tolerance reporting */ +#define PCI_EXP_OBFF_MASK 0xc0000 /* OBFF support mechanism */ +#define PCI_EXP_OBFF_MSG 0x40000 /* New message signaling */ +#define PCI_EXP_OBFF_WAKE 0x80000 /* Re-use WAKE# for OBFF */ +#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ +#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */ +#define PCI_EXP_IDO_REQ_EN 0x100 /* ID-based ordering request enable */ +#define PCI_EXP_IDO_CMP_EN 0x200 /* ID-based ordering completion enable */ +#define PCI_EXP_LTR_EN 0x400 /* Latency tolerance reporting */ +#define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message type A */ +#define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message type B */ +#define PCI_EXP_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ +#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ +#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ + +/* Extended Capabilities (PCI-X 2.0 and Express) */ +#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff) +#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf) +#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc) + +#define PCI_EXT_CAP_ID_ERR 1 +#define PCI_EXT_CAP_ID_VC 2 +#define PCI_EXT_CAP_ID_DSN 3 +#define PCI_EXT_CAP_ID_PWR 4 +#define PCI_EXT_CAP_ID_VNDR 11 +#define PCI_EXT_CAP_ID_ACS 13 +#define PCI_EXT_CAP_ID_ARI 14 +#define PCI_EXT_CAP_ID_ATS 15 +#define PCI_EXT_CAP_ID_SRIOV 16 +#define PCI_EXT_CAP_ID_LTR 24 + +/* Advanced Error Reporting */ +#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ +#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */ +#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ +#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */ +#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */ +#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */ +#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */ +#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */ +#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */ +#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */ +#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */ +#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */ +#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */ + /* Same bits as above */ +#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */ + /* Same bits as above */ +#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */ +#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */ +#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */ +#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */ +#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */ +#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */ +#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ + /* Same bits as above */ +#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ +#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */ +#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */ +#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */ +#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */ +#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ +#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */ +#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */ +/* Correctable Err Reporting Enable */ +#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 +/* Non-fatal Err Reporting Enable */ +#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 +/* Fatal Err Reporting Enable */ +#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 +#define PCI_ERR_ROOT_STATUS 48 +#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ +/* Multi ERR_COR Received */ +#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 +/* ERR_FATAL/NONFATAL Recevied */ +#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 +/* Multi ERR_FATAL/NONFATAL Recevied */ +#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 +#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */ +#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ +#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ +#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */ + +/* Virtual Channel */ +#define PCI_VC_PORT_REG1 4 +#define PCI_VC_PORT_REG2 8 +#define PCI_VC_PORT_CTRL 12 +#define PCI_VC_PORT_STATUS 14 +#define PCI_VC_RES_CAP 16 +#define PCI_VC_RES_CTRL 20 +#define PCI_VC_RES_STATUS 26 + +/* Power Budgeting */ +#define PCI_PWR_DSR 4 /* Data Select Register */ +#define PCI_PWR_DATA 8 /* Data Register */ +#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */ +#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */ +#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */ +#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */ +#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */ +#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */ +#define PCI_PWR_CAP 12 /* Capability */ +#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ + +/* + * Hypertransport sub capability types + * + * Unfortunately there are both 3 bit and 5 bit capability types defined + * in the HT spec, catering for that is a little messy. You probably don't + * want to use these directly, just use pci_find_ht_capability() and it + * will do the right thing for you. + */ +#define HT_3BIT_CAP_MASK 0xE0 +#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ +#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ + +#define HT_5BIT_CAP_MASK 0xF8 +#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ +#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ +#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ +#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */ +#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */ +#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */ +#define HT_MSI_FLAGS 0x02 /* Offset to flags */ +#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */ +#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */ +#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */ +#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */ +#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */ +#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */ +#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */ +#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */ +#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */ +#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */ +#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */ + +/* Alternative Routing-ID Interpretation */ +#define PCI_ARI_CAP 0x04 /* ARI Capability Register */ +#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */ +#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */ +#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */ +#define PCI_ARI_CTRL 0x06 /* ARI Control Register */ +#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */ +#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ +#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ + +/* Address Translation Service */ +#define PCI_ATS_CAP 0x04 /* ATS Capability Register */ +#define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f) /* Invalidate Queue Depth */ +#define PCI_ATS_MAX_QDEP 32 /* Max Invalidate Queue Depth */ +#define PCI_ATS_CTRL 0x06 /* ATS Control Register */ +#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */ +#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */ +#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */ + +/* Single Root I/O Virtualization */ +#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ +#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ +#define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */ +#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */ +#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */ +#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */ +#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */ +#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */ +#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */ +#define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */ +#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */ +#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */ +#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */ +#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */ +#define PCI_SRIOV_FUNC_LINK 0x12 /* Function Dependency Link */ +#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */ +#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */ +#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */ +#define PCI_SRIOV_SUP_PGSIZE 0x1c /* Supported Page Sizes */ +#define PCI_SRIOV_SYS_PGSIZE 0x20 /* System Page Size */ +#define PCI_SRIOV_BAR 0x24 /* VF BAR0 */ +#define PCI_SRIOV_NUM_BARS 6 /* Number of VF BARs */ +#define PCI_SRIOV_VFM 0x3c /* VF Migration State Array Offset*/ +#define PCI_SRIOV_VFM_BIR(x) ((x) & 7) /* State BIR */ +#define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7) /* State Offset */ +#define PCI_SRIOV_VFM_UA 0x0 /* Inactive.Unavailable */ +#define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */ +#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ +#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ + +#define PCI_LTR_MAX_SNOOP_LAT 0x4 +#define PCI_LTR_MAX_NOSNOOP_LAT 0x6 +#define PCI_LTR_VALUE_MASK 0x000003ff +#define PCI_LTR_SCALE_MASK 0x00001c00 +#define PCI_LTR_SCALE_SHIFT 10 + +/* Access Control Service */ +#define PCI_ACS_CAP 0x04 /* ACS Capability Register */ +#define PCI_ACS_SV 0x01 /* Source Validation */ +#define PCI_ACS_TB 0x02 /* Translation Blocking */ +#define PCI_ACS_RR 0x04 /* P2P Request Redirect */ +#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */ +#define PCI_ACS_UF 0x10 /* Upstream Forwarding */ +#define PCI_ACS_EC 0x20 /* P2P Egress Control */ +#define PCI_ACS_DT 0x40 /* Direct Translated P2P */ +#define PCI_ACS_CTRL 0x06 /* ACS Control Register */ +#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ + +#endif /* LINUX_PCI_REGS_H */ diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c new file mode 100644 index 0000000..7c92f19 --- /dev/null +++ b/hw/pci/pcie.c @@ -0,0 +1,555 @@ +/* + * pcie.c + * + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu-common.h" +#include "pci_bridge.h" +#include "pcie.h" +#include "msix.h" +#include "msi.h" +#include "pci_internals.h" +#include "pcie_regs.h" +#include "range.h" + +//#define DEBUG_PCIE +#ifdef DEBUG_PCIE +# define PCIE_DPRINTF(fmt, ...) \ + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) +#else +# define PCIE_DPRINTF(fmt, ...) do {} while (0) +#endif +#define PCIE_DEV_PRINTF(dev, fmt, ...) \ + PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) + + +/*************************************************************************** + * pci express capability helper functions + */ +int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) +{ + int pos; + uint8_t *exp_cap; + + assert(pci_is_express(dev)); + + pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, + PCI_EXP_VER2_SIZEOF); + if (pos < 0) { + return pos; + } + dev->exp.exp_cap = pos; + exp_cap = dev->config + pos; + + /* capability register + interrupt message number defaults to 0 */ + pci_set_word(exp_cap + PCI_EXP_FLAGS, + ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) | + PCI_EXP_FLAGS_VER2); + + /* device capability register + * table 7-12: + * roll based error reporting bit must be set by all + * Functions conforming to the ECN, PCI Express Base + * Specification, Revision 1.1., or subsequent PCI Express Base + * Specification revisions. + */ + pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER); + + pci_set_long(exp_cap + PCI_EXP_LNKCAP, + (port << PCI_EXP_LNKCAP_PN_SHIFT) | + PCI_EXP_LNKCAP_ASPMS_0S | + PCI_EXP_LNK_MLW_1 | + PCI_EXP_LNK_LS_25); + + pci_set_word(exp_cap + PCI_EXP_LNKSTA, + PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25); + + pci_set_long(exp_cap + PCI_EXP_DEVCAP2, + PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP); + + pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB); + return pos; +} + +void pcie_cap_exit(PCIDevice *dev) +{ + pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF); +} + +uint8_t pcie_cap_get_type(const PCIDevice *dev) +{ + uint32_t pos = dev->exp.exp_cap; + assert(pos > 0); + return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) & + PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT; +} + +/* MSI/MSI-X */ +/* pci express interrupt message number */ +/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */ +void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector) +{ + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; + assert(vector < 32); + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ); + pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS, + vector << PCI_EXP_FLAGS_IRQ_SHIFT); +} + +uint8_t pcie_cap_flags_get_vector(PCIDevice *dev) +{ + return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) & + PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT; +} + +void pcie_cap_deverr_init(PCIDevice *dev) +{ + uint32_t pos = dev->exp.exp_cap; + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP, + PCI_EXP_DEVCAP_RBER); + pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); + pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA, + PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED | + PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD); +} + +void pcie_cap_deverr_reset(PCIDevice *dev) +{ + uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; + pci_long_test_and_clear_mask(devctl, + PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); +} + +static void hotplug_event_update_event_status(PCIDevice *dev) +{ + uint32_t pos = dev->exp.exp_cap; + uint8_t *exp_cap = dev->config + pos; + uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL); + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); + + dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) && + (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED); +} + +static void hotplug_event_notify(PCIDevice *dev) +{ + bool prev = dev->exp.hpev_notified; + + hotplug_event_update_event_status(dev); + + if (prev == dev->exp.hpev_notified) { + return; + } + + /* Note: the logic above does not take into account whether interrupts + * are masked. The result is that interrupt will be sent when it is + * subsequently unmasked. This appears to be legal: Section 6.7.3.4: + * The Port may optionally send an MSI when there are hot-plug events that + * occur while interrupt generation is disabled, and interrupt generation is + * subsequently enabled. */ + if (msix_enabled(dev)) { + msix_notify(dev, pcie_cap_flags_get_vector(dev)); + } else if (msi_enabled(dev)) { + msi_notify(dev, pcie_cap_flags_get_vector(dev)); + } else { + qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified); + } +} + +static void hotplug_event_clear(PCIDevice *dev) +{ + hotplug_event_update_event_status(dev); + if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) { + qemu_set_irq(dev->irq[dev->exp.hpev_intx], 0); + } +} + +/* + * A PCI Express Hot-Plug Event has occurred, so update slot status register + * and notify OS of the event if necessary. + * + * 6.7.3 PCI Express Hot-Plug Events + * 6.7.3.4 Software Notification of Hot-Plug Events + */ +static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) +{ + /* Minor optimization: if nothing changed - no event is needed. */ + if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap + + PCI_EXP_SLTSTA, event)) { + return; + } + hotplug_event_notify(dev); +} + +static int pcie_cap_slot_hotplug(DeviceState *qdev, + PCIDevice *pci_dev, PCIHotplugState state) +{ + PCIDevice *d = PCI_DEVICE(qdev); + uint8_t *exp_cap = d->config + d->exp.exp_cap; + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); + + /* Don't send event when device is enabled during qemu machine creation: + * it is present on boot, no hotplug event is necessary. We do send an + * event when the device is disabled later. */ + if (state == PCI_COLDPLUG_ENABLED) { + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_PDS); + return 0; + } + + PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state); + if (sltsta & PCI_EXP_SLTSTA_EIS) { + /* the slot is electromechanically locked. + * This error is propagated up to qdev and then to HMP/QMP. + */ + return -EBUSY; + } + + /* TODO: multifunction hot-plug. + * Right now, only a device of function = 0 is allowed to be + * hot plugged/unplugged. + */ + assert(PCI_FUNC(pci_dev->devfn) == 0); + + if (state == PCI_HOTPLUG_ENABLED) { + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_PDS); + pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); + } else { + qdev_free(&pci_dev->qdev); + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_PDS); + pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); + } + return 0; +} + +/* pci express slot for pci express root/downstream port + PCI express capability slot registers */ +void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot) +{ + uint32_t pos = dev->exp.exp_cap; + + pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS, + PCI_EXP_FLAGS_SLOT); + + pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP, + ~PCI_EXP_SLTCAP_PSN); + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP, + (slot << PCI_EXP_SLTCAP_PSN_SHIFT) | + PCI_EXP_SLTCAP_EIP | + PCI_EXP_SLTCAP_HPS | + PCI_EXP_SLTCAP_HPC | + PCI_EXP_SLTCAP_PIP | + PCI_EXP_SLTCAP_AIP | + PCI_EXP_SLTCAP_ABP); + + pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PIC | + PCI_EXP_SLTCTL_AIC); + pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PIC_OFF | + PCI_EXP_SLTCTL_AIC_OFF); + pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PIC | + PCI_EXP_SLTCTL_AIC | + PCI_EXP_SLTCTL_HPIE | + PCI_EXP_SLTCTL_CCIE | + PCI_EXP_SLTCTL_PDCE | + PCI_EXP_SLTCTL_ABPE); + /* Although reading PCI_EXP_SLTCTL_EIC returns always 0, + * make the bit writable here in order to detect 1b is written. + * pcie_cap_slot_write_config() test-and-clear the bit, so + * this bit always returns 0 to the guest. + */ + pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_EIC); + + pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA, + PCI_EXP_HP_EV_SUPPORTED); + + dev->exp.hpev_notified = false; + + pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)), + pcie_cap_slot_hotplug, &dev->qdev); +} + +void pcie_cap_slot_reset(PCIDevice *dev) +{ + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; + + PCIE_DEV_PRINTF(dev, "reset\n"); + + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_EIC | + PCI_EXP_SLTCTL_PIC | + PCI_EXP_SLTCTL_AIC | + PCI_EXP_SLTCTL_HPIE | + PCI_EXP_SLTCTL_CCIE | + PCI_EXP_SLTCTL_PDCE | + PCI_EXP_SLTCTL_ABPE); + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PIC_OFF | + PCI_EXP_SLTCTL_AIC_OFF); + + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_EIS |/* on reset, + the lock is released */ + PCI_EXP_SLTSTA_CC | + PCI_EXP_SLTSTA_PDC | + PCI_EXP_SLTSTA_ABP); + + hotplug_event_update_event_status(dev); +} + +void pcie_cap_slot_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len) +{ + uint32_t pos = dev->exp.exp_cap; + uint8_t *exp_cap = dev->config + pos; + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); + + if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) { + hotplug_event_clear(dev); + } + + if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) { + return; + } + + if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_EIC)) { + sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */ + pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta); + PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: " + "sltsta -> 0x%02"PRIx16"\n", + sltsta); + } + + hotplug_event_notify(dev); + + /* + * 6.7.3.2 Command Completed Events + * + * Software issues a command to a hot-plug capable Downstream Port by + * issuing a write transaction that targets any portion of the Port’s Slot + * Control register. A single write to the Slot Control register is + * considered to be a single command, even if the write affects more than + * one field in the Slot Control register. In response to this transaction, + * the Port must carry out the requested actions and then set the + * associated status field for the command completed event. */ + + /* Real hardware might take a while to complete requested command because + * physical movement would be involved like locking the electromechanical + * lock. However in our case, command is completed instantaneously above, + * so send a command completion event right now. + */ + pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI); +} + +int pcie_cap_slot_post_load(void *opaque, int version_id) +{ + PCIDevice *dev = opaque; + hotplug_event_update_event_status(dev); + return 0; +} + +void pcie_cap_slot_push_attention_button(PCIDevice *dev) +{ + pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP); +} + +/* root control/capabilities/status. PME isn't emulated for now */ +void pcie_cap_root_init(PCIDevice *dev) +{ + pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL, + PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | + PCI_EXP_RTCTL_SEFEE); +} + +void pcie_cap_root_reset(PCIDevice *dev) +{ + pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0); +} + +/* function level reset(FLR) */ +void pcie_cap_flr_init(PCIDevice *dev) +{ + pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP, + PCI_EXP_DEVCAP_FLR); + + /* Although reading BCR_FLR returns always 0, + * the bit is made writable here in order to detect the 1b is written + * pcie_cap_flr_write_config() test-and-clear the bit, so + * this bit always returns 0 to the guest. + */ + pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_BCR_FLR); +} + +void pcie_cap_flr_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len) +{ + uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; + if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) { + /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler + so the handler can detect FLR by looking at this bit. */ + pci_device_reset(dev); + pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR); + } +} + +/* Alternative Routing-ID Interpretation (ARI) */ +/* ari forwarding support for down stream port */ +void pcie_cap_ari_init(PCIDevice *dev) +{ + uint32_t pos = dev->exp.exp_cap; + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2, + PCI_EXP_DEVCAP2_ARI); + pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2, + PCI_EXP_DEVCTL2_ARI); +} + +void pcie_cap_ari_reset(PCIDevice *dev) +{ + uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2; + pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI); +} + +bool pcie_cap_is_ari_enabled(const PCIDevice *dev) +{ + if (!pci_is_express(dev)) { + return false; + } + if (!dev->exp.exp_cap) { + return false; + } + + return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & + PCI_EXP_DEVCTL2_ARI; +} + +/************************************************************************** + * pci express extended capability allocation functions + * uint16_t ext_cap_id (16 bit) + * uint8_t cap_ver (4 bit) + * uint16_t cap_offset (12 bit) + * uint16_t ext_cap_size + */ + +static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id, + uint16_t *prev_p) +{ + uint16_t prev = 0; + uint16_t next; + uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE); + + if (!header) { + /* no extended capability */ + next = 0; + goto out; + } + for (next = PCI_CONFIG_SPACE_SIZE; next; + prev = next, next = PCI_EXT_CAP_NEXT(header)) { + + assert(next >= PCI_CONFIG_SPACE_SIZE); + assert(next <= PCIE_CONFIG_SPACE_SIZE - 8); + + header = pci_get_long(dev->config + next); + if (PCI_EXT_CAP_ID(header) == cap_id) { + break; + } + } + +out: + if (prev_p) { + *prev_p = prev; + } + return next; +} + +uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id) +{ + return pcie_find_capability_list(dev, cap_id, NULL); +} + +static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next) +{ + uint16_t header = pci_get_long(dev->config + pos); + assert(!(next & (PCI_EXT_CAP_ALIGN - 1))); + header = (header & ~PCI_EXT_CAP_NEXT_MASK) | + ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK); + pci_set_long(dev->config + pos, header); +} + +/* + * caller must supply valid (offset, size) * such that the range shouldn't + * overlap with other capability or other registers. + * This function doesn't check it. + */ +void pcie_add_capability(PCIDevice *dev, + uint16_t cap_id, uint8_t cap_ver, + uint16_t offset, uint16_t size) +{ + uint32_t header; + uint16_t next; + + assert(offset >= PCI_CONFIG_SPACE_SIZE); + assert(offset < offset + size); + assert(offset + size < PCIE_CONFIG_SPACE_SIZE); + assert(size >= 8); + assert(pci_is_express(dev)); + + if (offset == PCI_CONFIG_SPACE_SIZE) { + header = pci_get_long(dev->config + offset); + next = PCI_EXT_CAP_NEXT(header); + } else { + uint16_t prev; + + /* 0 is reserved cap id. use internally to find the last capability + in the linked list */ + next = pcie_find_capability_list(dev, 0, &prev); + + assert(prev >= PCI_CONFIG_SPACE_SIZE); + assert(next == 0); + pcie_ext_cap_set_next(dev, prev, offset); + } + pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next)); + + /* Make capability read-only by default */ + memset(dev->wmask + offset, 0, size); + memset(dev->w1cmask + offset, 0, size); + /* Check capability by default */ + memset(dev->cmask + offset, 0xFF, size); +} + +/************************************************************************** + * pci express extended capability helper functions + */ + +/* ARI */ +void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn) +{ + pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER, + offset, PCI_ARI_SIZEOF); + pci_set_long(dev->config + offset + PCI_ARI_CAP, PCI_ARI_CAP_NFN(nextfn)); +} diff --git a/hw/pci/pcie.h b/hw/pci/pcie.h new file mode 100644 index 0000000..4889194 --- /dev/null +++ b/hw/pci/pcie.h @@ -0,0 +1,142 @@ +/* + * pcie.h + * + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_PCIE_H +#define QEMU_PCIE_H + +#include "hw.h" +#include "pci_regs.h" +#include "pcie_regs.h" +#include "pcie_aer.h" + +typedef enum { + /* for attention and power indicator */ + PCI_EXP_HP_IND_RESERVED = PCI_EXP_SLTCTL_IND_RESERVED, + PCI_EXP_HP_IND_ON = PCI_EXP_SLTCTL_IND_ON, + PCI_EXP_HP_IND_BLINK = PCI_EXP_SLTCTL_IND_BLINK, + PCI_EXP_HP_IND_OFF = PCI_EXP_SLTCTL_IND_OFF, +} PCIExpressIndicator; + +typedef enum { + /* these bits must match the bits in Slot Control/Status registers. + * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx + * + * Not all the bits of slot control register match with the ones of + * slot status. Not some bits of slot status register is used to + * show status, not to report event occurrence. + * So such bits must be masked out when checking the software + * notification condition. + */ + PCI_EXP_HP_EV_ABP = PCI_EXP_SLTCTL_ABPE, + /* attention button pressed */ + PCI_EXP_HP_EV_PDC = PCI_EXP_SLTCTL_PDCE, + /* presence detect changed */ + PCI_EXP_HP_EV_CCI = PCI_EXP_SLTCTL_CCIE, + /* command completed */ + + PCI_EXP_HP_EV_SUPPORTED = PCI_EXP_HP_EV_ABP | + PCI_EXP_HP_EV_PDC | + PCI_EXP_HP_EV_CCI, + /* supported event mask */ + + /* events not listed aren't supported */ +} PCIExpressHotPlugEvent; + +struct PCIExpressDevice { + /* Offset of express capability in config space */ + uint8_t exp_cap; + + /* SLOT */ + unsigned int hpev_intx; /* INTx for hot plug event (0-3:INT[A-D]#) + * default is 0 = INTA# + * If the chip wants to use other interrupt + * line, initialize this member with the + * desired number. + * If the chip dynamically changes this member, + * also initialize it when loaded as + * appropreately. + */ + bool hpev_notified; /* Logical AND of conditions for hot plug event. + Following 6.7.3.4: + Software Notification of Hot-Plug Events, an interrupt + is sent whenever the logical and of these conditions + transitions from false to true. */ + + /* AER */ + uint16_t aer_cap; + PCIEAERLog aer_log; + unsigned int aer_intx; /* INTx for error reporting + * default is 0 = INTA# + * If the chip wants to use other interrupt + * line, initialize this member with the + * desired number. + * If the chip dynamically changes this member, + * also initialize it when loaded as + * appropreately. + */ +}; + +/* PCI express capability helper functions */ +int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port); +void pcie_cap_exit(PCIDevice *dev); +uint8_t pcie_cap_get_type(const PCIDevice *dev); +void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector); +uint8_t pcie_cap_flags_get_vector(PCIDevice *dev); + +void pcie_cap_deverr_init(PCIDevice *dev); +void pcie_cap_deverr_reset(PCIDevice *dev); + +void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot); +void pcie_cap_slot_reset(PCIDevice *dev); +void pcie_cap_slot_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len); +int pcie_cap_slot_post_load(void *opaque, int version_id); +void pcie_cap_slot_push_attention_button(PCIDevice *dev); + +void pcie_cap_root_init(PCIDevice *dev); +void pcie_cap_root_reset(PCIDevice *dev); + +void pcie_cap_flr_init(PCIDevice *dev); +void pcie_cap_flr_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len); + +void pcie_cap_ari_init(PCIDevice *dev); +void pcie_cap_ari_reset(PCIDevice *dev); +bool pcie_cap_is_ari_enabled(const PCIDevice *dev); + +/* PCI express extended capability helper functions */ +uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id); +void pcie_add_capability(PCIDevice *dev, + uint16_t cap_id, uint8_t cap_ver, + uint16_t offset, uint16_t size); + +void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn); + +extern const VMStateDescription vmstate_pcie_device; + +#define VMSTATE_PCIE_DEVICE(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(PCIDevice), \ + .vmsd = &vmstate_pcie_device, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, PCIDevice), \ +} + +#endif /* QEMU_PCIE_H */ diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c new file mode 100644 index 0000000..b04c164 --- /dev/null +++ b/hw/pci/pcie_aer.c @@ -0,0 +1,1032 @@ +/* + * pcie_aer.c + * + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "sysemu.h" +#include "qemu-objects.h" +#include "monitor.h" +#include "pci_bridge.h" +#include "pcie.h" +#include "msix.h" +#include "msi.h" +#include "pci_internals.h" +#include "pcie_regs.h" + +//#define DEBUG_PCIE +#ifdef DEBUG_PCIE +# define PCIE_DPRINTF(fmt, ...) \ + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) +#else +# define PCIE_DPRINTF(fmt, ...) do {} while (0) +#endif +#define PCIE_DEV_PRINTF(dev, fmt, ...) \ + PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) + +#define PCI_ERR_SRC_COR_OFFS 0 +#define PCI_ERR_SRC_UNCOR_OFFS 2 + +/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */ +static uint32_t pcie_aer_uncor_default_severity(uint32_t status) +{ + switch (status) { + case PCI_ERR_UNC_INTN: + case PCI_ERR_UNC_DLP: + case PCI_ERR_UNC_SDN: + case PCI_ERR_UNC_RX_OVER: + case PCI_ERR_UNC_FCP: + case PCI_ERR_UNC_MALF_TLP: + return PCI_ERR_ROOT_CMD_FATAL_EN; + case PCI_ERR_UNC_POISON_TLP: + case PCI_ERR_UNC_ECRC: + case PCI_ERR_UNC_UNSUP: + case PCI_ERR_UNC_COMP_TIME: + case PCI_ERR_UNC_COMP_ABORT: + case PCI_ERR_UNC_UNX_COMP: + case PCI_ERR_UNC_ACSV: + case PCI_ERR_UNC_MCBTLP: + case PCI_ERR_UNC_ATOP_EBLOCKED: + case PCI_ERR_UNC_TLP_PRF_BLOCKED: + return PCI_ERR_ROOT_CMD_NONFATAL_EN; + default: + abort(); + break; + } + return PCI_ERR_ROOT_CMD_FATAL_EN; +} + +static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err) +{ + if (aer_log->log_num == aer_log->log_max) { + return -1; + } + memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err); + aer_log->log_num++; + return 0; +} + +static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err) +{ + assert(aer_log->log_num); + *err = aer_log->log[0]; + aer_log->log_num--; + memmove(&aer_log->log[0], &aer_log->log[1], + aer_log->log_num * sizeof *err); +} + +static void aer_log_clear_all_err(PCIEAERLog *aer_log) +{ + aer_log->log_num = 0; +} + +int pcie_aer_init(PCIDevice *dev, uint16_t offset) +{ + PCIExpressDevice *exp; + + pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER, + offset, PCI_ERR_SIZEOF); + exp = &dev->exp; + exp->aer_cap = offset; + + /* log_max is property */ + if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) { + dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT; + } + /* clip down the value to avoid unreasobale memory usage */ + if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) { + return -EINVAL; + } + dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] * + dev->exp.aer_log.log_max); + + pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS, + PCI_ERR_UNC_SUPPORTED); + + pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER, + PCI_ERR_UNC_SEVERITY_DEFAULT); + pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER, + PCI_ERR_UNC_SUPPORTED); + + pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS, + PCI_ERR_COR_STATUS); + + pci_set_long(dev->config + offset + PCI_ERR_COR_MASK, + PCI_ERR_COR_MASK_DEFAULT); + pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK, + PCI_ERR_COR_SUPPORTED); + + /* capabilities and control. multiple header logging is supported */ + if (dev->exp.aer_log.log_max > 0) { + pci_set_long(dev->config + offset + PCI_ERR_CAP, + PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC | + PCI_ERR_CAP_MHRC); + pci_set_long(dev->wmask + offset + PCI_ERR_CAP, + PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE | + PCI_ERR_CAP_MHRE); + } else { + pci_set_long(dev->config + offset + PCI_ERR_CAP, + PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC); + pci_set_long(dev->wmask + offset + PCI_ERR_CAP, + PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); + } + + switch (pcie_cap_get_type(dev)) { + case PCI_EXP_TYPE_ROOT_PORT: + /* this case will be set by pcie_aer_root_init() */ + /* fallthrough */ + case PCI_EXP_TYPE_DOWNSTREAM: + case PCI_EXP_TYPE_UPSTREAM: + pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL, + PCI_BRIDGE_CTL_SERR); + pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS, + PCI_SEC_STATUS_RCV_SYSTEM_ERROR); + break; + default: + /* nothing */ + break; + } + return 0; +} + +void pcie_aer_exit(PCIDevice *dev) +{ + g_free(dev->exp.aer_log.log); +} + +static void pcie_aer_update_uncor_status(PCIDevice *dev) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + PCIEAERLog *aer_log = &dev->exp.aer_log; + + uint16_t i; + for (i = 0; i < aer_log->log_num; i++) { + pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS, + dev->exp.aer_log.log[i].status); + } +} + +/* + * return value: + * true: error message needs to be sent up + * false: error message is masked + * + * 6.2.6 Error Message Control + * Figure 6-3 + * all pci express devices part + */ +static bool +pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg) +{ + if (!(pcie_aer_msg_is_uncor(msg) && + (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) { + return false; + } + + /* Signaled System Error + * + * 7.5.1.1 Command register + * Bit 8 SERR# Enable + * + * When Set, this bit enables reporting of Non-fatal and Fatal + * errors detected by the Function to the Root Complex. Note that + * errors are reported if enabled either through this bit or through + * the PCI Express specific bits in the Device Control register (see + * Section 7.8.4). + */ + pci_word_test_and_set_mask(dev->config + PCI_STATUS, + PCI_STATUS_SIG_SYSTEM_ERROR); + + if (!(msg->severity & + pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) { + return false; + } + + /* send up error message */ + return true; +} + +/* + * return value: + * true: error message is sent up + * false: error message is masked + * + * 6.2.6 Error Message Control + * Figure 6-3 + * virtual pci bridge part + */ +static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg) +{ + uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL); + + if (pcie_aer_msg_is_uncor(msg)) { + /* Received System Error */ + pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS, + PCI_SEC_STATUS_RCV_SYSTEM_ERROR); + } + + if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) { + return false; + } + return true; +} + +void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + assert(vector < PCI_ERR_ROOT_IRQ_MAX); + pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS, + PCI_ERR_ROOT_IRQ); + pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS, + vector << PCI_ERR_ROOT_IRQ_SHIFT); +} + +static unsigned int pcie_aer_root_get_vector(PCIDevice *dev) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); + return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT; +} + +/* Given a status register, get corresponding bits in the command register */ +static uint32_t pcie_aer_status_to_cmd(uint32_t status) +{ + uint32_t cmd = 0; + if (status & PCI_ERR_ROOT_COR_RCV) { + cmd |= PCI_ERR_ROOT_CMD_COR_EN; + } + if (status & PCI_ERR_ROOT_NONFATAL_RCV) { + cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN; + } + if (status & PCI_ERR_ROOT_FATAL_RCV) { + cmd |= PCI_ERR_ROOT_CMD_FATAL_EN; + } + return cmd; +} + +static void pcie_aer_root_notify(PCIDevice *dev) +{ + if (msix_enabled(dev)) { + msix_notify(dev, pcie_aer_root_get_vector(dev)); + } else if (msi_enabled(dev)) { + msi_notify(dev, pcie_aer_root_get_vector(dev)); + } else { + qemu_set_irq(dev->irq[dev->exp.aer_intx], 1); + } +} + +/* + * 6.2.6 Error Message Control + * Figure 6-3 + * root port part + */ +static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg) +{ + uint16_t cmd; + uint8_t *aer_cap; + uint32_t root_cmd; + uint32_t root_status, prev_status; + + cmd = pci_get_word(dev->config + PCI_COMMAND); + aer_cap = dev->config + dev->exp.aer_cap; + root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); + prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); + + if (cmd & PCI_COMMAND_SERR) { + /* System Error. + * + * The way to report System Error is platform specific and + * it isn't implemented in qemu right now. + * So just discard the error for now. + * OS which cares of aer would receive errors via + * native aer mechanims, so this wouldn't matter. + */ + } + + /* Errro Message Received: Root Error Status register */ + switch (msg->severity) { + case PCI_ERR_ROOT_CMD_COR_EN: + if (root_status & PCI_ERR_ROOT_COR_RCV) { + root_status |= PCI_ERR_ROOT_MULTI_COR_RCV; + } else { + pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SRC_COR_OFFS, + msg->source_id); + } + root_status |= PCI_ERR_ROOT_COR_RCV; + break; + case PCI_ERR_ROOT_CMD_NONFATAL_EN: + root_status |= PCI_ERR_ROOT_NONFATAL_RCV; + break; + case PCI_ERR_ROOT_CMD_FATAL_EN: + if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) { + root_status |= PCI_ERR_ROOT_FIRST_FATAL; + } + root_status |= PCI_ERR_ROOT_FATAL_RCV; + break; + default: + abort(); + break; + } + if (pcie_aer_msg_is_uncor(msg)) { + if (root_status & PCI_ERR_ROOT_UNCOR_RCV) { + root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV; + } else { + pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + + PCI_ERR_SRC_UNCOR_OFFS, msg->source_id); + } + root_status |= PCI_ERR_ROOT_UNCOR_RCV; + } + pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status); + + /* 6.2.4.1.2 Interrupt Generation */ + /* All the above did was set some bits in the status register. + * Specifically these that match message severity. + * The below code relies on this fact. */ + if (!(root_cmd & msg->severity) || + (pcie_aer_status_to_cmd(prev_status) & root_cmd)) { + /* Condition is not being set or was already true so nothing to do. */ + return; + } + + pcie_aer_root_notify(dev); +} + +/* + * 6.2.6 Error Message Control Figure 6-3 + * + * Walk up the bus tree from the device, propagate the error message. + */ +static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) +{ + uint8_t type; + + while (dev) { + if (!pci_is_express(dev)) { + /* just ignore it */ + /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR? + * Consider e.g. a PCI bridge above a PCI Express device. */ + return; + } + + type = pcie_cap_get_type(dev); + if ((type == PCI_EXP_TYPE_ROOT_PORT || + type == PCI_EXP_TYPE_UPSTREAM || + type == PCI_EXP_TYPE_DOWNSTREAM) && + !pcie_aer_msg_vbridge(dev, msg)) { + return; + } + if (!pcie_aer_msg_alldev(dev, msg)) { + return; + } + if (type == PCI_EXP_TYPE_ROOT_PORT) { + pcie_aer_msg_root_port(dev, msg); + /* Root port can notify system itself, + or send the error message to root complex event collector. */ + /* + * if root port is associated with an event collector, + * return the root complex event collector here. + * For now root complex event collector isn't supported. + */ + return; + } + dev = pci_bridge_get_device(dev->bus); + } +} + +static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + uint8_t first_bit = ffs(err->status) - 1; + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); + int i; + + assert(err->status); + assert(!(err->status & (err->status - 1))); + + errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); + errcap |= PCI_ERR_CAP_FEP(first_bit); + + if (err->flags & PCIE_AER_ERR_HEADER_VALID) { + for (i = 0; i < ARRAY_SIZE(err->header); ++i) { + /* 7.10.8 Header Log Register */ + uint8_t *header_log = + aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0]; + cpu_to_be32wu((uint32_t*)header_log, err->header[i]); + } + } else { + assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT)); + memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); + } + + if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) && + (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & + PCI_EXP_DEVCAP2_EETLPP)) { + for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) { + /* 7.10.12 tlp prefix log register */ + uint8_t *prefix_log = + aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0]; + cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]); + } + errcap |= PCI_ERR_CAP_TLP; + } else { + memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, + PCI_ERR_TLP_PREFIX_LOG_SIZE); + } + pci_set_long(aer_cap + PCI_ERR_CAP, errcap); +} + +static void pcie_aer_clear_log(PCIDevice *dev) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + + pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP, + PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); + + memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); + memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE); +} + +static void pcie_aer_clear_error(PCIDevice *dev) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); + PCIEAERLog *aer_log = &dev->exp.aer_log; + PCIEAERErr err; + + if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) { + pcie_aer_clear_log(dev); + return; + } + + /* + * If more errors are queued, set corresponding bits in uncorrectable + * error status. + * We emulate uncorrectable error status register as W1CS. + * So set bit in uncorrectable error status here again for multiple + * error recording support. + * + * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability) + */ + pcie_aer_update_uncor_status(dev); + + aer_log_del_err(aer_log, &err); + pcie_aer_update_log(dev, &err); +} + +static int pcie_aer_record_error(PCIDevice *dev, + const PCIEAERErr *err) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); + int fep = PCI_ERR_CAP_FEP(errcap); + + assert(err->status); + assert(!(err->status & (err->status - 1))); + + if (errcap & PCI_ERR_CAP_MHRE && + (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) { + /* Not first error. queue error */ + if (aer_log_add_err(&dev->exp.aer_log, err) < 0) { + /* overflow */ + return -1; + } + return 0; + } + + pcie_aer_update_log(dev, err); + return 0; +} + +typedef struct PCIEAERInject { + PCIDevice *dev; + uint8_t *aer_cap; + const PCIEAERErr *err; + uint16_t devctl; + uint16_t devsta; + uint32_t error_status; + bool unsupported_request; + bool log_overflow; + PCIEAERMsg msg; +} PCIEAERInject; + +static bool pcie_aer_inject_cor_error(PCIEAERInject *inj, + uint32_t uncor_status, + bool is_advisory_nonfatal) +{ + PCIDevice *dev = inj->dev; + + inj->devsta |= PCI_EXP_DEVSTA_CED; + if (inj->unsupported_request) { + inj->devsta |= PCI_EXP_DEVSTA_URD; + } + pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); + + if (inj->aer_cap) { + uint32_t mask; + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS, + inj->error_status); + mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK); + if (mask & inj->error_status) { + return false; + } + if (is_advisory_nonfatal) { + uint32_t uncor_mask = + pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); + if (!(uncor_mask & uncor_status)) { + inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); + } + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, + uncor_status); + } + } + + if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) { + return false; + } + if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) { + return false; + } + + inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN; + return true; +} + +static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal) +{ + PCIDevice *dev = inj->dev; + uint16_t cmd; + + if (is_fatal) { + inj->devsta |= PCI_EXP_DEVSTA_FED; + } else { + inj->devsta |= PCI_EXP_DEVSTA_NFED; + } + if (inj->unsupported_request) { + inj->devsta |= PCI_EXP_DEVSTA_URD; + } + pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); + + if (inj->aer_cap) { + uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); + if (mask & inj->error_status) { + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, + inj->error_status); + return false; + } + + inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, + inj->error_status); + } + + cmd = pci_get_word(dev->config + PCI_COMMAND); + if (inj->unsupported_request && + !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) { + return false; + } + if (is_fatal) { + if (!((cmd & PCI_COMMAND_SERR) || + (inj->devctl & PCI_EXP_DEVCTL_FERE))) { + return false; + } + inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN; + } else { + if (!((cmd & PCI_COMMAND_SERR) || + (inj->devctl & PCI_EXP_DEVCTL_NFERE))) { + return false; + } + inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN; + } + return true; +} + +/* + * non-Function specific error must be recorded in all functions. + * It is the responsibility of the caller of this function. + * It is also caller's responsibility to determine which function should + * report the rerror. + * + * 6.2.4 Error Logging + * 6.2.5 Sqeunce of Device Error Signaling and Logging Operations + * table 6-2: Flowchard Showing Sequence of Device Error Signaling and Logging + * Operations + */ +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err) +{ + uint8_t *aer_cap = NULL; + uint16_t devctl = 0; + uint16_t devsta = 0; + uint32_t error_status = err->status; + PCIEAERInject inj; + + if (!pci_is_express(dev)) { + return -ENOSYS; + } + + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { + error_status &= PCI_ERR_COR_SUPPORTED; + } else { + error_status &= PCI_ERR_UNC_SUPPORTED; + } + + /* invalid status bit. one and only one bit must be set */ + if (!error_status || (error_status & (error_status - 1))) { + return -EINVAL; + } + + if (dev->exp.aer_cap) { + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; + aer_cap = dev->config + dev->exp.aer_cap; + devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL); + devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA); + } + + inj.dev = dev; + inj.aer_cap = aer_cap; + inj.err = err; + inj.devctl = devctl; + inj.devsta = devsta; + inj.error_status = error_status; + inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) && + err->status == PCI_ERR_UNC_UNSUP; + inj.log_overflow = false; + + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { + if (!pcie_aer_inject_cor_error(&inj, 0, false)) { + return 0; + } + } else { + bool is_fatal = + pcie_aer_uncor_default_severity(error_status) == + PCI_ERR_ROOT_CMD_FATAL_EN; + if (aer_cap) { + is_fatal = + error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER); + } + if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) { + inj.error_status = PCI_ERR_COR_ADV_NONFATAL; + if (!pcie_aer_inject_cor_error(&inj, error_status, true)) { + return 0; + } + } else { + if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) { + return 0; + } + } + } + + /* send up error message */ + inj.msg.source_id = err->source_id; + pcie_aer_msg(dev, &inj.msg); + + if (inj.log_overflow) { + PCIEAERErr header_log_overflow = { + .status = PCI_ERR_COR_HL_OVERFLOW, + .flags = PCIE_AER_ERR_IS_CORRECTABLE, + }; + int ret = pcie_aer_inject_error(dev, &header_log_overflow); + assert(!ret); + } + return 0; +} + +void pcie_aer_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); + uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap); + uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS); + + /* uncorrectable error */ + if (!(uncorsta & first_error)) { + /* the bit that corresponds to the first error is cleared */ + pcie_aer_clear_error(dev); + } else if (errcap & PCI_ERR_CAP_MHRE) { + /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared + * nothing should happen. So we have to revert the modification to + * the register. + */ + pcie_aer_update_uncor_status(dev); + } else { + /* capability & control + * PCI_ERR_CAP_MHRE might be cleared, so clear of header log. + */ + aer_log_clear_all_err(&dev->exp.aer_log); + } +} + +void pcie_aer_root_init(PCIDevice *dev) +{ + uint16_t pos = dev->exp.aer_cap; + + pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND, + PCI_ERR_ROOT_CMD_EN_MASK); + pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS, + PCI_ERR_ROOT_STATUS_REPORT_MASK); + /* PCI_ERR_ROOT_IRQ is RO but devices change it using a + * device-specific method. + */ + pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS, + ~PCI_ERR_ROOT_IRQ); +} + +void pcie_aer_root_reset(PCIDevice *dev) +{ + uint8_t* aer_cap = dev->config + dev->exp.aer_cap; + + pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0); + + /* + * Advanced Error Interrupt Message Number in Root Error Status Register + * must be updated by chip dependent code because it's chip dependent + * which number is used. + */ +} + +void pcie_aer_root_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len, + uint32_t root_cmd_prev) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); + uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status); + uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); + /* 6.2.4.1.2 Interrupt Generation */ + if (!msix_enabled(dev) && !msi_enabled(dev)) { + qemu_set_irq(dev->irq[dev->exp.aer_intx], !!(root_cmd & enabled_cmd)); + return; + } + + if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) { + /* Send MSI on transition from false to true. */ + return; + } + + pcie_aer_root_notify(dev); +} + +static const VMStateDescription vmstate_pcie_aer_err = { + .name = "PCIE_AER_ERROR", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(status, PCIEAERErr), + VMSTATE_UINT16(source_id, PCIEAERErr), + VMSTATE_UINT16(flags, PCIEAERErr), + VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4), + VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4), + VMSTATE_END_OF_LIST() + } +}; + +const VMStateDescription vmstate_pcie_aer_log = { + .name = "PCIE_AER_ERROR_LOG", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT16(log_num, PCIEAERLog), + VMSTATE_UINT16(log_max, PCIEAERLog), + VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num, + vmstate_pcie_aer_err, PCIEAERErr), + VMSTATE_END_OF_LIST() + } +}; + +void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) +{ + QDict *qdict; + int devfn; + assert(qobject_type(data) == QTYPE_QDICT); + qdict = qobject_to_qdict(data); + + devfn = (int)qdict_get_int(qdict, "devfn"); + monitor_printf(mon, "OK id: %s domain: %x, bus: %x devfn: %x.%x\n", + qdict_get_str(qdict, "id"), + (int) qdict_get_int(qdict, "domain"), + (int) qdict_get_int(qdict, "bus"), + PCI_SLOT(devfn), PCI_FUNC(devfn)); +} + +typedef struct PCIEAERErrorName { + const char *name; + uint32_t val; + bool correctable; +} PCIEAERErrorName; + +/* + * AER error name -> value conversion table + * This naming scheme is same to linux aer-injection tool. + */ +static const struct PCIEAERErrorName pcie_aer_error_list[] = { + { + .name = "TRAIN", + .val = PCI_ERR_UNC_TRAIN, + .correctable = false, + }, { + .name = "DLP", + .val = PCI_ERR_UNC_DLP, + .correctable = false, + }, { + .name = "SDN", + .val = PCI_ERR_UNC_SDN, + .correctable = false, + }, { + .name = "POISON_TLP", + .val = PCI_ERR_UNC_POISON_TLP, + .correctable = false, + }, { + .name = "FCP", + .val = PCI_ERR_UNC_FCP, + .correctable = false, + }, { + .name = "COMP_TIME", + .val = PCI_ERR_UNC_COMP_TIME, + .correctable = false, + }, { + .name = "COMP_ABORT", + .val = PCI_ERR_UNC_COMP_ABORT, + .correctable = false, + }, { + .name = "UNX_COMP", + .val = PCI_ERR_UNC_UNX_COMP, + .correctable = false, + }, { + .name = "RX_OVER", + .val = PCI_ERR_UNC_RX_OVER, + .correctable = false, + }, { + .name = "MALF_TLP", + .val = PCI_ERR_UNC_MALF_TLP, + .correctable = false, + }, { + .name = "ECRC", + .val = PCI_ERR_UNC_ECRC, + .correctable = false, + }, { + .name = "UNSUP", + .val = PCI_ERR_UNC_UNSUP, + .correctable = false, + }, { + .name = "ACSV", + .val = PCI_ERR_UNC_ACSV, + .correctable = false, + }, { + .name = "INTN", + .val = PCI_ERR_UNC_INTN, + .correctable = false, + }, { + .name = "MCBTLP", + .val = PCI_ERR_UNC_MCBTLP, + .correctable = false, + }, { + .name = "ATOP_EBLOCKED", + .val = PCI_ERR_UNC_ATOP_EBLOCKED, + .correctable = false, + }, { + .name = "TLP_PRF_BLOCKED", + .val = PCI_ERR_UNC_TLP_PRF_BLOCKED, + .correctable = false, + }, { + .name = "RCVR", + .val = PCI_ERR_COR_RCVR, + .correctable = true, + }, { + .name = "BAD_TLP", + .val = PCI_ERR_COR_BAD_TLP, + .correctable = true, + }, { + .name = "BAD_DLLP", + .val = PCI_ERR_COR_BAD_DLLP, + .correctable = true, + }, { + .name = "REP_ROLL", + .val = PCI_ERR_COR_REP_ROLL, + .correctable = true, + }, { + .name = "REP_TIMER", + .val = PCI_ERR_COR_REP_TIMER, + .correctable = true, + }, { + .name = "ADV_NONFATAL", + .val = PCI_ERR_COR_ADV_NONFATAL, + .correctable = true, + }, { + .name = "INTERNAL", + .val = PCI_ERR_COR_INTERNAL, + .correctable = true, + }, { + .name = "HL_OVERFLOW", + .val = PCI_ERR_COR_HL_OVERFLOW, + .correctable = true, + }, +}; + +static int pcie_aer_parse_error_string(const char *error_name, + uint32_t *status, bool *correctable) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) { + const PCIEAERErrorName *e = &pcie_aer_error_list[i]; + if (strcmp(error_name, e->name)) { + continue; + } + + *status = e->val; + *correctable = e->correctable; + return 0; + } + return -EINVAL; +} + +int do_pcie_aer_inject_error(Monitor *mon, + const QDict *qdict, QObject **ret_data) +{ + const char *id = qdict_get_str(qdict, "id"); + const char *error_name; + uint32_t error_status; + bool correctable; + PCIDevice *dev; + PCIEAERErr err; + int ret; + + ret = pci_qdev_find_device(id, &dev); + if (ret < 0) { + monitor_printf(mon, + "id or pci device path is invalid or device not " + "found. %s\n", id); + return ret; + } + if (!pci_is_express(dev)) { + monitor_printf(mon, "the device doesn't support pci express. %s\n", + id); + return -ENOSYS; + } + + error_name = qdict_get_str(qdict, "error_status"); + if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) { + char *e = NULL; + error_status = strtoul(error_name, &e, 0); + correctable = qdict_get_try_bool(qdict, "correctable", 0); + if (!e || *e != '\0') { + monitor_printf(mon, "invalid error status value. \"%s\"", + error_name); + return -EINVAL; + } + } + err.status = error_status; + err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn; + + err.flags = 0; + if (correctable) { + err.flags |= PCIE_AER_ERR_IS_CORRECTABLE; + } + if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) { + err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY; + } + if (qdict_haskey(qdict, "header0")) { + err.flags |= PCIE_AER_ERR_HEADER_VALID; + } + if (qdict_haskey(qdict, "prefix0")) { + err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT; + } + + err.header[0] = qdict_get_try_int(qdict, "header0", 0); + err.header[1] = qdict_get_try_int(qdict, "header1", 0); + err.header[2] = qdict_get_try_int(qdict, "header2", 0); + err.header[3] = qdict_get_try_int(qdict, "header3", 0); + + err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0); + err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0); + err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0); + err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0); + + ret = pcie_aer_inject_error(dev, &err); + *ret_data = qobject_from_jsonf("{'id': %s, " + "'domain': %d, 'bus': %d, 'devfn': %d, " + "'ret': %d}", + id, + pci_find_domain(dev->bus), + pci_bus_num(dev->bus), dev->devfn, + ret); + assert(*ret_data); + + return 0; +} diff --git a/hw/pci/pcie_aer.h b/hw/pci/pcie_aer.h new file mode 100644 index 0000000..7539500 --- /dev/null +++ b/hw/pci/pcie_aer.h @@ -0,0 +1,106 @@ +/* + * pcie_aer.h + * + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_PCIE_AER_H +#define QEMU_PCIE_AER_H + +#include "hw.h" + +/* definitions which PCIExpressDevice uses */ + +/* AER log */ +struct PCIEAERLog { + /* This structure is saved/loaded. + So explicitly size them instead of unsigned int */ + + /* the number of currently recorded log in log member */ + uint16_t log_num; + + /* + * The maximum number of the log. Errors can be logged up to this. + * + * This is configurable property. + * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT + * to avoid unreasonable memory usage. + * I bet that 128 log size would be big enough, otherwise too many errors + * for system to function normaly. But could consecutive errors occur? + */ +#define PCIE_AER_LOG_MAX_DEFAULT 8 +#define PCIE_AER_LOG_MAX_LIMIT 128 +#define PCIE_AER_LOG_MAX_UNSET 0xffff + uint16_t log_max; + + /* Error log. log_max-sized array */ + PCIEAERErr *log; +}; + +/* aer error message: error signaling message has only error sevirity and + source id. See 2.2.8.3 error signaling messages */ +struct PCIEAERMsg { + /* + * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN + * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE} + */ + uint32_t severity; + + uint16_t source_id; /* bdf */ +}; + +static inline bool +pcie_aer_msg_is_uncor(const PCIEAERMsg *msg) +{ + return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN || + msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN; +} + +/* error */ +struct PCIEAERErr { + uint32_t status; /* error status bits */ + uint16_t source_id; /* bdf */ + +#define PCIE_AER_ERR_IS_CORRECTABLE 0x1 /* correctable/uncorrectable */ +#define PCIE_AER_ERR_MAYBE_ADVISORY 0x2 /* maybe advisory non-fatal */ +#define PCIE_AER_ERR_HEADER_VALID 0x4 /* TLP header is logged */ +#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8 /* TLP Prefix is logged */ + uint16_t flags; + + uint32_t header[4]; /* TLP header */ + uint32_t prefix[4]; /* TLP header prefix */ +}; + +extern const VMStateDescription vmstate_pcie_aer_log; + +int pcie_aer_init(PCIDevice *dev, uint16_t offset); +void pcie_aer_exit(PCIDevice *dev); +void pcie_aer_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len); + +/* aer root port */ +void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector); +void pcie_aer_root_init(PCIDevice *dev); +void pcie_aer_root_reset(PCIDevice *dev); +void pcie_aer_root_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len, + uint32_t root_cmd_prev); + +/* error injection */ +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err); + +#endif /* QEMU_PCIE_AER_H */ diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c new file mode 100644 index 0000000..c257fb4 --- /dev/null +++ b/hw/pci/pcie_host.c @@ -0,0 +1,161 @@ +/* + * pcie_host.c + * utility functions for pci express host bridge. + * + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw.h" +#include "pci.h" +#include "pcie_host.h" +#include "exec-memory.h" + +/* + * PCI express mmcfig address + * bit 20 - 28: bus number + * bit 15 - 19: device number + * bit 12 - 14: function number + * bit 0 - 11: offset in configuration space of a given device + */ +#define PCIE_MMCFG_SIZE_MAX (1ULL << 28) +#define PCIE_MMCFG_SIZE_MIN (1ULL << 20) +#define PCIE_MMCFG_BUS_BIT 20 +#define PCIE_MMCFG_BUS_MASK 0x1ff +#define PCIE_MMCFG_DEVFN_BIT 12 +#define PCIE_MMCFG_DEVFN_MASK 0xff +#define PCIE_MMCFG_CONFOFFSET_MASK 0xfff +#define PCIE_MMCFG_BUS(addr) (((addr) >> PCIE_MMCFG_BUS_BIT) & \ + PCIE_MMCFG_BUS_MASK) +#define PCIE_MMCFG_DEVFN(addr) (((addr) >> PCIE_MMCFG_DEVFN_BIT) & \ + PCIE_MMCFG_DEVFN_MASK) +#define PCIE_MMCFG_CONFOFFSET(addr) ((addr) & PCIE_MMCFG_CONFOFFSET_MASK) + + +/* a helper function to get a PCIDevice for a given mmconfig address */ +static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, + uint32_t mmcfg_addr) +{ + return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), + PCIE_MMCFG_DEVFN(mmcfg_addr)); +} + +static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr, + uint64_t val, unsigned len) +{ + PCIExpressHost *e = opaque; + PCIBus *s = e->pci.bus; + PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); + uint32_t addr; + uint32_t limit; + + if (!pci_dev) { + return; + } + addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); + limit = pci_config_size(pci_dev); + if (limit <= addr) { + /* conventional pci device can be behind pcie-to-pci bridge. + 256 <= addr < 4K has no effects. */ + return; + } + pci_host_config_write_common(pci_dev, addr, limit, val, len); +} + +static uint64_t pcie_mmcfg_data_read(void *opaque, + hwaddr mmcfg_addr, + unsigned len) +{ + PCIExpressHost *e = opaque; + PCIBus *s = e->pci.bus; + PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); + uint32_t addr; + uint32_t limit; + + if (!pci_dev) { + return ~0x0; + } + addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); + limit = pci_config_size(pci_dev); + if (limit <= addr) { + /* conventional pci device can be behind pcie-to-pci bridge. + 256 <= addr < 4K has no effects. */ + return ~0x0; + } + return pci_host_config_read_common(pci_dev, addr, limit, len); +} + +static const MemoryRegionOps pcie_mmcfg_ops = { + .read = pcie_mmcfg_data_read, + .write = pcie_mmcfg_data_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +/* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */ +#define PCIE_BASE_ADDR_UNMAPPED ((hwaddr)-1ULL) + +int pcie_host_init(PCIExpressHost *e) +{ + e->base_addr = PCIE_BASE_ADDR_UNMAPPED; + + return 0; +} + +void pcie_host_mmcfg_unmap(PCIExpressHost *e) +{ + if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { + memory_region_del_subregion(get_system_memory(), &e->mmio); + memory_region_destroy(&e->mmio); + e->base_addr = PCIE_BASE_ADDR_UNMAPPED; + } +} + +void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, + uint32_t size) +{ + assert(!(size & (size - 1))); /* power of 2 */ + assert(size >= PCIE_MMCFG_SIZE_MIN); + assert(size <= PCIE_MMCFG_SIZE_MAX); + e->size = size; + memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size); + e->base_addr = addr; + memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio); +} + +void pcie_host_mmcfg_update(PCIExpressHost *e, + int enable, + hwaddr addr, + uint32_t size) +{ + pcie_host_mmcfg_unmap(e); + if (enable) { + pcie_host_mmcfg_map(e, addr, size); + } +} + +static const TypeInfo pcie_host_type_info = { + .name = TYPE_PCIE_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, + .abstract = true, + .instance_size = sizeof(PCIExpressHost), +}; + +static void pcie_host_register_types(void) +{ + type_register_static(&pcie_host_type_info); +} + +type_init(pcie_host_register_types) diff --git a/hw/pci/pcie_host.h b/hw/pci/pcie_host.h new file mode 100644 index 0000000..3921935 --- /dev/null +++ b/hw/pci/pcie_host.h @@ -0,0 +1,54 @@ +/* + * pcie_host.h + * + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef PCIE_HOST_H +#define PCIE_HOST_H + +#include "pci_host.h" +#include "memory.h" + +#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge" +#define PCIE_HOST_BRIDGE(obj) \ + OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE) + +struct PCIExpressHost { + PCIHostState pci; + + /* express part */ + + /* base address where MMCONFIG area is mapped. */ + hwaddr base_addr; + + /* the size of MMCONFIG area. It's host bridge dependent */ + hwaddr size; + + /* MMCONFIG mmio area */ + MemoryRegion mmio; +}; + +int pcie_host_init(PCIExpressHost *e); +void pcie_host_mmcfg_unmap(PCIExpressHost *e); +void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size); +void pcie_host_mmcfg_update(PCIExpressHost *e, + int enable, + hwaddr addr, + uint32_t size); + +#endif /* PCIE_HOST_H */ diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c new file mode 100644 index 0000000..d6350e5 --- /dev/null +++ b/hw/pci/pcie_port.c @@ -0,0 +1,114 @@ +/* + * pcie_port.c + * + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "pcie_port.h" + +void pcie_port_init_reg(PCIDevice *d) +{ + /* Unlike pci bridge, + 66MHz and fast back to back don't apply to pci express port. */ + pci_set_word(d->config + PCI_STATUS, 0); + pci_set_word(d->config + PCI_SEC_STATUS, 0); + + /* Unlike conventional pci bridge, some bits are hardwired to 0. */ + pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, + PCI_BRIDGE_CTL_PARITY | + PCI_BRIDGE_CTL_ISA | + PCI_BRIDGE_CTL_VGA | + PCI_BRIDGE_CTL_SERR | + PCI_BRIDGE_CTL_BUS_RESET); +} + +/************************************************************************** + * (chassis number, pcie physical slot number) -> pcie slot conversion + */ +struct PCIEChassis { + uint8_t number; + + QLIST_HEAD(, PCIESlot) slots; + QLIST_ENTRY(PCIEChassis) next; +}; + +static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis); + +static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number) +{ + struct PCIEChassis *c; + QLIST_FOREACH(c, &chassis, next) { + if (c->number == chassis_number) { + break; + } + } + return c; +} + +void pcie_chassis_create(uint8_t chassis_number) +{ + struct PCIEChassis *c; + c = pcie_chassis_find(chassis_number); + if (c) { + return; + } + c = g_malloc0(sizeof(*c)); + c->number = chassis_number; + QLIST_INIT(&c->slots); + QLIST_INSERT_HEAD(&chassis, c, next); +} + +static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c, + uint8_t slot) +{ + PCIESlot *s; + QLIST_FOREACH(s, &c->slots, next) { + if (s->slot == slot) { + break; + } + } + return s; +} + +PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot) +{ + struct PCIEChassis *c; + c = pcie_chassis_find(chassis_number); + if (!c) { + return NULL; + } + return pcie_chassis_find_slot_with_chassis(c, slot); +} + +int pcie_chassis_add_slot(struct PCIESlot *slot) +{ + struct PCIEChassis *c; + c = pcie_chassis_find(slot->chassis); + if (!c) { + return -ENODEV; + } + if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) { + return -EBUSY; + } + QLIST_INSERT_HEAD(&c->slots, slot, next); + return 0; +} + +void pcie_chassis_del_slot(PCIESlot *s) +{ + QLIST_REMOVE(s, next); +} diff --git a/hw/pci/pcie_port.h b/hw/pci/pcie_port.h new file mode 100644 index 0000000..3709583 --- /dev/null +++ b/hw/pci/pcie_port.h @@ -0,0 +1,51 @@ +/* + * pcie_port.h + * + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_PCIE_PORT_H +#define QEMU_PCIE_PORT_H + +#include "pci_bridge.h" +#include "pci_internals.h" + +struct PCIEPort { + PCIBridge br; + + /* pci express switch port */ + uint8_t port; +}; + +void pcie_port_init_reg(PCIDevice *d); + +struct PCIESlot { + PCIEPort port; + + /* pci express switch port with slot */ + uint8_t chassis; + uint16_t slot; + QLIST_ENTRY(PCIESlot) next; +}; + +void pcie_chassis_create(uint8_t chassis_number); +void pcie_main_chassis_create(void); +PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot); +int pcie_chassis_add_slot(struct PCIESlot *slot); +void pcie_chassis_del_slot(PCIESlot *s); + +#endif /* QEMU_PCIE_PORT_H */ diff --git a/hw/pci/pcie_regs.h b/hw/pci/pcie_regs.h new file mode 100644 index 0000000..4d123d9 --- /dev/null +++ b/hw/pci/pcie_regs.h @@ -0,0 +1,156 @@ +/* + * constants for pcie configurations space from pci express spec. + * + * TODO: + * Those constants and macros should go to Linux pci_regs.h + * Once they're merged, they will go away. + */ +#ifndef QEMU_PCIE_REGS_H +#define QEMU_PCIE_REGS_H + + +/* express capability */ + +#define PCI_EXP_VER2_SIZEOF 0x3c /* express capability of ver. 2 */ +#define PCI_EXT_CAP_VER_SHIFT 16 +#define PCI_EXT_CAP_NEXT_SHIFT 20 +#define PCI_EXT_CAP_NEXT_MASK (0xffc << PCI_EXT_CAP_NEXT_SHIFT) + +#define PCI_EXT_CAP(id, ver, next) \ + ((id) | \ + ((ver) << PCI_EXT_CAP_VER_SHIFT) | \ + ((next) << PCI_EXT_CAP_NEXT_SHIFT)) + +#define PCI_EXT_CAP_ALIGN 4 +#define PCI_EXT_CAP_ALIGNUP(x) \ + (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1)) + +/* PCI_EXP_FLAGS */ +#define PCI_EXP_FLAGS_VER2 2 /* for now, supports only ver. 2 */ +#define PCI_EXP_FLAGS_IRQ_SHIFT (ffs(PCI_EXP_FLAGS_IRQ) - 1) +#define PCI_EXP_FLAGS_TYPE_SHIFT (ffs(PCI_EXP_FLAGS_TYPE) - 1) + + +/* PCI_EXP_LINK{CAP, STA} */ +/* link speed */ +#define PCI_EXP_LNK_LS_25 1 + +#define PCI_EXP_LNK_MLW_SHIFT (ffs(PCI_EXP_LNKCAP_MLW) - 1) +#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT) + +/* PCI_EXP_LINKCAP */ +#define PCI_EXP_LNKCAP_ASPMS_SHIFT (ffs(PCI_EXP_LNKCAP_ASPMS) - 1) +#define PCI_EXP_LNKCAP_ASPMS_0S (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT) + +#define PCI_EXP_LNKCAP_PN_SHIFT (ffs(PCI_EXP_LNKCAP_PN) - 1) + +#define PCI_EXP_SLTCAP_PSN_SHIFT (ffs(PCI_EXP_SLTCAP_PSN) - 1) + +#define PCI_EXP_SLTCTL_IND_RESERVED 0x0 +#define PCI_EXP_SLTCTL_IND_ON 0x1 +#define PCI_EXP_SLTCTL_IND_BLINK 0x2 +#define PCI_EXP_SLTCTL_IND_OFF 0x3 +#define PCI_EXP_SLTCTL_AIC_SHIFT (ffs(PCI_EXP_SLTCTL_AIC) - 1) +#define PCI_EXP_SLTCTL_AIC_OFF \ + (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT) + +#define PCI_EXP_SLTCTL_PIC_SHIFT (ffs(PCI_EXP_SLTCTL_PIC) - 1) +#define PCI_EXP_SLTCTL_PIC_OFF \ + (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT) + +#define PCI_EXP_SLTCTL_SUPPORTED \ + (PCI_EXP_SLTCTL_ABPE | \ + PCI_EXP_SLTCTL_PDCE | \ + PCI_EXP_SLTCTL_CCIE | \ + PCI_EXP_SLTCTL_HPIE | \ + PCI_EXP_SLTCTL_AIC | \ + PCI_EXP_SLTCTL_PCC | \ + PCI_EXP_SLTCTL_EIC) + +#define PCI_EXP_DEVCAP2_EFF 0x100000 +#define PCI_EXP_DEVCAP2_EETLPP 0x200000 + +#define PCI_EXP_DEVCTL2_EETLPPB 0x80 + +/* ARI */ +#define PCI_ARI_VER 1 +#define PCI_ARI_SIZEOF 8 + +/* AER */ +#define PCI_ERR_VER 2 +#define PCI_ERR_SIZEOF 0x48 + +#define PCI_ERR_UNC_SDN 0x00000020 /* surprise down */ +#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */ +#define PCI_ERR_UNC_INTN 0x00400000 /* Internal Error */ +#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC Blcoked TLP */ +#define PCI_ERR_UNC_ATOP_EBLOCKED 0x01000000 /* atomic op egress blocked */ +#define PCI_ERR_UNC_TLP_PRF_BLOCKED 0x02000000 /* TLP Prefix Blocked */ +#define PCI_ERR_COR_ADV_NONFATAL 0x00002000 /* Advisory Non-Fatal */ +#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected Internal */ +#define PCI_ERR_COR_HL_OVERFLOW 0x00008000 /* Header Long Overflow */ +#define PCI_ERR_CAP_FEP_MASK 0x0000001f +#define PCI_ERR_CAP_MHRC 0x00000200 +#define PCI_ERR_CAP_MHRE 0x00000400 +#define PCI_ERR_CAP_TLP 0x00000800 + +#define PCI_ERR_HEADER_LOG_SIZE 16 +#define PCI_ERR_TLP_PREFIX_LOG 0x38 +#define PCI_ERR_TLP_PREFIX_LOG_SIZE 16 + +#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR 0x4000 + +/* aer root error command/status */ +#define PCI_ERR_ROOT_CMD_EN_MASK (PCI_ERR_ROOT_CMD_COR_EN | \ + PCI_ERR_ROOT_CMD_NONFATAL_EN | \ + PCI_ERR_ROOT_CMD_FATAL_EN) + +#define PCI_ERR_ROOT_IRQ_MAX 32 +#define PCI_ERR_ROOT_IRQ 0xf8000000 +#define PCI_ERR_ROOT_IRQ_SHIFT (ffs(PCI_ERR_ROOT_IRQ) - 1) +#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV | \ + PCI_ERR_ROOT_MULTI_COR_RCV | \ + PCI_ERR_ROOT_UNCOR_RCV | \ + PCI_ERR_ROOT_MULTI_UNCOR_RCV | \ + PCI_ERR_ROOT_FIRST_FATAL | \ + PCI_ERR_ROOT_NONFATAL_RCV | \ + PCI_ERR_ROOT_FATAL_RCV) + +#define PCI_ERR_UNC_SUPPORTED (PCI_ERR_UNC_DLP | \ + PCI_ERR_UNC_SDN | \ + PCI_ERR_UNC_POISON_TLP | \ + PCI_ERR_UNC_FCP | \ + PCI_ERR_UNC_COMP_TIME | \ + PCI_ERR_UNC_COMP_ABORT | \ + PCI_ERR_UNC_UNX_COMP | \ + PCI_ERR_UNC_RX_OVER | \ + PCI_ERR_UNC_MALF_TLP | \ + PCI_ERR_UNC_ECRC | \ + PCI_ERR_UNC_UNSUP | \ + PCI_ERR_UNC_ACSV | \ + PCI_ERR_UNC_INTN | \ + PCI_ERR_UNC_MCBTLP | \ + PCI_ERR_UNC_ATOP_EBLOCKED | \ + PCI_ERR_UNC_TLP_PRF_BLOCKED) + +#define PCI_ERR_UNC_SEVERITY_DEFAULT (PCI_ERR_UNC_DLP | \ + PCI_ERR_UNC_SDN | \ + PCI_ERR_UNC_FCP | \ + PCI_ERR_UNC_RX_OVER | \ + PCI_ERR_UNC_MALF_TLP | \ + PCI_ERR_UNC_INTN) + +#define PCI_ERR_COR_SUPPORTED (PCI_ERR_COR_RCVR | \ + PCI_ERR_COR_BAD_TLP | \ + PCI_ERR_COR_BAD_DLLP | \ + PCI_ERR_COR_REP_ROLL | \ + PCI_ERR_COR_REP_TIMER | \ + PCI_ERR_COR_ADV_NONFATAL | \ + PCI_ERR_COR_INTERNAL | \ + PCI_ERR_COR_HL_OVERFLOW) + +#define PCI_ERR_COR_MASK_DEFAULT (PCI_ERR_COR_ADV_NONFATAL | \ + PCI_ERR_COR_INTERNAL | \ + PCI_ERR_COR_HL_OVERFLOW) + +#endif /* QEMU_PCIE_REGS_H */ diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c new file mode 100644 index 0000000..4597bbd --- /dev/null +++ b/hw/pci/shpc.c @@ -0,0 +1,681 @@ +#include <strings.h> +#include <stdint.h> +#include "range.h" +#include "range.h" +#include "shpc.h" +#include "pci.h" +#include "pci_internals.h" +#include "msi.h" + +/* TODO: model power only and disabled slot states. */ +/* TODO: handle SERR and wakeups */ +/* TODO: consider enabling 66MHz support */ + +/* TODO: remove fully only on state DISABLED and LED off. + * track state to properly record this. */ + +/* SHPC Working Register Set */ +#define SHPC_BASE_OFFSET 0x00 /* 4 bytes */ +#define SHPC_SLOTS_33 0x04 /* 4 bytes. Also encodes PCI-X slots. */ +#define SHPC_SLOTS_66 0x08 /* 4 bytes. */ +#define SHPC_NSLOTS 0x0C /* 1 byte */ +#define SHPC_FIRST_DEV 0x0D /* 1 byte */ +#define SHPC_PHYS_SLOT 0x0E /* 2 byte */ +#define SHPC_PHYS_NUM_MAX 0x7ff +#define SHPC_PHYS_NUM_UP 0x2000 +#define SHPC_PHYS_MRL 0x4000 +#define SHPC_PHYS_BUTTON 0x8000 +#define SHPC_SEC_BUS 0x10 /* 2 bytes */ +#define SHPC_SEC_BUS_33 0x0 +#define SHPC_SEC_BUS_66 0x1 /* Unused */ +#define SHPC_SEC_BUS_MASK 0x7 +#define SHPC_MSI_CTL 0x12 /* 1 byte */ +#define SHPC_PROG_IFC 0x13 /* 1 byte */ +#define SHPC_PROG_IFC_1_0 0x1 +#define SHPC_CMD_CODE 0x14 /* 1 byte */ +#define SHPC_CMD_TRGT 0x15 /* 1 byte */ +#define SHPC_CMD_TRGT_MIN 0x1 +#define SHPC_CMD_TRGT_MAX 0x1f +#define SHPC_CMD_STATUS 0x16 /* 2 bytes */ +#define SHPC_CMD_STATUS_BUSY 0x1 +#define SHPC_CMD_STATUS_MRL_OPEN 0x2 +#define SHPC_CMD_STATUS_INVALID_CMD 0x4 +#define SHPC_CMD_STATUS_INVALID_MODE 0x8 +#define SHPC_INT_LOCATOR 0x18 /* 4 bytes */ +#define SHPC_INT_COMMAND 0x1 +#define SHPC_SERR_LOCATOR 0x1C /* 4 bytes */ +#define SHPC_SERR_INT 0x20 /* 4 bytes */ +#define SHPC_INT_DIS 0x1 +#define SHPC_SERR_DIS 0x2 +#define SHPC_CMD_INT_DIS 0x4 +#define SHPC_ARB_SERR_DIS 0x8 +#define SHPC_CMD_DETECTED 0x10000 +#define SHPC_ARB_DETECTED 0x20000 + /* 4 bytes * slot # (start from 0) */ +#define SHPC_SLOT_REG(s) (0x24 + (s) * 4) + /* 2 bytes */ +#define SHPC_SLOT_STATUS(s) (0x0 + SHPC_SLOT_REG(s)) + +/* Same slot state masks are used for command and status registers */ +#define SHPC_SLOT_STATE_MASK 0x03 +#define SHPC_SLOT_STATE_SHIFT \ + (ffs(SHPC_SLOT_STATE_MASK) - 1) + +#define SHPC_STATE_NO 0x0 +#define SHPC_STATE_PWRONLY 0x1 +#define SHPC_STATE_ENABLED 0x2 +#define SHPC_STATE_DISABLED 0x3 + +#define SHPC_SLOT_PWR_LED_MASK 0xC +#define SHPC_SLOT_PWR_LED_SHIFT \ + (ffs(SHPC_SLOT_PWR_LED_MASK) - 1) +#define SHPC_SLOT_ATTN_LED_MASK 0x30 +#define SHPC_SLOT_ATTN_LED_SHIFT \ + (ffs(SHPC_SLOT_ATTN_LED_MASK) - 1) + +#define SHPC_LED_NO 0x0 +#define SHPC_LED_ON 0x1 +#define SHPC_LED_BLINK 0x2 +#define SHPC_LED_OFF 0x3 + +#define SHPC_SLOT_STATUS_PWR_FAULT 0x40 +#define SHPC_SLOT_STATUS_BUTTON 0x80 +#define SHPC_SLOT_STATUS_MRL_OPEN 0x100 +#define SHPC_SLOT_STATUS_66 0x200 +#define SHPC_SLOT_STATUS_PRSNT_MASK 0xC00 +#define SHPC_SLOT_STATUS_PRSNT_EMPTY 0x3 +#define SHPC_SLOT_STATUS_PRSNT_25W 0x1 +#define SHPC_SLOT_STATUS_PRSNT_15W 0x2 +#define SHPC_SLOT_STATUS_PRSNT_7_5W 0x0 + +#define SHPC_SLOT_STATUS_PRSNT_PCIX 0x3000 + + + /* 1 byte */ +#define SHPC_SLOT_EVENT_LATCH(s) (0x2 + SHPC_SLOT_REG(s)) + /* 1 byte */ +#define SHPC_SLOT_EVENT_SERR_INT_DIS(d, s) (0x3 + SHPC_SLOT_REG(s)) +#define SHPC_SLOT_EVENT_PRESENCE 0x01 +#define SHPC_SLOT_EVENT_ISOLATED_FAULT 0x02 +#define SHPC_SLOT_EVENT_BUTTON 0x04 +#define SHPC_SLOT_EVENT_MRL 0x08 +#define SHPC_SLOT_EVENT_CONNECTED_FAULT 0x10 +/* Bits below are used for Serr/Int disable only */ +#define SHPC_SLOT_EVENT_MRL_SERR_DIS 0x20 +#define SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS 0x40 + +#define SHPC_MIN_SLOTS 1 +#define SHPC_MAX_SLOTS 31 +#define SHPC_SIZEOF(d) SHPC_SLOT_REG((d)->shpc->nslots) + +/* SHPC Slot identifiers */ + +/* Hotplug supported at 31 slots out of the total 32. We reserve slot 0, + and give the rest of them physical *and* pci numbers starting from 1, so + they match logical numbers. Note: this means that multiple slots must have + different chassis number values, to make chassis+physical slot unique. + TODO: make this configurable? */ +#define SHPC_IDX_TO_LOGICAL(slot) ((slot) + 1) +#define SHPC_LOGICAL_TO_IDX(target) ((target) - 1) +#define SHPC_IDX_TO_PCI(slot) ((slot) + 1) +#define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1) +#define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1) + +static int roundup_pow_of_two(int x) +{ + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return x + 1; +} + +static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk) +{ + uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); + return (pci_get_word(status) & msk) >> (ffs(msk) - 1); +} + +static void shpc_set_status(SHPCDevice *shpc, + int slot, uint8_t value, uint16_t msk) +{ + uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); + pci_word_test_and_clear_mask(status, msk); + pci_word_test_and_set_mask(status, value << (ffs(msk) - 1)); +} + +static void shpc_interrupt_update(PCIDevice *d) +{ + SHPCDevice *shpc = d->shpc; + int slot; + int level = 0; + uint32_t serr_int; + uint32_t int_locator = 0; + + /* Update interrupt locator register */ + for (slot = 0; slot < shpc->nslots; ++slot) { + uint8_t event = shpc->config[SHPC_SLOT_EVENT_LATCH(slot)]; + uint8_t disable = shpc->config[SHPC_SLOT_EVENT_SERR_INT_DIS(d, slot)]; + uint32_t mask = 1 << SHPC_IDX_TO_LOGICAL(slot); + if (event & ~disable) { + int_locator |= mask; + } + } + serr_int = pci_get_long(shpc->config + SHPC_SERR_INT); + if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_DIS)) { + int_locator |= SHPC_INT_COMMAND; + } + pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator); + level = (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0; + if (msi_enabled(d) && shpc->msi_requested != level) + msi_notify(d, 0); + else + qemu_set_irq(d->irq[0], level); + shpc->msi_requested = level; +} + +static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed) +{ + switch (speed) { + case SHPC_SEC_BUS_33: + shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK; + shpc->config[SHPC_SEC_BUS] |= speed; + break; + default: + pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, + SHPC_CMD_STATUS_INVALID_MODE); + } +} + +void shpc_reset(PCIDevice *d) +{ + SHPCDevice *shpc = d->shpc; + int nslots = shpc->nslots; + int i; + memset(shpc->config, 0, SHPC_SIZEOF(d)); + pci_set_byte(shpc->config + SHPC_NSLOTS, nslots); + pci_set_long(shpc->config + SHPC_SLOTS_33, nslots); + pci_set_long(shpc->config + SHPC_SLOTS_66, 0); + pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0)); + pci_set_word(shpc->config + SHPC_PHYS_SLOT, + SHPC_IDX_TO_PHYSICAL(0) | + SHPC_PHYS_NUM_UP | + SHPC_PHYS_MRL | + SHPC_PHYS_BUTTON); + pci_set_long(shpc->config + SHPC_SERR_INT, SHPC_INT_DIS | + SHPC_SERR_DIS | + SHPC_CMD_INT_DIS | + SHPC_ARB_SERR_DIS); + pci_set_byte(shpc->config + SHPC_PROG_IFC, SHPC_PROG_IFC_1_0); + pci_set_word(shpc->config + SHPC_SEC_BUS, SHPC_SEC_BUS_33); + for (i = 0; i < shpc->nslots; ++i) { + pci_set_byte(shpc->config + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), + SHPC_SLOT_EVENT_PRESENCE | + SHPC_SLOT_EVENT_ISOLATED_FAULT | + SHPC_SLOT_EVENT_BUTTON | + SHPC_SLOT_EVENT_MRL | + SHPC_SLOT_EVENT_CONNECTED_FAULT | + SHPC_SLOT_EVENT_MRL_SERR_DIS | + SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); + if (shpc->sec_bus->devices[PCI_DEVFN(SHPC_IDX_TO_PCI(i), 0)]) { + shpc_set_status(shpc, i, SHPC_STATE_ENABLED, SHPC_SLOT_STATE_MASK); + shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_MRL_OPEN); + shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_7_5W, + SHPC_SLOT_STATUS_PRSNT_MASK); + shpc_set_status(shpc, i, SHPC_LED_ON, SHPC_SLOT_PWR_LED_MASK); + } else { + shpc_set_status(shpc, i, SHPC_STATE_DISABLED, SHPC_SLOT_STATE_MASK); + shpc_set_status(shpc, i, 1, SHPC_SLOT_STATUS_MRL_OPEN); + shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_EMPTY, + SHPC_SLOT_STATUS_PRSNT_MASK); + shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK); + } + shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66); + } + shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33); + shpc->msi_requested = 0; + shpc_interrupt_update(d); +} + +static void shpc_invalid_command(SHPCDevice *shpc) +{ + pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, + SHPC_CMD_STATUS_INVALID_CMD); +} + +static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot) +{ + int devfn; + int pci_slot = SHPC_IDX_TO_PCI(slot); + for (devfn = PCI_DEVFN(pci_slot, 0); + devfn <= PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1); + ++devfn) { + PCIDevice *affected_dev = shpc->sec_bus->devices[devfn]; + if (affected_dev) { + qdev_free(&affected_dev->qdev); + } + } +} + +static void shpc_slot_command(SHPCDevice *shpc, uint8_t target, + uint8_t state, uint8_t power, uint8_t attn) +{ + uint8_t current_state; + int slot = SHPC_LOGICAL_TO_IDX(target); + if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) { + shpc_invalid_command(shpc); + return; + } + current_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); + if (current_state == SHPC_STATE_ENABLED && state == SHPC_STATE_PWRONLY) { + shpc_invalid_command(shpc); + return; + } + + switch (power) { + case SHPC_LED_NO: + break; + default: + /* TODO: send event to monitor */ + shpc_set_status(shpc, slot, power, SHPC_SLOT_PWR_LED_MASK); + } + switch (attn) { + case SHPC_LED_NO: + break; + default: + /* TODO: send event to monitor */ + shpc_set_status(shpc, slot, attn, SHPC_SLOT_ATTN_LED_MASK); + } + + if ((current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_PWRONLY) || + (current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_ENABLED)) { + shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); + } else if ((current_state == SHPC_STATE_ENABLED || + current_state == SHPC_STATE_PWRONLY) && + state == SHPC_STATE_DISABLED) { + shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); + power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); + /* TODO: track what monitor requested. */ + /* Look at LED to figure out whether it's ok to remove the device. */ + if (power == SHPC_LED_OFF) { + shpc_free_devices_in_slot(shpc, slot); + shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, + SHPC_SLOT_STATUS_PRSNT_MASK); + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= + SHPC_SLOT_EVENT_BUTTON | + SHPC_SLOT_EVENT_MRL | + SHPC_SLOT_EVENT_PRESENCE; + } + } +} + +static void shpc_command(SHPCDevice *shpc) +{ + uint8_t code = pci_get_byte(shpc->config + SHPC_CMD_CODE); + uint8_t speed; + uint8_t target; + uint8_t attn; + uint8_t power; + uint8_t state; + int i; + + /* Clear status from the previous command. */ + pci_word_test_and_clear_mask(shpc->config + SHPC_CMD_STATUS, + SHPC_CMD_STATUS_BUSY | + SHPC_CMD_STATUS_MRL_OPEN | + SHPC_CMD_STATUS_INVALID_CMD | + SHPC_CMD_STATUS_INVALID_MODE); + switch (code) { + case 0x00 ... 0x3f: + target = shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX; + state = (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_SHIFT; + power = (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_LED_SHIFT; + attn = (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_LED_SHIFT; + shpc_slot_command(shpc, target, state, power, attn); + break; + case 0x40 ... 0x47: + speed = code & SHPC_SEC_BUS_MASK; + shpc_set_sec_bus_speed(shpc, speed); + break; + case 0x48: + /* Power only all slots */ + /* first verify no slots are enabled */ + for (i = 0; i < shpc->nslots; ++i) { + state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); + if (state == SHPC_STATE_ENABLED) { + shpc_invalid_command(shpc); + goto done; + } + } + for (i = 0; i < shpc->nslots; ++i) { + if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, + SHPC_STATE_PWRONLY, SHPC_LED_ON, SHPC_LED_NO); + } else { + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, + SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); + } + } + break; + case 0x49: + /* Enable all slots */ + /* TODO: Spec says this shall fail if some are already enabled. + * This doesn't make sense - why not? a spec bug? */ + for (i = 0; i < shpc->nslots; ++i) { + state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); + if (state == SHPC_STATE_ENABLED) { + shpc_invalid_command(shpc); + goto done; + } + } + for (i = 0; i < shpc->nslots; ++i) { + if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, + SHPC_STATE_ENABLED, SHPC_LED_ON, SHPC_LED_NO); + } else { + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, + SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); + } + } + break; + default: + shpc_invalid_command(shpc); + break; + } +done: + pci_long_test_and_set_mask(shpc->config + SHPC_SERR_INT, SHPC_CMD_DETECTED); +} + +static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, int l) +{ + SHPCDevice *shpc = d->shpc; + int i; + if (addr >= SHPC_SIZEOF(d)) { + return; + } + l = MIN(l, SHPC_SIZEOF(d) - addr); + + /* TODO: code duplicated from pci.c */ + for (i = 0; i < l; val >>= 8, ++i) { + unsigned a = addr + i; + uint8_t wmask = shpc->wmask[a]; + uint8_t w1cmask = shpc->w1cmask[a]; + assert(!(wmask & w1cmask)); + shpc->config[a] = (shpc->config[a] & ~wmask) | (val & wmask); + shpc->config[a] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ + } + if (ranges_overlap(addr, l, SHPC_CMD_CODE, 2)) { + shpc_command(shpc); + } + shpc_interrupt_update(d); +} + +static uint64_t shpc_read(PCIDevice *d, unsigned addr, int l) +{ + uint64_t val = 0x0; + if (addr >= SHPC_SIZEOF(d)) { + return val; + } + l = MIN(l, SHPC_SIZEOF(d) - addr); + memcpy(&val, d->shpc->config + addr, l); + return val; +} + +/* SHPC Bridge Capability */ +#define SHPC_CAP_LENGTH 0x08 +#define SHPC_CAP_DWORD_SELECT 0x2 /* 1 byte */ +#define SHPC_CAP_CxP 0x3 /* 1 byte: CSP, CIP */ +#define SHPC_CAP_DWORD_DATA 0x4 /* 4 bytes */ +#define SHPC_CAP_CSP_MASK 0x4 +#define SHPC_CAP_CIP_MASK 0x8 + +static uint8_t shpc_cap_dword(PCIDevice *d) +{ + return pci_get_byte(d->config + d->shpc->cap + SHPC_CAP_DWORD_SELECT); +} + +/* Update dword data capability register */ +static void shpc_cap_update_dword(PCIDevice *d) +{ + unsigned data; + data = shpc_read(d, shpc_cap_dword(d) * 4, 4); + pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, data); +} + +/* Add SHPC capability to the config space for the device. */ +static int shpc_cap_add_config(PCIDevice *d) +{ + uint8_t *config; + int config_offset; + config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC, + 0, SHPC_CAP_LENGTH); + if (config_offset < 0) { + return config_offset; + } + config = d->config + config_offset; + + pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0); + pci_set_byte(config + SHPC_CAP_CxP, 0); + pci_set_long(config + SHPC_CAP_DWORD_DATA, 0); + d->shpc->cap = config_offset; + /* Make dword select and data writeable. */ + pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff); + pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff); + return 0; +} + +static uint64_t shpc_mmio_read(void *opaque, hwaddr addr, + unsigned size) +{ + return shpc_read(opaque, addr, size); +} + +static void shpc_mmio_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + shpc_write(opaque, addr, val, size); +} + +static const MemoryRegionOps shpc_mmio_ops = { + .read = shpc_mmio_read, + .write = shpc_mmio_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + /* SHPC ECN requires dword accesses, but the original 1.0 spec doesn't. + * It's easier to suppport all sizes than worry about it. */ + .min_access_size = 1, + .max_access_size = 4, + }, +}; + +static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev, + PCIHotplugState hotplug_state) +{ + int pci_slot = PCI_SLOT(affected_dev->devfn); + uint8_t state; + uint8_t led; + PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); + SHPCDevice *shpc = d->shpc; + int slot = SHPC_PCI_TO_IDX(pci_slot); + if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) { + error_report("Unsupported PCI slot %d for standard hotplug " + "controller. Valid slots are between %d and %d.", + pci_slot, SHPC_IDX_TO_PCI(0), + SHPC_IDX_TO_PCI(shpc->nslots) - 1); + return -1; + } + /* Don't send event when device is enabled during qemu machine creation: + * it is present on boot, no hotplug event is necessary. We do send an + * event when the device is disabled later. */ + if (hotplug_state == PCI_COLDPLUG_ENABLED) { + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, + SHPC_SLOT_STATUS_PRSNT_MASK); + return 0; + } + if (hotplug_state == PCI_HOTPLUG_DISABLED) { + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON; + state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); + led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); + if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) { + shpc_free_devices_in_slot(shpc, slot); + shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, + SHPC_SLOT_STATUS_PRSNT_MASK); + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= + SHPC_SLOT_EVENT_MRL | + SHPC_SLOT_EVENT_PRESENCE; + } + } else { + /* This could be a cancellation of the previous removal. + * We check MRL state to figure out. */ + if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) { + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, + SHPC_SLOT_STATUS_PRSNT_MASK); + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= + SHPC_SLOT_EVENT_BUTTON | + SHPC_SLOT_EVENT_MRL | + SHPC_SLOT_EVENT_PRESENCE; + } else { + /* Press attention button to cancel removal */ + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= + SHPC_SLOT_EVENT_BUTTON; + } + } + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66); + shpc_interrupt_update(d); + return 0; +} + +/* Initialize the SHPC structure in bridge's BAR. */ +int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset) +{ + int i, ret; + int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */ + SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc)); + shpc->sec_bus = sec_bus; + ret = shpc_cap_add_config(d); + if (ret) { + g_free(d->shpc); + return ret; + } + if (nslots < SHPC_MIN_SLOTS) { + return 0; + } + if (nslots > SHPC_MAX_SLOTS || + SHPC_IDX_TO_PCI(nslots) > PCI_SLOT_MAX) { + /* TODO: report an error mesage that makes sense. */ + return -EINVAL; + } + shpc->nslots = nslots; + shpc->config = g_malloc0(SHPC_SIZEOF(d)); + shpc->cmask = g_malloc0(SHPC_SIZEOF(d)); + shpc->wmask = g_malloc0(SHPC_SIZEOF(d)); + shpc->w1cmask = g_malloc0(SHPC_SIZEOF(d)); + + shpc_reset(d); + + pci_set_long(shpc->config + SHPC_BASE_OFFSET, offset); + + pci_set_byte(shpc->wmask + SHPC_CMD_CODE, 0xff); + pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); + pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); + pci_set_long(shpc->wmask + SHPC_SERR_INT, + SHPC_INT_DIS | + SHPC_SERR_DIS | + SHPC_CMD_INT_DIS | + SHPC_ARB_SERR_DIS); + pci_set_long(shpc->w1cmask + SHPC_SERR_INT, + SHPC_CMD_DETECTED | + SHPC_ARB_DETECTED); + for (i = 0; i < nslots; ++i) { + pci_set_byte(shpc->wmask + + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), + SHPC_SLOT_EVENT_PRESENCE | + SHPC_SLOT_EVENT_ISOLATED_FAULT | + SHPC_SLOT_EVENT_BUTTON | + SHPC_SLOT_EVENT_MRL | + SHPC_SLOT_EVENT_CONNECTED_FAULT | + SHPC_SLOT_EVENT_MRL_SERR_DIS | + SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); + pci_set_byte(shpc->w1cmask + + SHPC_SLOT_EVENT_LATCH(i), + SHPC_SLOT_EVENT_PRESENCE | + SHPC_SLOT_EVENT_ISOLATED_FAULT | + SHPC_SLOT_EVENT_BUTTON | + SHPC_SLOT_EVENT_MRL | + SHPC_SLOT_EVENT_CONNECTED_FAULT); + } + + /* TODO: init cmask */ + memory_region_init_io(&shpc->mmio, &shpc_mmio_ops, d, "shpc-mmio", + SHPC_SIZEOF(d)); + shpc_cap_update_dword(d); + memory_region_add_subregion(bar, offset, &shpc->mmio); + pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev); + + d->cap_present |= QEMU_PCI_CAP_SHPC; + return 0; +} + +int shpc_bar_size(PCIDevice *d) +{ + return roundup_pow_of_two(SHPC_SLOT_REG(SHPC_MAX_SLOTS)); +} + +void shpc_cleanup(PCIDevice *d, MemoryRegion *bar) +{ + SHPCDevice *shpc = d->shpc; + d->cap_present &= ~QEMU_PCI_CAP_SHPC; + memory_region_del_subregion(bar, &shpc->mmio); + /* TODO: cleanup config space changes? */ + g_free(shpc->config); + g_free(shpc->cmask); + g_free(shpc->wmask); + g_free(shpc->w1cmask); + memory_region_destroy(&shpc->mmio); + g_free(shpc); +} + +void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) +{ + if (!ranges_overlap(addr, l, d->shpc->cap, SHPC_CAP_LENGTH)) { + return; + } + if (ranges_overlap(addr, l, d->shpc->cap + SHPC_CAP_DWORD_DATA, 4)) { + unsigned dword_data; + dword_data = pci_get_long(d->shpc->config + d->shpc->cap + + SHPC_CAP_DWORD_DATA); + shpc_write(d, shpc_cap_dword(d) * 4, dword_data, 4); + } + /* Update cap dword data in case guest is going to read it. */ + shpc_cap_update_dword(d); +} + +static void shpc_save(QEMUFile *f, void *pv, size_t size) +{ + PCIDevice *d = container_of(pv, PCIDevice, shpc); + qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); +} + +static int shpc_load(QEMUFile *f, void *pv, size_t size) +{ + PCIDevice *d = container_of(pv, PCIDevice, shpc); + int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); + if (ret != SHPC_SIZEOF(d)) { + return -EINVAL; + } + /* Make sure we don't lose notifications. An extra interrupt is harmless. */ + d->shpc->msi_requested = 0; + shpc_interrupt_update(d); + return 0; +} + +VMStateInfo shpc_vmstate_info = { + .name = "shpc", + .get = shpc_load, + .put = shpc_save, +}; diff --git a/hw/pci/shpc.h b/hw/pci/shpc.h new file mode 100644 index 0000000..130b71d --- /dev/null +++ b/hw/pci/shpc.h @@ -0,0 +1,48 @@ +#ifndef SHPC_H +#define SHPC_H + +#include "qemu-common.h" +#include "memory.h" +#include "vmstate.h" + +struct SHPCDevice { + /* Capability offset in device's config space */ + int cap; + + /* # of hot-pluggable slots */ + int nslots; + + /* SHPC WRS: working register set */ + uint8_t *config; + + /* Used to enable checks on load. Note that writable bits are + * never checked even if set in cmask. */ + uint8_t *cmask; + + /* Used to implement R/W bytes */ + uint8_t *wmask; + + /* Used to implement RW1C(Write 1 to Clear) bytes */ + uint8_t *w1cmask; + + /* MMIO for the SHPC BAR */ + MemoryRegion mmio; + + /* Bus controlled by this SHPC */ + PCIBus *sec_bus; + + /* MSI already requested for this event */ + int msi_requested; +}; + +void shpc_reset(PCIDevice *d); +int shpc_bar_size(PCIDevice *dev); +int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off); +void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar); +void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len); + +extern VMStateInfo shpc_vmstate_info; +#define SHPC_VMSTATE(_field, _type) \ + VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0) + +#endif diff --git a/hw/pci/slotid_cap.c b/hw/pci/slotid_cap.c new file mode 100644 index 0000000..0106452 --- /dev/null +++ b/hw/pci/slotid_cap.c @@ -0,0 +1,44 @@ +#include "slotid_cap.h" +#include "pci.h" + +#define SLOTID_CAP_LENGTH 4 +#define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1) + +int slotid_cap_init(PCIDevice *d, int nslots, + uint8_t chassis, + unsigned offset) +{ + int cap; + if (!chassis) { + error_report("Bridge chassis not specified. Each bridge is required " + "to be assigned a unique chassis id > 0."); + return -EINVAL; + } + if (nslots < 0 || nslots > (PCI_SID_ESR_NSLOTS >> SLOTID_NSLOTS_SHIFT)) { + /* TODO: error report? */ + return -EINVAL; + } + + cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset, SLOTID_CAP_LENGTH); + if (cap < 0) { + return cap; + } + /* We make each chassis unique, this way each bridge is First in Chassis */ + d->config[cap + PCI_SID_ESR] = PCI_SID_ESR_FIC | + (nslots << SLOTID_NSLOTS_SHIFT); + d->cmask[cap + PCI_SID_ESR] = 0xff; + d->config[cap + PCI_SID_CHASSIS_NR] = chassis; + /* Note: Chassis number register is non-volatile, + so we don't reset it. */ + /* TODO: store in eeprom? */ + d->wmask[cap + PCI_SID_CHASSIS_NR] = 0xff; + + d->cap_present |= QEMU_PCI_CAP_SLOTID; + return 0; +} + +void slotid_cap_cleanup(PCIDevice *d) +{ + /* TODO: cleanup config space? */ + d->cap_present &= ~QEMU_PCI_CAP_SLOTID; +} diff --git a/hw/pci/slotid_cap.h b/hw/pci/slotid_cap.h new file mode 100644 index 0000000..70db047 --- /dev/null +++ b/hw/pci/slotid_cap.h @@ -0,0 +1,11 @@ +#ifndef PCI_SLOTID_CAP_H +#define PCI_SLOTID_CAP_H + +#include "qemu-common.h" + +int slotid_cap_init(PCIDevice *dev, int nslots, + uint8_t chassis, + unsigned offset); +void slotid_cap_cleanup(PCIDevice *dev); + +#endif diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c deleted file mode 100644 index 4680501..0000000 --- a/hw/pci_bridge.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * QEMU PCI bus manager - * - * Copyright (c) 2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to dea - - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM - - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -/* - * split out from pci.c - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - */ - -#include "pci_bridge.h" -#include "pci_internals.h" -#include "range.h" - -/* PCI bridge subsystem vendor ID helper functions */ -#define PCI_SSVID_SIZEOF 8 -#define PCI_SSVID_SVID 4 -#define PCI_SSVID_SSID 6 - -int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, - uint16_t svid, uint16_t ssid) -{ - int pos; - pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF); - if (pos < 0) { - return pos; - } - - pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid); - pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid); - return pos; -} - -/* Accessor function to get parent bridge device from pci bus. */ -PCIDevice *pci_bridge_get_device(PCIBus *bus) -{ - return bus->parent_dev; -} - -/* Accessor function to get secondary bus from pci-to-pci bridge device */ -PCIBus *pci_bridge_get_sec_bus(PCIBridge *br) -{ - return &br->sec_bus; -} - -static uint32_t pci_config_get_io_base(const PCIDevice *d, - uint32_t base, uint32_t base_upper16) -{ - uint32_t val; - - val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8; - if (d->config[base] & PCI_IO_RANGE_TYPE_32) { - val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16; - } - return val; -} - -static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base) -{ - return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) - << 16; -} - -static pcibus_t pci_config_get_pref_base(const PCIDevice *d, - uint32_t base, uint32_t upper) -{ - pcibus_t tmp; - pcibus_t val; - - tmp = (pcibus_t)pci_get_word(d->config + base); - val = (tmp & PCI_PREF_RANGE_MASK) << 16; - if (tmp & PCI_PREF_RANGE_TYPE_64) { - val |= (pcibus_t)pci_get_long(d->config + upper) << 32; - } - return val; -} - -/* accessor function to get bridge filtering base address */ -pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type) -{ - pcibus_t base; - if (type & PCI_BASE_ADDRESS_SPACE_IO) { - base = pci_config_get_io_base(bridge, - PCI_IO_BASE, PCI_IO_BASE_UPPER16); - } else { - if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { - base = pci_config_get_pref_base( - bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32); - } else { - base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE); - } - } - - return base; -} - -/* accessor funciton to get bridge filtering limit */ -pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type) -{ - pcibus_t limit; - if (type & PCI_BASE_ADDRESS_SPACE_IO) { - limit = pci_config_get_io_base(bridge, - PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16); - limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */ - } else { - if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { - limit = pci_config_get_pref_base( - bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32); - } else { - limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT); - } - limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */ - } - return limit; -} - -static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, - uint8_t type, const char *name, - MemoryRegion *space, - MemoryRegion *parent_space, - bool enabled) -{ - pcibus_t base = pci_bridge_get_base(&bridge->dev, type); - pcibus_t limit = pci_bridge_get_limit(&bridge->dev, type); - /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly. - * Apparently no way to do this with existing memory APIs. */ - pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0; - - memory_region_init_alias(alias, name, space, base, size); - memory_region_add_subregion_overlap(parent_space, base, alias, 1); -} - -static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) -{ - PCIBus *parent = br->dev.bus; - PCIBridgeWindows *w = g_new(PCIBridgeWindows, 1); - uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND); - - pci_bridge_init_alias(br, &w->alias_pref_mem, - PCI_BASE_ADDRESS_MEM_PREFETCH, - "pci_bridge_pref_mem", - &br->address_space_mem, - parent->address_space_mem, - cmd & PCI_COMMAND_MEMORY); - pci_bridge_init_alias(br, &w->alias_mem, - PCI_BASE_ADDRESS_SPACE_MEMORY, - "pci_bridge_mem", - &br->address_space_mem, - parent->address_space_mem, - cmd & PCI_COMMAND_MEMORY); - pci_bridge_init_alias(br, &w->alias_io, - PCI_BASE_ADDRESS_SPACE_IO, - "pci_bridge_io", - &br->address_space_io, - parent->address_space_io, - cmd & PCI_COMMAND_IO); - /* TODO: optinal VGA and VGA palette snooping support. */ - - return w; -} - -static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w) -{ - PCIBus *parent = br->dev.bus; - - memory_region_del_subregion(parent->address_space_io, &w->alias_io); - memory_region_del_subregion(parent->address_space_mem, &w->alias_mem); - memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem); -} - -static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w) -{ - memory_region_destroy(&w->alias_io); - memory_region_destroy(&w->alias_mem); - memory_region_destroy(&w->alias_pref_mem); - g_free(w); -} - -static void pci_bridge_update_mappings(PCIBridge *br) -{ - PCIBridgeWindows *w = br->windows; - - /* Make updates atomic to: handle the case of one VCPU updating the bridge - * while another accesses an unaffected region. */ - memory_region_transaction_begin(); - pci_bridge_region_del(br, br->windows); - br->windows = pci_bridge_region_init(br); - memory_region_transaction_commit(); - pci_bridge_region_cleanup(br, w); -} - -/* default write_config function for PCI-to-PCI bridge */ -void pci_bridge_write_config(PCIDevice *d, - uint32_t address, uint32_t val, int len) -{ - PCIBridge *s = container_of(d, PCIBridge, dev); - uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); - uint16_t newctl; - - pci_default_write_config(d, address, val, len); - - if (ranges_overlap(address, len, PCI_COMMAND, 2) || - - /* io base/limit */ - ranges_overlap(address, len, PCI_IO_BASE, 2) || - - /* memory base/limit, prefetchable base/limit and - io base/limit upper 16 */ - ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { - pci_bridge_update_mappings(s); - } - - newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); - if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) { - /* Trigger hot reset on 0->1 transition. */ - pci_bus_reset(&s->sec_bus); - } -} - -void pci_bridge_disable_base_limit(PCIDevice *dev) -{ - uint8_t *conf = dev->config; - - pci_byte_test_and_set_mask(conf + PCI_IO_BASE, - PCI_IO_RANGE_MASK & 0xff); - pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, - PCI_IO_RANGE_MASK & 0xff); - pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE, - PCI_MEMORY_RANGE_MASK & 0xffff); - pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, - PCI_MEMORY_RANGE_MASK & 0xffff); - pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE, - PCI_PREF_RANGE_MASK & 0xffff); - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, - PCI_PREF_RANGE_MASK & 0xffff); - pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); - pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); -} - -/* reset bridge specific configuration registers */ -void pci_bridge_reset(DeviceState *qdev) -{ - PCIDevice *dev = PCI_DEVICE(qdev); - uint8_t *conf = dev->config; - - conf[PCI_PRIMARY_BUS] = 0; - conf[PCI_SECONDARY_BUS] = 0; - conf[PCI_SUBORDINATE_BUS] = 0; - conf[PCI_SEC_LATENCY_TIMER] = 0; - - /* - * the default values for base/limit registers aren't specified - * in the PCI-to-PCI-bridge spec. So we don't thouch them here. - * Each implementation can override it. - * typical implementation does - * zero base/limit registers or - * disable forwarding: pci_bridge_disable_base_limit() - * If disable forwarding is wanted, call pci_bridge_disable_base_limit() - * after this function. - */ - pci_byte_test_and_clear_mask(conf + PCI_IO_BASE, - PCI_IO_RANGE_MASK & 0xff); - pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, - PCI_IO_RANGE_MASK & 0xff); - pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE, - PCI_MEMORY_RANGE_MASK & 0xffff); - pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, - PCI_MEMORY_RANGE_MASK & 0xffff); - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE, - PCI_PREF_RANGE_MASK & 0xffff); - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, - PCI_PREF_RANGE_MASK & 0xffff); - pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); - pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); - - pci_set_word(conf + PCI_BRIDGE_CONTROL, 0); -} - -/* default qdev initialization function for PCI-to-PCI bridge */ -int pci_bridge_initfn(PCIDevice *dev) -{ - PCIBus *parent = dev->bus; - PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); - PCIBus *sec_bus = &br->sec_bus; - - pci_word_test_and_set_mask(dev->config + PCI_STATUS, - PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); - pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI); - dev->config[PCI_HEADER_TYPE] = - (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) | - PCI_HEADER_TYPE_BRIDGE; - pci_set_word(dev->config + PCI_SEC_STATUS, - PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); - - /* - * If we don't specify the name, the bus will be addressed as <id>.0, where - * id is the device id. - * Since PCI Bridge devices have a single bus each, we don't need the index: - * let users address the bus using the device name. - */ - if (!br->bus_name && dev->qdev.id && *dev->qdev.id) { - br->bus_name = dev->qdev.id; - } - - qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev, - br->bus_name); - sec_bus->parent_dev = dev; - sec_bus->map_irq = br->map_irq; - sec_bus->address_space_mem = &br->address_space_mem; - memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX); - sec_bus->address_space_io = &br->address_space_io; - memory_region_init(&br->address_space_io, "pci_bridge_io", 65536); - br->windows = pci_bridge_region_init(br); - QLIST_INIT(&sec_bus->child); - QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); - return 0; -} - -/* default qdev clean up function for PCI-to-PCI bridge */ -void pci_bridge_exitfn(PCIDevice *pci_dev) -{ - PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); - assert(QLIST_EMPTY(&s->sec_bus.child)); - QLIST_REMOVE(&s->sec_bus, sibling); - pci_bridge_region_del(s, s->windows); - pci_bridge_region_cleanup(s, s->windows); - memory_region_destroy(&s->address_space_mem); - memory_region_destroy(&s->address_space_io); - /* qbus_free() is called automatically by qdev_free() */ -} - -/* - * before qdev initialization(qdev_init()), this function sets bus_name and - * map_irq callback which are necessry for pci_bridge_initfn() to - * initialize bus. - */ -void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, - pci_map_irq_fn map_irq) -{ - br->map_irq = map_irq; - br->bus_name = bus_name; -} diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h deleted file mode 100644 index a00accc..0000000 --- a/hw/pci_bridge.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * QEMU PCI bridge - * - * Copyright (c) 2004 Fabrice Bellard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc] - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - */ - -#ifndef QEMU_PCI_BRIDGE_H -#define QEMU_PCI_BRIDGE_H - -#include "pci.h" - -int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, - uint16_t svid, uint16_t ssid); - -PCIDevice *pci_bridge_get_device(PCIBus *bus); -PCIBus *pci_bridge_get_sec_bus(PCIBridge *br); - -pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type); -pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type); - -void pci_bridge_write_config(PCIDevice *d, - uint32_t address, uint32_t val, int len); -void pci_bridge_disable_base_limit(PCIDevice *dev); -void pci_bridge_reset_reg(PCIDevice *dev); -void pci_bridge_reset(DeviceState *qdev); - -int pci_bridge_initfn(PCIDevice *pci_dev); -void pci_bridge_exitfn(PCIDevice *pci_dev); - - -/* - * before qdev initialization(qdev_init()), this function sets bus_name and - * map_irq callback which are necessry for pci_bridge_initfn() to - * initialize bus. - */ -void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, - pci_map_irq_fn map_irq); - -#endif /* QEMU_PCI_BRIDGE_H */ -/* - * Local variables: - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 8 - * indent-tab-mode: nil - * End: - */ diff --git a/hw/pci_host.c b/hw/pci_host.c deleted file mode 100644 index 68e328c..0000000 --- a/hw/pci_host.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * pci_host.c - * - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "pci.h" -#include "pci_host.h" - -/* debug PCI */ -//#define DEBUG_PCI - -#ifdef DEBUG_PCI -#define PCI_DPRINTF(fmt, ...) \ -do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0) -#else -#define PCI_DPRINTF(fmt, ...) -#endif - -/* - * PCI address - * bit 16 - 24: bus number - * bit 8 - 15: devfun number - * bit 0 - 7: offset in configuration space of a given pci device - */ - -/* the helper functio to get a PCIDeice* for a given pci address */ -static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr) -{ - uint8_t bus_num = addr >> 16; - uint8_t devfn = addr >> 8; - - return pci_find_device(bus, bus_num, devfn); -} - -void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, - uint32_t limit, uint32_t val, uint32_t len) -{ - assert(len <= 4); - pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr)); -} - -uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, - uint32_t limit, uint32_t len) -{ - assert(len <= 4); - return pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr)); -} - -void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len) -{ - PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); - uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); - - if (!pci_dev) { - return; - } - - PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n", - __func__, pci_dev->name, config_addr, val, len); - pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE, - val, len); -} - -uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) -{ - PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); - uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); - uint32_t val; - - if (!pci_dev) { - return ~0x0; - } - - val = pci_host_config_read_common(pci_dev, config_addr, - PCI_CONFIG_SPACE_SIZE, len); - PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n", - __func__, pci_dev->name, config_addr, val, len); - - return val; -} - -static void pci_host_config_write(void *opaque, hwaddr addr, - uint64_t val, unsigned len) -{ - PCIHostState *s = opaque; - - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", - __func__, addr, len, val); - if (addr != 0 || len != 4) { - return; - } - s->config_reg = val; -} - -static uint64_t pci_host_config_read(void *opaque, hwaddr addr, - unsigned len) -{ - PCIHostState *s = opaque; - uint32_t val = s->config_reg; - - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n", - __func__, addr, len, val); - return val; -} - -static void pci_host_data_write(void *opaque, hwaddr addr, - uint64_t val, unsigned len) -{ - PCIHostState *s = opaque; - PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n", - addr, len, (unsigned)val); - if (s->config_reg & (1u << 31)) - pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); -} - -static uint64_t pci_host_data_read(void *opaque, - hwaddr addr, unsigned len) -{ - PCIHostState *s = opaque; - uint32_t val; - if (!(s->config_reg & (1 << 31))) - return 0xffffffff; - val = pci_data_read(s->bus, s->config_reg | (addr & 3), len); - PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n", - addr, len, val); - return val; -} - -const MemoryRegionOps pci_host_conf_le_ops = { - .read = pci_host_config_read, - .write = pci_host_config_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -const MemoryRegionOps pci_host_conf_be_ops = { - .read = pci_host_config_read, - .write = pci_host_config_write, - .endianness = DEVICE_BIG_ENDIAN, -}; - -const MemoryRegionOps pci_host_data_le_ops = { - .read = pci_host_data_read, - .write = pci_host_data_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -const MemoryRegionOps pci_host_data_be_ops = { - .read = pci_host_data_read, - .write = pci_host_data_write, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static const TypeInfo pci_host_type_info = { - .name = TYPE_PCI_HOST_BRIDGE, - .parent = TYPE_SYS_BUS_DEVICE, - .abstract = true, - .instance_size = sizeof(PCIHostState), -}; - -static void pci_host_register_types(void) -{ - type_register_static(&pci_host_type_info); -} - -type_init(pci_host_register_types) diff --git a/hw/pci_host.h b/hw/pci_host.h deleted file mode 100644 index 4b9c300..0000000 --- a/hw/pci_host.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * QEMU Common PCI Host bridge configuration data space access routines. - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* Worker routines for a PCI host controller that uses an {address,data} - register pair to access PCI configuration space. */ - -#ifndef PCI_HOST_H -#define PCI_HOST_H - -#include "sysbus.h" - -#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge" -#define PCI_HOST_BRIDGE(obj) \ - OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE) - -struct PCIHostState { - SysBusDevice busdev; - - MemoryRegion conf_mem; - MemoryRegion data_mem; - MemoryRegion mmcfg; - MemoryRegion *address_space; - uint32_t config_reg; - PCIBus *bus; -}; - -/* common internal helpers for PCI/PCIe hosts, cut off overflows */ -void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, - uint32_t limit, uint32_t val, uint32_t len); -uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, - uint32_t limit, uint32_t len); - -void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len); -uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len); - -extern const MemoryRegionOps pci_host_conf_le_ops; -extern const MemoryRegionOps pci_host_conf_be_ops; -extern const MemoryRegionOps pci_host_data_le_ops; -extern const MemoryRegionOps pci_host_data_be_ops; - -#endif /* PCI_HOST_H */ diff --git a/hw/pci_ids.h b/hw/pci_ids.h deleted file mode 100644 index 5df7245..0000000 --- a/hw/pci_ids.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * PCI Class, Vendor and Device IDs - * - * Please keep sorted. - * - * Abbreviated version of linux/pci_ids.h - * - * QEMU-specific definitions belong in pci.h - */ - -/* Device classes and subclasses */ - -#define PCI_BASE_CLASS_STORAGE 0x01 -#define PCI_BASE_CLASS_NETWORK 0x02 - -#define PCI_CLASS_STORAGE_SCSI 0x0100 -#define PCI_CLASS_STORAGE_IDE 0x0101 -#define PCI_CLASS_STORAGE_RAID 0x0104 -#define PCI_CLASS_STORAGE_SATA 0x0106 -#define PCI_CLASS_STORAGE_OTHER 0x0180 - -#define PCI_CLASS_NETWORK_ETHERNET 0x0200 - -#define PCI_CLASS_DISPLAY_VGA 0x0300 -#define PCI_CLASS_DISPLAY_OTHER 0x0380 - -#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 - -#define PCI_CLASS_MEMORY_RAM 0x0500 - -#define PCI_CLASS_SYSTEM_OTHER 0x0880 - -#define PCI_CLASS_SERIAL_USB 0x0c03 -#define PCI_CLASS_SERIAL_SMBUS 0x0c05 - -#define PCI_CLASS_BRIDGE_HOST 0x0600 -#define PCI_CLASS_BRIDGE_ISA 0x0601 -#define PCI_CLASS_BRIDGE_PCI 0x0604 -#define PCI_CLASS_BRDIGE_PCI_INF_SUB 0x01 -#define PCI_CLASS_BRIDGE_OTHER 0x0680 - -#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 -#define PCI_CLASS_COMMUNICATION_OTHER 0x0780 - -#define PCI_CLASS_PROCESSOR_CO 0x0b40 -#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20 - -#define PCI_CLASS_OTHERS 0xff - -/* Vendors and devices. Sort key: vendor first, device next. */ - -#define PCI_VENDOR_ID_LSI_LOGIC 0x1000 -#define PCI_DEVICE_ID_LSI_53C895A 0x0012 -#define PCI_DEVICE_ID_LSI_SAS1078 0x0060 - -#define PCI_VENDOR_ID_DEC 0x1011 -#define PCI_DEVICE_ID_DEC_21154 0x0026 - -#define PCI_VENDOR_ID_CIRRUS 0x1013 - -#define PCI_VENDOR_ID_IBM 0x1014 - -#define PCI_VENDOR_ID_AMD 0x1022 -#define PCI_DEVICE_ID_AMD_LANCE 0x2000 -#define PCI_DEVICE_ID_AMD_SCSI 0x2020 - -#define PCI_VENDOR_ID_TI 0x104c - -#define PCI_VENDOR_ID_MOTOROLA 0x1057 -#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 -#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 - -#define PCI_VENDOR_ID_APPLE 0x106b -#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 -#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b - -#define PCI_VENDOR_ID_SUN 0x108e -#define PCI_DEVICE_ID_SUN_EBUS 0x1000 -#define PCI_DEVICE_ID_SUN_SIMBA 0x5000 -#define PCI_DEVICE_ID_SUN_SABRE 0xa000 - -#define PCI_VENDOR_ID_CMD 0x1095 -#define PCI_DEVICE_ID_CMD_646 0x0646 - -#define PCI_VENDOR_ID_REALTEK 0x10ec -#define PCI_DEVICE_ID_REALTEK_8139 0x8139 - -#define PCI_VENDOR_ID_XILINX 0x10ee - -#define PCI_VENDOR_ID_VIA 0x1106 -#define PCI_DEVICE_ID_VIA_ISA_BRIDGE 0x0686 -#define PCI_DEVICE_ID_VIA_IDE 0x0571 -#define PCI_DEVICE_ID_VIA_UHCI 0x3038 -#define PCI_DEVICE_ID_VIA_ACPI 0x3057 -#define PCI_DEVICE_ID_VIA_AC97 0x3058 -#define PCI_DEVICE_ID_VIA_MC97 0x3068 - -#define PCI_VENDOR_ID_MARVELL 0x11ab - -#define PCI_VENDOR_ID_ENSONIQ 0x1274 -#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 - -#define PCI_VENDOR_ID_FREESCALE 0x1957 -#define PCI_DEVICE_ID_MPC8533E 0x0030 - -#define PCI_VENDOR_ID_INTEL 0x8086 -#define PCI_DEVICE_ID_INTEL_82378 0x0484 -#define PCI_DEVICE_ID_INTEL_82441 0x1237 -#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 -#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e -#define PCI_DEVICE_ID_INTEL_82801D 0x24CD -#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab -#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 -#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 -#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 -#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 -#define PCI_DEVICE_ID_INTEL_82371AB 0x7111 -#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 -#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 - -#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 -#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 -#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 -#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 -#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 -#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 -#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 -#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 -#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 - -#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934 -#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935 -#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936 -#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937 -#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938 -#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939 -#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a -#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c -#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed - -#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 - -#define PCI_VENDOR_ID_XEN 0x5853 -#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 - -#define PCI_VENDOR_ID_NEC 0x1033 -#define PCI_DEVICE_ID_NEC_UPD720200 0x0194 diff --git a/hw/pci_internals.h b/hw/pci_internals.h deleted file mode 100644 index 21d0ce6..0000000 --- a/hw/pci_internals.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef QEMU_PCI_INTERNALS_H -#define QEMU_PCI_INTERNALS_H - -/* - * This header files is private to pci.c and pci_bridge.c - * So following structures are opaque to others and shouldn't be - * accessed. - * - * For pci-to-pci bridge needs to include this header file to embed - * PCIBridge in its structure or to get sizeof(PCIBridge), - * However, they shouldn't access those following members directly. - * Use accessor function in pci.h, pci_bridge.h - */ - -#define TYPE_PCI_BUS "PCI" -#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) - -struct PCIBus { - BusState qbus; - PCIDMAContextFunc dma_context_fn; - void *dma_context_opaque; - uint8_t devfn_min; - pci_set_irq_fn set_irq; - pci_map_irq_fn map_irq; - pci_route_irq_fn route_intx_to_irq; - pci_hotplug_fn hotplug; - DeviceState *hotplug_qdev; - void *irq_opaque; - PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; - PCIDevice *parent_dev; - MemoryRegion *address_space_mem; - MemoryRegion *address_space_io; - - QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ - QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ - - /* The bus IRQ state is the logical OR of the connected devices. - Keep a count of the number of devices with raised IRQs. */ - int nirq; - int *irq_count; -}; - -typedef struct PCIBridgeWindows PCIBridgeWindows; - -/* - * Aliases for each of the address space windows that the bridge - * can forward. Mapped into the bridge's parent's address space, - * as subregions. - */ -struct PCIBridgeWindows { - MemoryRegion alias_pref_mem; - MemoryRegion alias_mem; - MemoryRegion alias_io; -}; - -struct PCIBridge { - PCIDevice dev; - - /* private member */ - PCIBus sec_bus; - /* - * Memory regions for the bridge's address spaces. These regions are not - * directly added to system_memory/system_io or its descendants. - * Bridge's secondary bus points to these, so that devices - * under the bridge see these regions as its address spaces. - * The regions are as large as the entire address space - - * they don't take into account any windows. - */ - MemoryRegion address_space_mem; - MemoryRegion address_space_io; - - PCIBridgeWindows *windows; - - pci_map_irq_fn map_irq; - const char *bus_name; -}; - -#endif /* QEMU_PCI_INTERNALS_H */ diff --git a/hw/pci_regs.h b/hw/pci_regs.h deleted file mode 100644 index 56a404b..0000000 --- a/hw/pci_regs.h +++ /dev/null @@ -1,717 +0,0 @@ -/* - * pci_regs.h - * - * PCI standard defines - * Copyright 1994, Drew Eckhardt - * Copyright 1997--1999 Martin Mares <mj@ucw.cz> - * - * For more information, please consult the following manuals (look at - * http://www.pcisig.com/ for how to get them): - * - * PCI BIOS Specification - * PCI Local Bus Specification - * PCI to PCI Bridge Specification - * PCI System Design Guide - * - * For hypertransport information, please consult the following manuals - * from http://www.hypertransport.org - * - * The Hypertransport I/O Link Specification - */ - -#ifndef LINUX_PCI_REGS_H -#define LINUX_PCI_REGS_H - -/* - * Under PCI, each device has 256 bytes of configuration address space, - * of which the first 64 bytes are standardized as follows: - */ -#define PCI_VENDOR_ID 0x00 /* 16 bits */ -#define PCI_DEVICE_ID 0x02 /* 16 bits */ -#define PCI_COMMAND 0x04 /* 16 bits */ -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ -#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ -#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ -#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ -#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ -#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ -#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ -#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ -#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ -#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ - -#define PCI_STATUS 0x06 /* 16 bits */ -#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */ -#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ -#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ -#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ -#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ -#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ -#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ -#define PCI_STATUS_DEVSEL_FAST 0x000 -#define PCI_STATUS_DEVSEL_MEDIUM 0x200 -#define PCI_STATUS_DEVSEL_SLOW 0x400 -#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ -#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ -#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ -#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ -#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ - -#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ -#define PCI_REVISION_ID 0x08 /* Revision ID */ -#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ -#define PCI_CLASS_DEVICE 0x0a /* Device class */ - -#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ -#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ -#define PCI_HEADER_TYPE 0x0e /* 8 bits */ -#define PCI_HEADER_TYPE_NORMAL 0 -#define PCI_HEADER_TYPE_BRIDGE 1 -#define PCI_HEADER_TYPE_CARDBUS 2 - -#define PCI_BIST 0x0f /* 8 bits */ -#define PCI_BIST_CODE_MASK 0x0f /* Return result */ -#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ -#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ - -/* - * Base addresses specify locations in memory or I/O space. - * Decoded size can be determined by writing a value of - * 0xffffffff to the register, and reading it back. Only - * 1 bits are decoded. - */ -#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ -#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ -#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ -#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ -#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ -#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ -#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ -#define PCI_BASE_ADDRESS_SPACE_IO 0x01 -#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 -#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 -#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ -#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ -#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ -#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ -#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) -#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) -/* bit 1 is reserved if address_space = 1 */ - -/* Header type 0 (normal devices) */ -#define PCI_CARDBUS_CIS 0x28 -#define PCI_SUBSYSTEM_VENDOR_ID 0x2c -#define PCI_SUBSYSTEM_ID 0x2e -#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ -#define PCI_ROM_ADDRESS_ENABLE 0x01 -#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) - -#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ - -/* 0x35-0x3b are reserved */ -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ -#define PCI_MIN_GNT 0x3e /* 8 bits */ -#define PCI_MAX_LAT 0x3f /* 8 bits */ - -/* Header type 1 (PCI-to-PCI bridges) */ -#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ -#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ -#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ -#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ -#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ -#define PCI_IO_LIMIT 0x1d -#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ -#define PCI_IO_RANGE_TYPE_16 0x00 -#define PCI_IO_RANGE_TYPE_32 0x01 -#define PCI_IO_RANGE_MASK (~0x0fUL) -#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ -#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ -#define PCI_MEMORY_LIMIT 0x22 -#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL -#define PCI_MEMORY_RANGE_MASK (~0x0fUL) -#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ -#define PCI_PREF_MEMORY_LIMIT 0x26 -#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL -#define PCI_PREF_RANGE_TYPE_32 0x00 -#define PCI_PREF_RANGE_TYPE_64 0x01 -#define PCI_PREF_RANGE_MASK (~0x0fUL) -#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ -#define PCI_PREF_LIMIT_UPPER32 0x2c -#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ -#define PCI_IO_LIMIT_UPPER16 0x32 -/* 0x34 same as for htype 0 */ -/* 0x35-0x3b is reserved */ -#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ -/* 0x3c-0x3d are same as for htype 0 */ -#define PCI_BRIDGE_CONTROL 0x3e -#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ -#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ -#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */ -#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ -#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ -#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ -#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ - -/* Header type 2 (CardBus bridges) */ -#define PCI_CB_CAPABILITY_LIST 0x14 -/* 0x15 reserved */ -#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */ -#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */ -#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */ -#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */ -#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ -#define PCI_CB_MEMORY_BASE_0 0x1c -#define PCI_CB_MEMORY_LIMIT_0 0x20 -#define PCI_CB_MEMORY_BASE_1 0x24 -#define PCI_CB_MEMORY_LIMIT_1 0x28 -#define PCI_CB_IO_BASE_0 0x2c -#define PCI_CB_IO_BASE_0_HI 0x2e -#define PCI_CB_IO_LIMIT_0 0x30 -#define PCI_CB_IO_LIMIT_0_HI 0x32 -#define PCI_CB_IO_BASE_1 0x34 -#define PCI_CB_IO_BASE_1_HI 0x36 -#define PCI_CB_IO_LIMIT_1 0x38 -#define PCI_CB_IO_LIMIT_1_HI 0x3a -#define PCI_CB_IO_RANGE_MASK (~0x03UL) -/* 0x3c-0x3d are same as for htype 0 */ -#define PCI_CB_BRIDGE_CONTROL 0x3e -#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */ -#define PCI_CB_BRIDGE_CTL_SERR 0x02 -#define PCI_CB_BRIDGE_CTL_ISA 0x04 -#define PCI_CB_BRIDGE_CTL_VGA 0x08 -#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20 -#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */ -#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */ -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */ -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200 -#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400 -#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 -#define PCI_CB_SUBSYSTEM_ID 0x42 -#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */ -/* 0x48-0x7f reserved */ - -/* Capability lists */ - -#define PCI_CAP_LIST_ID 0 /* Capability ID */ -#define PCI_CAP_ID_PM 0x01 /* Power Management */ -#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ -#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ -#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ -#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ -#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ -#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ -#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ -#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */ -#define PCI_CAP_ID_DBG 0x0A /* Debug port */ -#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ -#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ -#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ -#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ -#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ -#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ -#define PCI_CAP_ID_SATA 0x12 /* Serial ATA */ -#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ -#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ -#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ -#define PCI_CAP_SIZEOF 4 - -/* Power Management Registers */ - -#define PCI_PM_PMC 2 /* PM Capabilities Register */ -#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ -#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ -#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ -#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ -#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */ -#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ -#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ -#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ -#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ -#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ -#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ -#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ -#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ -#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ -#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */ -#define PCI_PM_CTRL 4 /* PM control and status register */ -#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ -#define PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */ -#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ -#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ -#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ -#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ -#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ -#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ -#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ -#define PCI_PM_DATA_REGISTER 7 /* (??) */ -#define PCI_PM_SIZEOF 8 - -/* AGP registers */ - -#define PCI_AGP_VERSION 2 /* BCD version number */ -#define PCI_AGP_RFU 3 /* Rest of capability flags */ -#define PCI_AGP_STATUS 4 /* Status register */ -#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ -#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ -#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ -#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ -#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ -#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ -#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ -#define PCI_AGP_COMMAND 8 /* Control register */ -#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ -#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ -#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ -#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ -#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ -#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ -#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ -#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ -#define PCI_AGP_SIZEOF 12 - -/* Vital Product Data */ - -#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */ -#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */ -#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */ -#define PCI_VPD_DATA 4 /* 32-bits of data returned here */ - -/* Slot Identification */ - -#define PCI_SID_ESR 2 /* Expansion Slot Register */ -#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ -#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ -#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ - -/* Message Signalled Interrupts registers */ - -#define PCI_MSI_FLAGS 2 /* Various flags */ -#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */ -#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */ -#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */ -#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */ -#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */ -#define PCI_MSI_RFU 3 /* Rest of capability flags */ -#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ -#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ -#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ -#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */ -#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ -#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ - -/* MSI-X registers */ -#define PCI_MSIX_FLAGS 2 -#define PCI_MSIX_FLAGS_QSIZE 0x7FF -#define PCI_MSIX_FLAGS_ENABLE (1 << 15) -#define PCI_MSIX_FLAGS_MASKALL (1 << 14) -#define PCI_MSIX_TABLE 4 -#define PCI_MSIX_PBA 8 -#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) - -/* MSI-X entry's format */ -#define PCI_MSIX_ENTRY_SIZE 16 -#define PCI_MSIX_ENTRY_LOWER_ADDR 0 -#define PCI_MSIX_ENTRY_UPPER_ADDR 4 -#define PCI_MSIX_ENTRY_DATA 8 -#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 -#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 - -/* CompactPCI Hotswap Register */ - -#define PCI_CHSWP_CSR 2 /* Control and Status Register */ -#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */ -#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */ -#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */ -#define PCI_CHSWP_LOO 0x08 /* LED On / Off */ -#define PCI_CHSWP_PI 0x30 /* Programming Interface */ -#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ -#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ - -/* PCI Advanced Feature registers */ - -#define PCI_AF_LENGTH 2 -#define PCI_AF_CAP 3 -#define PCI_AF_CAP_TP 0x01 -#define PCI_AF_CAP_FLR 0x02 -#define PCI_AF_CTRL 4 -#define PCI_AF_CTRL_FLR 0x01 -#define PCI_AF_STATUS 5 -#define PCI_AF_STATUS_TP 0x01 - -/* PCI-X registers */ - -#define PCI_X_CMD 2 /* Modes & Features */ -#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ -#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ -#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ -#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ -#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ -#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ -#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ - /* Max # of outstanding split transactions */ -#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */ -#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */ -#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */ -#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */ -#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */ -#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */ -#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */ -#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */ -#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ -#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */ -#define PCI_X_STATUS 4 /* PCI-X capabilities */ -#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */ -#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */ -#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */ -#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */ -#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */ -#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */ -#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */ -#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count */ -#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */ -#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */ -#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ -#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ -#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ - -/* PCI Bridge Subsystem ID registers */ - -#define PCI_SSVID_VENDOR_ID 4 /* PCI-Bridge subsystem vendor id register */ -#define PCI_SSVID_DEVICE_ID 6 /* PCI-Bridge subsystem device id register */ - -/* PCI Express capability registers */ - -#define PCI_EXP_FLAGS 2 /* Capabilities register */ -#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ -#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ -#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ -#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ -#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ -#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ -#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ -#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ -#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */ -#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ -#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ -#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ -#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ -#define PCI_EXP_DEVCAP 4 /* Device capabilities */ -#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */ -#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */ -#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */ -#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */ -#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */ -#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ -#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ -#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ -#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ -#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ -#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ -#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ -#define PCI_EXP_DEVCTL 8 /* Device Control */ -#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ -#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ -#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ -#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ -#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */ -#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ -#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ -#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ -#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ -#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ -#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ -#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ -#define PCI_EXP_DEVSTA 10 /* Device Status */ -#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ -#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ -#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */ -#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */ -#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ -#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ -#define PCI_EXP_LNKCAP 12 /* Link Capabilities */ -#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */ -#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */ -#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */ -#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */ -#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */ -#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* L1 Clock Power Management */ -#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Reporting Capable */ -#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link Active Reporting Capable */ -#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notification Capability */ -#define PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */ -#define PCI_EXP_LNKCTL 16 /* Link Control */ -#define PCI_EXP_LNKCTL_ASPMC 0x0003 /* ASPM Control */ -#define PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */ -#define PCI_EXP_LNKCTL_LD 0x0010 /* Link Disable */ -#define PCI_EXP_LNKCTL_RL 0x0020 /* Retrain Link */ -#define PCI_EXP_LNKCTL_CCC 0x0040 /* Common Clock Configuration */ -#define PCI_EXP_LNKCTL_ES 0x0080 /* Extended Synch */ -#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ -#define PCI_EXP_LNKCTL_HAWD 0x0200 /* Hardware Autonomous Width Disable */ -#define PCI_EXP_LNKCTL_LBMIE 0x0400 /* Link Bandwidth Management Interrupt Enable */ -#define PCI_EXP_LNKCTL_LABIE 0x0800 /* Lnk Autonomous Bandwidth Interrupt Enable */ -#define PCI_EXP_LNKSTA 18 /* Link Status */ -#define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */ -#define PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */ -#define PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */ -#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Nogotiated Link Width */ -#define PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */ -#define PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */ -#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ -#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ -#define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ -#define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */ -#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ -#define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */ -#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */ -#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */ -#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Present */ -#define PCI_EXP_SLTCAP_PIP 0x00000010 /* Power Indicator Present */ -#define PCI_EXP_SLTCAP_HPS 0x00000020 /* Hot-Plug Surprise */ -#define PCI_EXP_SLTCAP_HPC 0x00000040 /* Hot-Plug Capable */ -#define PCI_EXP_SLTCAP_SPLV 0x00007f80 /* Slot Power Limit Value */ -#define PCI_EXP_SLTCAP_SPLS 0x00018000 /* Slot Power Limit Scale */ -#define PCI_EXP_SLTCAP_EIP 0x00020000 /* Electromechanical Interlock Present */ -#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Support */ -#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ -#define PCI_EXP_SLTCTL 24 /* Slot Control */ -#define PCI_EXP_SLTCTL_ABPE 0x0001 /* Attention Button Pressed Enable */ -#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enable */ -#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable */ -#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed Enable */ -#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable */ -#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */ -#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */ -#define PCI_EXP_SLTCTL_PIC 0x0300 /* Power Indicator Control */ -#define PCI_EXP_SLTCTL_PCC 0x0400 /* Power Controller Control */ -#define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */ -#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */ -#define PCI_EXP_SLTSTA 26 /* Slot Status */ -#define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */ -#define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */ -#define PCI_EXP_SLTSTA_MRLSC 0x0004 /* MRL Sensor Changed */ -#define PCI_EXP_SLTSTA_PDC 0x0008 /* Presence Detect Changed */ -#define PCI_EXP_SLTSTA_CC 0x0010 /* Command Completed */ -#define PCI_EXP_SLTSTA_MRLSS 0x0020 /* MRL Sensor State */ -#define PCI_EXP_SLTSTA_PDS 0x0040 /* Presence Detect State */ -#define PCI_EXP_SLTSTA_EIS 0x0080 /* Electromechanical Interlock Status */ -#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Changed */ -#define PCI_EXP_RTCTL 28 /* Root Control */ -#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctable Error */ -#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal Error */ -#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Error */ -#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */ -#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */ -#define PCI_EXP_RTCAP 30 /* Root Capabilities */ -#define PCI_EXP_RTSTA 32 /* Root Status */ -#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ -#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ -#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ -#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ -#define PCI_EXP_DEVCAP2_LTR 0x800 /* Latency tolerance reporting */ -#define PCI_EXP_OBFF_MASK 0xc0000 /* OBFF support mechanism */ -#define PCI_EXP_OBFF_MSG 0x40000 /* New message signaling */ -#define PCI_EXP_OBFF_WAKE 0x80000 /* Re-use WAKE# for OBFF */ -#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ -#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */ -#define PCI_EXP_IDO_REQ_EN 0x100 /* ID-based ordering request enable */ -#define PCI_EXP_IDO_CMP_EN 0x200 /* ID-based ordering completion enable */ -#define PCI_EXP_LTR_EN 0x400 /* Latency tolerance reporting */ -#define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message type A */ -#define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message type B */ -#define PCI_EXP_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ -#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ -#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ - -/* Extended Capabilities (PCI-X 2.0 and Express) */ -#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff) -#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf) -#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc) - -#define PCI_EXT_CAP_ID_ERR 1 -#define PCI_EXT_CAP_ID_VC 2 -#define PCI_EXT_CAP_ID_DSN 3 -#define PCI_EXT_CAP_ID_PWR 4 -#define PCI_EXT_CAP_ID_VNDR 11 -#define PCI_EXT_CAP_ID_ACS 13 -#define PCI_EXT_CAP_ID_ARI 14 -#define PCI_EXT_CAP_ID_ATS 15 -#define PCI_EXT_CAP_ID_SRIOV 16 -#define PCI_EXT_CAP_ID_LTR 24 - -/* Advanced Error Reporting */ -#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ -#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */ -#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ -#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */ -#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */ -#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */ -#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */ -#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */ -#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */ -#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */ -#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */ -#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */ -#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */ - /* Same bits as above */ -#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */ - /* Same bits as above */ -#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */ -#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */ -#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */ -#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */ -#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */ -#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */ -#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ - /* Same bits as above */ -#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ -#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */ -#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */ -#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */ -#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */ -#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ -#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */ -#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */ -/* Correctable Err Reporting Enable */ -#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 -/* Non-fatal Err Reporting Enable */ -#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 -/* Fatal Err Reporting Enable */ -#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 -#define PCI_ERR_ROOT_STATUS 48 -#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ -/* Multi ERR_COR Received */ -#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 -/* ERR_FATAL/NONFATAL Recevied */ -#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 -/* Multi ERR_FATAL/NONFATAL Recevied */ -#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 -#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */ -#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ -#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ -#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */ - -/* Virtual Channel */ -#define PCI_VC_PORT_REG1 4 -#define PCI_VC_PORT_REG2 8 -#define PCI_VC_PORT_CTRL 12 -#define PCI_VC_PORT_STATUS 14 -#define PCI_VC_RES_CAP 16 -#define PCI_VC_RES_CTRL 20 -#define PCI_VC_RES_STATUS 26 - -/* Power Budgeting */ -#define PCI_PWR_DSR 4 /* Data Select Register */ -#define PCI_PWR_DATA 8 /* Data Register */ -#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */ -#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */ -#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */ -#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */ -#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */ -#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */ -#define PCI_PWR_CAP 12 /* Capability */ -#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ - -/* - * Hypertransport sub capability types - * - * Unfortunately there are both 3 bit and 5 bit capability types defined - * in the HT spec, catering for that is a little messy. You probably don't - * want to use these directly, just use pci_find_ht_capability() and it - * will do the right thing for you. - */ -#define HT_3BIT_CAP_MASK 0xE0 -#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ -#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ - -#define HT_5BIT_CAP_MASK 0xF8 -#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ -#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ -#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ -#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */ -#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */ -#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */ -#define HT_MSI_FLAGS 0x02 /* Offset to flags */ -#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */ -#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */ -#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */ -#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */ -#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */ -#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */ -#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */ -#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */ -#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */ -#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */ -#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */ - -/* Alternative Routing-ID Interpretation */ -#define PCI_ARI_CAP 0x04 /* ARI Capability Register */ -#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */ -#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */ -#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */ -#define PCI_ARI_CTRL 0x06 /* ARI Control Register */ -#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */ -#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ -#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ - -/* Address Translation Service */ -#define PCI_ATS_CAP 0x04 /* ATS Capability Register */ -#define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f) /* Invalidate Queue Depth */ -#define PCI_ATS_MAX_QDEP 32 /* Max Invalidate Queue Depth */ -#define PCI_ATS_CTRL 0x06 /* ATS Control Register */ -#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */ -#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */ -#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */ - -/* Single Root I/O Virtualization */ -#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ -#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ -#define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */ -#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */ -#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */ -#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */ -#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */ -#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */ -#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */ -#define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */ -#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */ -#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */ -#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */ -#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */ -#define PCI_SRIOV_FUNC_LINK 0x12 /* Function Dependency Link */ -#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */ -#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */ -#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */ -#define PCI_SRIOV_SUP_PGSIZE 0x1c /* Supported Page Sizes */ -#define PCI_SRIOV_SYS_PGSIZE 0x20 /* System Page Size */ -#define PCI_SRIOV_BAR 0x24 /* VF BAR0 */ -#define PCI_SRIOV_NUM_BARS 6 /* Number of VF BARs */ -#define PCI_SRIOV_VFM 0x3c /* VF Migration State Array Offset*/ -#define PCI_SRIOV_VFM_BIR(x) ((x) & 7) /* State BIR */ -#define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7) /* State Offset */ -#define PCI_SRIOV_VFM_UA 0x0 /* Inactive.Unavailable */ -#define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */ -#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ -#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ - -#define PCI_LTR_MAX_SNOOP_LAT 0x4 -#define PCI_LTR_MAX_NOSNOOP_LAT 0x6 -#define PCI_LTR_VALUE_MASK 0x000003ff -#define PCI_LTR_SCALE_MASK 0x00001c00 -#define PCI_LTR_SCALE_SHIFT 10 - -/* Access Control Service */ -#define PCI_ACS_CAP 0x04 /* ACS Capability Register */ -#define PCI_ACS_SV 0x01 /* Source Validation */ -#define PCI_ACS_TB 0x02 /* Translation Blocking */ -#define PCI_ACS_RR 0x04 /* P2P Request Redirect */ -#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */ -#define PCI_ACS_UF 0x10 /* Upstream Forwarding */ -#define PCI_ACS_EC 0x20 /* P2P Egress Control */ -#define PCI_ACS_DT 0x40 /* Direct Translated P2P */ -#define PCI_ACS_CTRL 0x06 /* ACS Control Register */ -#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ - -#endif /* LINUX_PCI_REGS_H */ diff --git a/hw/pcie.c b/hw/pcie.c deleted file mode 100644 index 7c92f19..0000000 --- a/hw/pcie.c +++ /dev/null @@ -1,555 +0,0 @@ -/* - * pcie.c - * - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu-common.h" -#include "pci_bridge.h" -#include "pcie.h" -#include "msix.h" -#include "msi.h" -#include "pci_internals.h" -#include "pcie_regs.h" -#include "range.h" - -//#define DEBUG_PCIE -#ifdef DEBUG_PCIE -# define PCIE_DPRINTF(fmt, ...) \ - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) -#else -# define PCIE_DPRINTF(fmt, ...) do {} while (0) -#endif -#define PCIE_DEV_PRINTF(dev, fmt, ...) \ - PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) - - -/*************************************************************************** - * pci express capability helper functions - */ -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) -{ - int pos; - uint8_t *exp_cap; - - assert(pci_is_express(dev)); - - pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, - PCI_EXP_VER2_SIZEOF); - if (pos < 0) { - return pos; - } - dev->exp.exp_cap = pos; - exp_cap = dev->config + pos; - - /* capability register - interrupt message number defaults to 0 */ - pci_set_word(exp_cap + PCI_EXP_FLAGS, - ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) | - PCI_EXP_FLAGS_VER2); - - /* device capability register - * table 7-12: - * roll based error reporting bit must be set by all - * Functions conforming to the ECN, PCI Express Base - * Specification, Revision 1.1., or subsequent PCI Express Base - * Specification revisions. - */ - pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER); - - pci_set_long(exp_cap + PCI_EXP_LNKCAP, - (port << PCI_EXP_LNKCAP_PN_SHIFT) | - PCI_EXP_LNKCAP_ASPMS_0S | - PCI_EXP_LNK_MLW_1 | - PCI_EXP_LNK_LS_25); - - pci_set_word(exp_cap + PCI_EXP_LNKSTA, - PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25); - - pci_set_long(exp_cap + PCI_EXP_DEVCAP2, - PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP); - - pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB); - return pos; -} - -void pcie_cap_exit(PCIDevice *dev) -{ - pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF); -} - -uint8_t pcie_cap_get_type(const PCIDevice *dev) -{ - uint32_t pos = dev->exp.exp_cap; - assert(pos > 0); - return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) & - PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT; -} - -/* MSI/MSI-X */ -/* pci express interrupt message number */ -/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */ -void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector) -{ - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; - assert(vector < 32); - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ); - pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS, - vector << PCI_EXP_FLAGS_IRQ_SHIFT); -} - -uint8_t pcie_cap_flags_get_vector(PCIDevice *dev) -{ - return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) & - PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT; -} - -void pcie_cap_deverr_init(PCIDevice *dev) -{ - uint32_t pos = dev->exp.exp_cap; - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP, - PCI_EXP_DEVCAP_RBER); - pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | - PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); - pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA, - PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED | - PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD); -} - -void pcie_cap_deverr_reset(PCIDevice *dev) -{ - uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; - pci_long_test_and_clear_mask(devctl, - PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | - PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); -} - -static void hotplug_event_update_event_status(PCIDevice *dev) -{ - uint32_t pos = dev->exp.exp_cap; - uint8_t *exp_cap = dev->config + pos; - uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL); - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); - - dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) && - (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED); -} - -static void hotplug_event_notify(PCIDevice *dev) -{ - bool prev = dev->exp.hpev_notified; - - hotplug_event_update_event_status(dev); - - if (prev == dev->exp.hpev_notified) { - return; - } - - /* Note: the logic above does not take into account whether interrupts - * are masked. The result is that interrupt will be sent when it is - * subsequently unmasked. This appears to be legal: Section 6.7.3.4: - * The Port may optionally send an MSI when there are hot-plug events that - * occur while interrupt generation is disabled, and interrupt generation is - * subsequently enabled. */ - if (msix_enabled(dev)) { - msix_notify(dev, pcie_cap_flags_get_vector(dev)); - } else if (msi_enabled(dev)) { - msi_notify(dev, pcie_cap_flags_get_vector(dev)); - } else { - qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified); - } -} - -static void hotplug_event_clear(PCIDevice *dev) -{ - hotplug_event_update_event_status(dev); - if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) { - qemu_set_irq(dev->irq[dev->exp.hpev_intx], 0); - } -} - -/* - * A PCI Express Hot-Plug Event has occurred, so update slot status register - * and notify OS of the event if necessary. - * - * 6.7.3 PCI Express Hot-Plug Events - * 6.7.3.4 Software Notification of Hot-Plug Events - */ -static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) -{ - /* Minor optimization: if nothing changed - no event is needed. */ - if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap + - PCI_EXP_SLTSTA, event)) { - return; - } - hotplug_event_notify(dev); -} - -static int pcie_cap_slot_hotplug(DeviceState *qdev, - PCIDevice *pci_dev, PCIHotplugState state) -{ - PCIDevice *d = PCI_DEVICE(qdev); - uint8_t *exp_cap = d->config + d->exp.exp_cap; - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); - - /* Don't send event when device is enabled during qemu machine creation: - * it is present on boot, no hotplug event is necessary. We do send an - * event when the device is disabled later. */ - if (state == PCI_COLDPLUG_ENABLED) { - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_PDS); - return 0; - } - - PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state); - if (sltsta & PCI_EXP_SLTSTA_EIS) { - /* the slot is electromechanically locked. - * This error is propagated up to qdev and then to HMP/QMP. - */ - return -EBUSY; - } - - /* TODO: multifunction hot-plug. - * Right now, only a device of function = 0 is allowed to be - * hot plugged/unplugged. - */ - assert(PCI_FUNC(pci_dev->devfn) == 0); - - if (state == PCI_HOTPLUG_ENABLED) { - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_PDS); - pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); - } else { - qdev_free(&pci_dev->qdev); - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_PDS); - pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); - } - return 0; -} - -/* pci express slot for pci express root/downstream port - PCI express capability slot registers */ -void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot) -{ - uint32_t pos = dev->exp.exp_cap; - - pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS, - PCI_EXP_FLAGS_SLOT); - - pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP, - ~PCI_EXP_SLTCAP_PSN); - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP, - (slot << PCI_EXP_SLTCAP_PSN_SHIFT) | - PCI_EXP_SLTCAP_EIP | - PCI_EXP_SLTCAP_HPS | - PCI_EXP_SLTCAP_HPC | - PCI_EXP_SLTCAP_PIP | - PCI_EXP_SLTCAP_AIP | - PCI_EXP_SLTCAP_ABP); - - pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL, - PCI_EXP_SLTCTL_PIC | - PCI_EXP_SLTCTL_AIC); - pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL, - PCI_EXP_SLTCTL_PIC_OFF | - PCI_EXP_SLTCTL_AIC_OFF); - pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, - PCI_EXP_SLTCTL_PIC | - PCI_EXP_SLTCTL_AIC | - PCI_EXP_SLTCTL_HPIE | - PCI_EXP_SLTCTL_CCIE | - PCI_EXP_SLTCTL_PDCE | - PCI_EXP_SLTCTL_ABPE); - /* Although reading PCI_EXP_SLTCTL_EIC returns always 0, - * make the bit writable here in order to detect 1b is written. - * pcie_cap_slot_write_config() test-and-clear the bit, so - * this bit always returns 0 to the guest. - */ - pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, - PCI_EXP_SLTCTL_EIC); - - pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA, - PCI_EXP_HP_EV_SUPPORTED); - - dev->exp.hpev_notified = false; - - pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)), - pcie_cap_slot_hotplug, &dev->qdev); -} - -void pcie_cap_slot_reset(PCIDevice *dev) -{ - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; - - PCIE_DEV_PRINTF(dev, "reset\n"); - - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, - PCI_EXP_SLTCTL_EIC | - PCI_EXP_SLTCTL_PIC | - PCI_EXP_SLTCTL_AIC | - PCI_EXP_SLTCTL_HPIE | - PCI_EXP_SLTCTL_CCIE | - PCI_EXP_SLTCTL_PDCE | - PCI_EXP_SLTCTL_ABPE); - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL, - PCI_EXP_SLTCTL_PIC_OFF | - PCI_EXP_SLTCTL_AIC_OFF); - - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_EIS |/* on reset, - the lock is released */ - PCI_EXP_SLTSTA_CC | - PCI_EXP_SLTSTA_PDC | - PCI_EXP_SLTSTA_ABP); - - hotplug_event_update_event_status(dev); -} - -void pcie_cap_slot_write_config(PCIDevice *dev, - uint32_t addr, uint32_t val, int len) -{ - uint32_t pos = dev->exp.exp_cap; - uint8_t *exp_cap = dev->config + pos; - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); - - if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) { - hotplug_event_clear(dev); - } - - if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) { - return; - } - - if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, - PCI_EXP_SLTCTL_EIC)) { - sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */ - pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta); - PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: " - "sltsta -> 0x%02"PRIx16"\n", - sltsta); - } - - hotplug_event_notify(dev); - - /* - * 6.7.3.2 Command Completed Events - * - * Software issues a command to a hot-plug capable Downstream Port by - * issuing a write transaction that targets any portion of the Port’s Slot - * Control register. A single write to the Slot Control register is - * considered to be a single command, even if the write affects more than - * one field in the Slot Control register. In response to this transaction, - * the Port must carry out the requested actions and then set the - * associated status field for the command completed event. */ - - /* Real hardware might take a while to complete requested command because - * physical movement would be involved like locking the electromechanical - * lock. However in our case, command is completed instantaneously above, - * so send a command completion event right now. - */ - pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI); -} - -int pcie_cap_slot_post_load(void *opaque, int version_id) -{ - PCIDevice *dev = opaque; - hotplug_event_update_event_status(dev); - return 0; -} - -void pcie_cap_slot_push_attention_button(PCIDevice *dev) -{ - pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP); -} - -/* root control/capabilities/status. PME isn't emulated for now */ -void pcie_cap_root_init(PCIDevice *dev) -{ - pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL, - PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | - PCI_EXP_RTCTL_SEFEE); -} - -void pcie_cap_root_reset(PCIDevice *dev) -{ - pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0); -} - -/* function level reset(FLR) */ -void pcie_cap_flr_init(PCIDevice *dev) -{ - pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP, - PCI_EXP_DEVCAP_FLR); - - /* Although reading BCR_FLR returns always 0, - * the bit is made writable here in order to detect the 1b is written - * pcie_cap_flr_write_config() test-and-clear the bit, so - * this bit always returns 0 to the guest. - */ - pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_BCR_FLR); -} - -void pcie_cap_flr_write_config(PCIDevice *dev, - uint32_t addr, uint32_t val, int len) -{ - uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; - if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) { - /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler - so the handler can detect FLR by looking at this bit. */ - pci_device_reset(dev); - pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR); - } -} - -/* Alternative Routing-ID Interpretation (ARI) */ -/* ari forwarding support for down stream port */ -void pcie_cap_ari_init(PCIDevice *dev) -{ - uint32_t pos = dev->exp.exp_cap; - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2, - PCI_EXP_DEVCAP2_ARI); - pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2, - PCI_EXP_DEVCTL2_ARI); -} - -void pcie_cap_ari_reset(PCIDevice *dev) -{ - uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2; - pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI); -} - -bool pcie_cap_is_ari_enabled(const PCIDevice *dev) -{ - if (!pci_is_express(dev)) { - return false; - } - if (!dev->exp.exp_cap) { - return false; - } - - return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & - PCI_EXP_DEVCTL2_ARI; -} - -/************************************************************************** - * pci express extended capability allocation functions - * uint16_t ext_cap_id (16 bit) - * uint8_t cap_ver (4 bit) - * uint16_t cap_offset (12 bit) - * uint16_t ext_cap_size - */ - -static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id, - uint16_t *prev_p) -{ - uint16_t prev = 0; - uint16_t next; - uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE); - - if (!header) { - /* no extended capability */ - next = 0; - goto out; - } - for (next = PCI_CONFIG_SPACE_SIZE; next; - prev = next, next = PCI_EXT_CAP_NEXT(header)) { - - assert(next >= PCI_CONFIG_SPACE_SIZE); - assert(next <= PCIE_CONFIG_SPACE_SIZE - 8); - - header = pci_get_long(dev->config + next); - if (PCI_EXT_CAP_ID(header) == cap_id) { - break; - } - } - -out: - if (prev_p) { - *prev_p = prev; - } - return next; -} - -uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id) -{ - return pcie_find_capability_list(dev, cap_id, NULL); -} - -static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next) -{ - uint16_t header = pci_get_long(dev->config + pos); - assert(!(next & (PCI_EXT_CAP_ALIGN - 1))); - header = (header & ~PCI_EXT_CAP_NEXT_MASK) | - ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK); - pci_set_long(dev->config + pos, header); -} - -/* - * caller must supply valid (offset, size) * such that the range shouldn't - * overlap with other capability or other registers. - * This function doesn't check it. - */ -void pcie_add_capability(PCIDevice *dev, - uint16_t cap_id, uint8_t cap_ver, - uint16_t offset, uint16_t size) -{ - uint32_t header; - uint16_t next; - - assert(offset >= PCI_CONFIG_SPACE_SIZE); - assert(offset < offset + size); - assert(offset + size < PCIE_CONFIG_SPACE_SIZE); - assert(size >= 8); - assert(pci_is_express(dev)); - - if (offset == PCI_CONFIG_SPACE_SIZE) { - header = pci_get_long(dev->config + offset); - next = PCI_EXT_CAP_NEXT(header); - } else { - uint16_t prev; - - /* 0 is reserved cap id. use internally to find the last capability - in the linked list */ - next = pcie_find_capability_list(dev, 0, &prev); - - assert(prev >= PCI_CONFIG_SPACE_SIZE); - assert(next == 0); - pcie_ext_cap_set_next(dev, prev, offset); - } - pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next)); - - /* Make capability read-only by default */ - memset(dev->wmask + offset, 0, size); - memset(dev->w1cmask + offset, 0, size); - /* Check capability by default */ - memset(dev->cmask + offset, 0xFF, size); -} - -/************************************************************************** - * pci express extended capability helper functions - */ - -/* ARI */ -void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn) -{ - pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER, - offset, PCI_ARI_SIZEOF); - pci_set_long(dev->config + offset + PCI_ARI_CAP, PCI_ARI_CAP_NFN(nextfn)); -} diff --git a/hw/pcie.h b/hw/pcie.h deleted file mode 100644 index 4889194..0000000 --- a/hw/pcie.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * pcie.h - * - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef QEMU_PCIE_H -#define QEMU_PCIE_H - -#include "hw.h" -#include "pci_regs.h" -#include "pcie_regs.h" -#include "pcie_aer.h" - -typedef enum { - /* for attention and power indicator */ - PCI_EXP_HP_IND_RESERVED = PCI_EXP_SLTCTL_IND_RESERVED, - PCI_EXP_HP_IND_ON = PCI_EXP_SLTCTL_IND_ON, - PCI_EXP_HP_IND_BLINK = PCI_EXP_SLTCTL_IND_BLINK, - PCI_EXP_HP_IND_OFF = PCI_EXP_SLTCTL_IND_OFF, -} PCIExpressIndicator; - -typedef enum { - /* these bits must match the bits in Slot Control/Status registers. - * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx - * - * Not all the bits of slot control register match with the ones of - * slot status. Not some bits of slot status register is used to - * show status, not to report event occurrence. - * So such bits must be masked out when checking the software - * notification condition. - */ - PCI_EXP_HP_EV_ABP = PCI_EXP_SLTCTL_ABPE, - /* attention button pressed */ - PCI_EXP_HP_EV_PDC = PCI_EXP_SLTCTL_PDCE, - /* presence detect changed */ - PCI_EXP_HP_EV_CCI = PCI_EXP_SLTCTL_CCIE, - /* command completed */ - - PCI_EXP_HP_EV_SUPPORTED = PCI_EXP_HP_EV_ABP | - PCI_EXP_HP_EV_PDC | - PCI_EXP_HP_EV_CCI, - /* supported event mask */ - - /* events not listed aren't supported */ -} PCIExpressHotPlugEvent; - -struct PCIExpressDevice { - /* Offset of express capability in config space */ - uint8_t exp_cap; - - /* SLOT */ - unsigned int hpev_intx; /* INTx for hot plug event (0-3:INT[A-D]#) - * default is 0 = INTA# - * If the chip wants to use other interrupt - * line, initialize this member with the - * desired number. - * If the chip dynamically changes this member, - * also initialize it when loaded as - * appropreately. - */ - bool hpev_notified; /* Logical AND of conditions for hot plug event. - Following 6.7.3.4: - Software Notification of Hot-Plug Events, an interrupt - is sent whenever the logical and of these conditions - transitions from false to true. */ - - /* AER */ - uint16_t aer_cap; - PCIEAERLog aer_log; - unsigned int aer_intx; /* INTx for error reporting - * default is 0 = INTA# - * If the chip wants to use other interrupt - * line, initialize this member with the - * desired number. - * If the chip dynamically changes this member, - * also initialize it when loaded as - * appropreately. - */ -}; - -/* PCI express capability helper functions */ -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port); -void pcie_cap_exit(PCIDevice *dev); -uint8_t pcie_cap_get_type(const PCIDevice *dev); -void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector); -uint8_t pcie_cap_flags_get_vector(PCIDevice *dev); - -void pcie_cap_deverr_init(PCIDevice *dev); -void pcie_cap_deverr_reset(PCIDevice *dev); - -void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot); -void pcie_cap_slot_reset(PCIDevice *dev); -void pcie_cap_slot_write_config(PCIDevice *dev, - uint32_t addr, uint32_t val, int len); -int pcie_cap_slot_post_load(void *opaque, int version_id); -void pcie_cap_slot_push_attention_button(PCIDevice *dev); - -void pcie_cap_root_init(PCIDevice *dev); -void pcie_cap_root_reset(PCIDevice *dev); - -void pcie_cap_flr_init(PCIDevice *dev); -void pcie_cap_flr_write_config(PCIDevice *dev, - uint32_t addr, uint32_t val, int len); - -void pcie_cap_ari_init(PCIDevice *dev); -void pcie_cap_ari_reset(PCIDevice *dev); -bool pcie_cap_is_ari_enabled(const PCIDevice *dev); - -/* PCI express extended capability helper functions */ -uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id); -void pcie_add_capability(PCIDevice *dev, - uint16_t cap_id, uint8_t cap_ver, - uint16_t offset, uint16_t size); - -void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn); - -extern const VMStateDescription vmstate_pcie_device; - -#define VMSTATE_PCIE_DEVICE(_field, _state) { \ - .name = (stringify(_field)), \ - .size = sizeof(PCIDevice), \ - .vmsd = &vmstate_pcie_device, \ - .flags = VMS_STRUCT, \ - .offset = vmstate_offset_value(_state, _field, PCIDevice), \ -} - -#endif /* QEMU_PCIE_H */ diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c deleted file mode 100644 index b04c164..0000000 --- a/hw/pcie_aer.c +++ /dev/null @@ -1,1032 +0,0 @@ -/* - * pcie_aer.c - * - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "sysemu.h" -#include "qemu-objects.h" -#include "monitor.h" -#include "pci_bridge.h" -#include "pcie.h" -#include "msix.h" -#include "msi.h" -#include "pci_internals.h" -#include "pcie_regs.h" - -//#define DEBUG_PCIE -#ifdef DEBUG_PCIE -# define PCIE_DPRINTF(fmt, ...) \ - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) -#else -# define PCIE_DPRINTF(fmt, ...) do {} while (0) -#endif -#define PCIE_DEV_PRINTF(dev, fmt, ...) \ - PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) - -#define PCI_ERR_SRC_COR_OFFS 0 -#define PCI_ERR_SRC_UNCOR_OFFS 2 - -/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */ -static uint32_t pcie_aer_uncor_default_severity(uint32_t status) -{ - switch (status) { - case PCI_ERR_UNC_INTN: - case PCI_ERR_UNC_DLP: - case PCI_ERR_UNC_SDN: - case PCI_ERR_UNC_RX_OVER: - case PCI_ERR_UNC_FCP: - case PCI_ERR_UNC_MALF_TLP: - return PCI_ERR_ROOT_CMD_FATAL_EN; - case PCI_ERR_UNC_POISON_TLP: - case PCI_ERR_UNC_ECRC: - case PCI_ERR_UNC_UNSUP: - case PCI_ERR_UNC_COMP_TIME: - case PCI_ERR_UNC_COMP_ABORT: - case PCI_ERR_UNC_UNX_COMP: - case PCI_ERR_UNC_ACSV: - case PCI_ERR_UNC_MCBTLP: - case PCI_ERR_UNC_ATOP_EBLOCKED: - case PCI_ERR_UNC_TLP_PRF_BLOCKED: - return PCI_ERR_ROOT_CMD_NONFATAL_EN; - default: - abort(); - break; - } - return PCI_ERR_ROOT_CMD_FATAL_EN; -} - -static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err) -{ - if (aer_log->log_num == aer_log->log_max) { - return -1; - } - memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err); - aer_log->log_num++; - return 0; -} - -static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err) -{ - assert(aer_log->log_num); - *err = aer_log->log[0]; - aer_log->log_num--; - memmove(&aer_log->log[0], &aer_log->log[1], - aer_log->log_num * sizeof *err); -} - -static void aer_log_clear_all_err(PCIEAERLog *aer_log) -{ - aer_log->log_num = 0; -} - -int pcie_aer_init(PCIDevice *dev, uint16_t offset) -{ - PCIExpressDevice *exp; - - pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER, - offset, PCI_ERR_SIZEOF); - exp = &dev->exp; - exp->aer_cap = offset; - - /* log_max is property */ - if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) { - dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT; - } - /* clip down the value to avoid unreasobale memory usage */ - if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) { - return -EINVAL; - } - dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] * - dev->exp.aer_log.log_max); - - pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS, - PCI_ERR_UNC_SUPPORTED); - - pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER, - PCI_ERR_UNC_SEVERITY_DEFAULT); - pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER, - PCI_ERR_UNC_SUPPORTED); - - pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS, - PCI_ERR_COR_STATUS); - - pci_set_long(dev->config + offset + PCI_ERR_COR_MASK, - PCI_ERR_COR_MASK_DEFAULT); - pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK, - PCI_ERR_COR_SUPPORTED); - - /* capabilities and control. multiple header logging is supported */ - if (dev->exp.aer_log.log_max > 0) { - pci_set_long(dev->config + offset + PCI_ERR_CAP, - PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC | - PCI_ERR_CAP_MHRC); - pci_set_long(dev->wmask + offset + PCI_ERR_CAP, - PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE | - PCI_ERR_CAP_MHRE); - } else { - pci_set_long(dev->config + offset + PCI_ERR_CAP, - PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC); - pci_set_long(dev->wmask + offset + PCI_ERR_CAP, - PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); - } - - switch (pcie_cap_get_type(dev)) { - case PCI_EXP_TYPE_ROOT_PORT: - /* this case will be set by pcie_aer_root_init() */ - /* fallthrough */ - case PCI_EXP_TYPE_DOWNSTREAM: - case PCI_EXP_TYPE_UPSTREAM: - pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL, - PCI_BRIDGE_CTL_SERR); - pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS, - PCI_SEC_STATUS_RCV_SYSTEM_ERROR); - break; - default: - /* nothing */ - break; - } - return 0; -} - -void pcie_aer_exit(PCIDevice *dev) -{ - g_free(dev->exp.aer_log.log); -} - -static void pcie_aer_update_uncor_status(PCIDevice *dev) -{ - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; - PCIEAERLog *aer_log = &dev->exp.aer_log; - - uint16_t i; - for (i = 0; i < aer_log->log_num; i++) { - pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS, - dev->exp.aer_log.log[i].status); - } -} - -/* - * return value: - * true: error message needs to be sent up - * false: error message is masked - * - * 6.2.6 Error Message Control - * Figure 6-3 - * all pci express devices part - */ -static bool -pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg) -{ - if (!(pcie_aer_msg_is_uncor(msg) && - (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) { - return false; - } - - /* Signaled System Error - * - * 7.5.1.1 Command register - * Bit 8 SERR# Enable - * - * When Set, this bit enables reporting of Non-fatal and Fatal - * errors detected by the Function to the Root Complex. Note that - * errors are reported if enabled either through this bit or through - * the PCI Express specific bits in the Device Control register (see - * Section 7.8.4). - */ - pci_word_test_and_set_mask(dev->config + PCI_STATUS, - PCI_STATUS_SIG_SYSTEM_ERROR); - - if (!(msg->severity & - pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) { - return false; - } - - /* send up error message */ - return true; -} - -/* - * return value: - * true: error message is sent up - * false: error message is masked - * - * 6.2.6 Error Message Control - * Figure 6-3 - * virtual pci bridge part - */ -static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg) -{ - uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL); - - if (pcie_aer_msg_is_uncor(msg)) { - /* Received System Error */ - pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS, - PCI_SEC_STATUS_RCV_SYSTEM_ERROR); - } - - if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) { - return false; - } - return true; -} - -void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector) -{ - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; - assert(vector < PCI_ERR_ROOT_IRQ_MAX); - pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS, - PCI_ERR_ROOT_IRQ); - pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS, - vector << PCI_ERR_ROOT_IRQ_SHIFT); -} - -static unsigned int pcie_aer_root_get_vector(PCIDevice *dev) -{ - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; - uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); - return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT; -} - -/* Given a status register, get corresponding bits in the command register */ -static uint32_t pcie_aer_status_to_cmd(uint32_t status) -{ - uint32_t cmd = 0; - if (status & PCI_ERR_ROOT_COR_RCV) { - cmd |= PCI_ERR_ROOT_CMD_COR_EN; - } - if (status & PCI_ERR_ROOT_NONFATAL_RCV) { - cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN; - } - if (status & PCI_ERR_ROOT_FATAL_RCV) { - cmd |= PCI_ERR_ROOT_CMD_FATAL_EN; - } - return cmd; -} - -static void pcie_aer_root_notify(PCIDevice *dev) -{ - if (msix_enabled(dev)) { - msix_notify(dev, pcie_aer_root_get_vector(dev)); - } else if (msi_enabled(dev)) { - msi_notify(dev, pcie_aer_root_get_vector(dev)); - } else { - qemu_set_irq(dev->irq[dev->exp.aer_intx], 1); - } -} - -/* - * 6.2.6 Error Message Control - * Figure 6-3 - * root port part - */ -static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg) -{ - uint16_t cmd; - uint8_t *aer_cap; - uint32_t root_cmd; - uint32_t root_status, prev_status; - - cmd = pci_get_word(dev->config + PCI_COMMAND); - aer_cap = dev->config + dev->exp.aer_cap; - root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); - prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); - - if (cmd & PCI_COMMAND_SERR) { - /* System Error. - * - * The way to report System Error is platform specific and - * it isn't implemented in qemu right now. - * So just discard the error for now. - * OS which cares of aer would receive errors via - * native aer mechanims, so this wouldn't matter. - */ - } - - /* Errro Message Received: Root Error Status register */ - switch (msg->severity) { - case PCI_ERR_ROOT_CMD_COR_EN: - if (root_status & PCI_ERR_ROOT_COR_RCV) { - root_status |= PCI_ERR_ROOT_MULTI_COR_RCV; - } else { - pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SRC_COR_OFFS, - msg->source_id); - } - root_status |= PCI_ERR_ROOT_COR_RCV; - break; - case PCI_ERR_ROOT_CMD_NONFATAL_EN: - root_status |= PCI_ERR_ROOT_NONFATAL_RCV; - break; - case PCI_ERR_ROOT_CMD_FATAL_EN: - if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) { - root_status |= PCI_ERR_ROOT_FIRST_FATAL; - } - root_status |= PCI_ERR_ROOT_FATAL_RCV; - break; - default: - abort(); - break; - } - if (pcie_aer_msg_is_uncor(msg)) { - if (root_status & PCI_ERR_ROOT_UNCOR_RCV) { - root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV; - } else { - pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + - PCI_ERR_SRC_UNCOR_OFFS, msg->source_id); - } - root_status |= PCI_ERR_ROOT_UNCOR_RCV; - } - pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status); - - /* 6.2.4.1.2 Interrupt Generation */ - /* All the above did was set some bits in the status register. - * Specifically these that match message severity. - * The below code relies on this fact. */ - if (!(root_cmd & msg->severity) || - (pcie_aer_status_to_cmd(prev_status) & root_cmd)) { - /* Condition is not being set or was already true so nothing to do. */ - return; - } - - pcie_aer_root_notify(dev); -} - -/* - * 6.2.6 Error Message Control Figure 6-3 - * - * Walk up the bus tree from the device, propagate the error message. - */ -static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) -{ - uint8_t type; - - while (dev) { - if (!pci_is_express(dev)) { - /* just ignore it */ - /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR? - * Consider e.g. a PCI bridge above a PCI Express device. */ - return; - } - - type = pcie_cap_get_type(dev); - if ((type == PCI_EXP_TYPE_ROOT_PORT || - type == PCI_EXP_TYPE_UPSTREAM || - type == PCI_EXP_TYPE_DOWNSTREAM) && - !pcie_aer_msg_vbridge(dev, msg)) { - return; - } - if (!pcie_aer_msg_alldev(dev, msg)) { - return; - } - if (type == PCI_EXP_TYPE_ROOT_PORT) { - pcie_aer_msg_root_port(dev, msg); - /* Root port can notify system itself, - or send the error message to root complex event collector. */ - /* - * if root port is associated with an event collector, - * return the root complex event collector here. - * For now root complex event collector isn't supported. - */ - return; - } - dev = pci_bridge_get_device(dev->bus); - } -} - -static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err) -{ - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; - uint8_t first_bit = ffs(err->status) - 1; - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); - int i; - - assert(err->status); - assert(!(err->status & (err->status - 1))); - - errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); - errcap |= PCI_ERR_CAP_FEP(first_bit); - - if (err->flags & PCIE_AER_ERR_HEADER_VALID) { - for (i = 0; i < ARRAY_SIZE(err->header); ++i) { - /* 7.10.8 Header Log Register */ - uint8_t *header_log = - aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0]; - cpu_to_be32wu((uint32_t*)header_log, err->header[i]); - } - } else { - assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT)); - memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); - } - - if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) && - (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & - PCI_EXP_DEVCAP2_EETLPP)) { - for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) { - /* 7.10.12 tlp prefix log register */ - uint8_t *prefix_log = - aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0]; - cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]); - } - errcap |= PCI_ERR_CAP_TLP; - } else { - memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, - PCI_ERR_TLP_PREFIX_LOG_SIZE); - } - pci_set_long(aer_cap + PCI_ERR_CAP, errcap); -} - -static void pcie_aer_clear_log(PCIDevice *dev) -{ - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; - - pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP, - PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); - - memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); - memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE); -} - -static void pcie_aer_clear_error(PCIDevice *dev) -{ - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); - PCIEAERLog *aer_log = &dev->exp.aer_log; - PCIEAERErr err; - - if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) { - pcie_aer_clear_log(dev); - return; - } - - /* - * If more errors are queued, set corresponding bits in uncorrectable - * error status. - * We emulate uncorrectable error status register as W1CS. - * So set bit in uncorrectable error status here again for multiple - * error recording support. - * - * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability) - */ - pcie_aer_update_uncor_status(dev); - - aer_log_del_err(aer_log, &err); - pcie_aer_update_log(dev, &err); -} - -static int pcie_aer_record_error(PCIDevice *dev, - const PCIEAERErr *err) -{ - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); - int fep = PCI_ERR_CAP_FEP(errcap); - - assert(err->status); - assert(!(err->status & (err->status - 1))); - - if (errcap & PCI_ERR_CAP_MHRE && - (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) { - /* Not first error. queue error */ - if (aer_log_add_err(&dev->exp.aer_log, err) < 0) { - /* overflow */ - return -1; - } - return 0; - } - - pcie_aer_update_log(dev, err); - return 0; -} - -typedef struct PCIEAERInject { - PCIDevice *dev; - uint8_t *aer_cap; - const PCIEAERErr *err; - uint16_t devctl; - uint16_t devsta; - uint32_t error_status; - bool unsupported_request; - bool log_overflow; - PCIEAERMsg msg; -} PCIEAERInject; - -static bool pcie_aer_inject_cor_error(PCIEAERInject *inj, - uint32_t uncor_status, - bool is_advisory_nonfatal) -{ - PCIDevice *dev = inj->dev; - - inj->devsta |= PCI_EXP_DEVSTA_CED; - if (inj->unsupported_request) { - inj->devsta |= PCI_EXP_DEVSTA_URD; - } - pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); - - if (inj->aer_cap) { - uint32_t mask; - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS, - inj->error_status); - mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK); - if (mask & inj->error_status) { - return false; - } - if (is_advisory_nonfatal) { - uint32_t uncor_mask = - pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); - if (!(uncor_mask & uncor_status)) { - inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); - } - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, - uncor_status); - } - } - - if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) { - return false; - } - if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) { - return false; - } - - inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN; - return true; -} - -static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal) -{ - PCIDevice *dev = inj->dev; - uint16_t cmd; - - if (is_fatal) { - inj->devsta |= PCI_EXP_DEVSTA_FED; - } else { - inj->devsta |= PCI_EXP_DEVSTA_NFED; - } - if (inj->unsupported_request) { - inj->devsta |= PCI_EXP_DEVSTA_URD; - } - pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); - - if (inj->aer_cap) { - uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); - if (mask & inj->error_status) { - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, - inj->error_status); - return false; - } - - inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, - inj->error_status); - } - - cmd = pci_get_word(dev->config + PCI_COMMAND); - if (inj->unsupported_request && - !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) { - return false; - } - if (is_fatal) { - if (!((cmd & PCI_COMMAND_SERR) || - (inj->devctl & PCI_EXP_DEVCTL_FERE))) { - return false; - } - inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN; - } else { - if (!((cmd & PCI_COMMAND_SERR) || - (inj->devctl & PCI_EXP_DEVCTL_NFERE))) { - return false; - } - inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN; - } - return true; -} - -/* - * non-Function specific error must be recorded in all functions. - * It is the responsibility of the caller of this function. - * It is also caller's responsibility to determine which function should - * report the rerror. - * - * 6.2.4 Error Logging - * 6.2.5 Sqeunce of Device Error Signaling and Logging Operations - * table 6-2: Flowchard Showing Sequence of Device Error Signaling and Logging - * Operations - */ -int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err) -{ - uint8_t *aer_cap = NULL; - uint16_t devctl = 0; - uint16_t devsta = 0; - uint32_t error_status = err->status; - PCIEAERInject inj; - - if (!pci_is_express(dev)) { - return -ENOSYS; - } - - if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { - error_status &= PCI_ERR_COR_SUPPORTED; - } else { - error_status &= PCI_ERR_UNC_SUPPORTED; - } - - /* invalid status bit. one and only one bit must be set */ - if (!error_status || (error_status & (error_status - 1))) { - return -EINVAL; - } - - if (dev->exp.aer_cap) { - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; - aer_cap = dev->config + dev->exp.aer_cap; - devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL); - devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA); - } - - inj.dev = dev; - inj.aer_cap = aer_cap; - inj.err = err; - inj.devctl = devctl; - inj.devsta = devsta; - inj.error_status = error_status; - inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) && - err->status == PCI_ERR_UNC_UNSUP; - inj.log_overflow = false; - - if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { - if (!pcie_aer_inject_cor_error(&inj, 0, false)) { - return 0; - } - } else { - bool is_fatal = - pcie_aer_uncor_default_severity(error_status) == - PCI_ERR_ROOT_CMD_FATAL_EN; - if (aer_cap) { - is_fatal = - error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER); - } - if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) { - inj.error_status = PCI_ERR_COR_ADV_NONFATAL; - if (!pcie_aer_inject_cor_error(&inj, error_status, true)) { - return 0; - } - } else { - if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) { - return 0; - } - } - } - - /* send up error message */ - inj.msg.source_id = err->source_id; - pcie_aer_msg(dev, &inj.msg); - - if (inj.log_overflow) { - PCIEAERErr header_log_overflow = { - .status = PCI_ERR_COR_HL_OVERFLOW, - .flags = PCIE_AER_ERR_IS_CORRECTABLE, - }; - int ret = pcie_aer_inject_error(dev, &header_log_overflow); - assert(!ret); - } - return 0; -} - -void pcie_aer_write_config(PCIDevice *dev, - uint32_t addr, uint32_t val, int len) -{ - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); - uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap); - uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS); - - /* uncorrectable error */ - if (!(uncorsta & first_error)) { - /* the bit that corresponds to the first error is cleared */ - pcie_aer_clear_error(dev); - } else if (errcap & PCI_ERR_CAP_MHRE) { - /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared - * nothing should happen. So we have to revert the modification to - * the register. - */ - pcie_aer_update_uncor_status(dev); - } else { - /* capability & control - * PCI_ERR_CAP_MHRE might be cleared, so clear of header log. - */ - aer_log_clear_all_err(&dev->exp.aer_log); - } -} - -void pcie_aer_root_init(PCIDevice *dev) -{ - uint16_t pos = dev->exp.aer_cap; - - pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND, - PCI_ERR_ROOT_CMD_EN_MASK); - pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS, - PCI_ERR_ROOT_STATUS_REPORT_MASK); - /* PCI_ERR_ROOT_IRQ is RO but devices change it using a - * device-specific method. - */ - pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS, - ~PCI_ERR_ROOT_IRQ); -} - -void pcie_aer_root_reset(PCIDevice *dev) -{ - uint8_t* aer_cap = dev->config + dev->exp.aer_cap; - - pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0); - - /* - * Advanced Error Interrupt Message Number in Root Error Status Register - * must be updated by chip dependent code because it's chip dependent - * which number is used. - */ -} - -void pcie_aer_root_write_config(PCIDevice *dev, - uint32_t addr, uint32_t val, int len, - uint32_t root_cmd_prev) -{ - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; - uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); - uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status); - uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); - /* 6.2.4.1.2 Interrupt Generation */ - if (!msix_enabled(dev) && !msi_enabled(dev)) { - qemu_set_irq(dev->irq[dev->exp.aer_intx], !!(root_cmd & enabled_cmd)); - return; - } - - if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) { - /* Send MSI on transition from false to true. */ - return; - } - - pcie_aer_root_notify(dev); -} - -static const VMStateDescription vmstate_pcie_aer_err = { - .name = "PCIE_AER_ERROR", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(status, PCIEAERErr), - VMSTATE_UINT16(source_id, PCIEAERErr), - VMSTATE_UINT16(flags, PCIEAERErr), - VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4), - VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4), - VMSTATE_END_OF_LIST() - } -}; - -const VMStateDescription vmstate_pcie_aer_log = { - .name = "PCIE_AER_ERROR_LOG", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT16(log_num, PCIEAERLog), - VMSTATE_UINT16(log_max, PCIEAERLog), - VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num, - vmstate_pcie_aer_err, PCIEAERErr), - VMSTATE_END_OF_LIST() - } -}; - -void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) -{ - QDict *qdict; - int devfn; - assert(qobject_type(data) == QTYPE_QDICT); - qdict = qobject_to_qdict(data); - - devfn = (int)qdict_get_int(qdict, "devfn"); - monitor_printf(mon, "OK id: %s domain: %x, bus: %x devfn: %x.%x\n", - qdict_get_str(qdict, "id"), - (int) qdict_get_int(qdict, "domain"), - (int) qdict_get_int(qdict, "bus"), - PCI_SLOT(devfn), PCI_FUNC(devfn)); -} - -typedef struct PCIEAERErrorName { - const char *name; - uint32_t val; - bool correctable; -} PCIEAERErrorName; - -/* - * AER error name -> value conversion table - * This naming scheme is same to linux aer-injection tool. - */ -static const struct PCIEAERErrorName pcie_aer_error_list[] = { - { - .name = "TRAIN", - .val = PCI_ERR_UNC_TRAIN, - .correctable = false, - }, { - .name = "DLP", - .val = PCI_ERR_UNC_DLP, - .correctable = false, - }, { - .name = "SDN", - .val = PCI_ERR_UNC_SDN, - .correctable = false, - }, { - .name = "POISON_TLP", - .val = PCI_ERR_UNC_POISON_TLP, - .correctable = false, - }, { - .name = "FCP", - .val = PCI_ERR_UNC_FCP, - .correctable = false, - }, { - .name = "COMP_TIME", - .val = PCI_ERR_UNC_COMP_TIME, - .correctable = false, - }, { - .name = "COMP_ABORT", - .val = PCI_ERR_UNC_COMP_ABORT, - .correctable = false, - }, { - .name = "UNX_COMP", - .val = PCI_ERR_UNC_UNX_COMP, - .correctable = false, - }, { - .name = "RX_OVER", - .val = PCI_ERR_UNC_RX_OVER, - .correctable = false, - }, { - .name = "MALF_TLP", - .val = PCI_ERR_UNC_MALF_TLP, - .correctable = false, - }, { - .name = "ECRC", - .val = PCI_ERR_UNC_ECRC, - .correctable = false, - }, { - .name = "UNSUP", - .val = PCI_ERR_UNC_UNSUP, - .correctable = false, - }, { - .name = "ACSV", - .val = PCI_ERR_UNC_ACSV, - .correctable = false, - }, { - .name = "INTN", - .val = PCI_ERR_UNC_INTN, - .correctable = false, - }, { - .name = "MCBTLP", - .val = PCI_ERR_UNC_MCBTLP, - .correctable = false, - }, { - .name = "ATOP_EBLOCKED", - .val = PCI_ERR_UNC_ATOP_EBLOCKED, - .correctable = false, - }, { - .name = "TLP_PRF_BLOCKED", - .val = PCI_ERR_UNC_TLP_PRF_BLOCKED, - .correctable = false, - }, { - .name = "RCVR", - .val = PCI_ERR_COR_RCVR, - .correctable = true, - }, { - .name = "BAD_TLP", - .val = PCI_ERR_COR_BAD_TLP, - .correctable = true, - }, { - .name = "BAD_DLLP", - .val = PCI_ERR_COR_BAD_DLLP, - .correctable = true, - }, { - .name = "REP_ROLL", - .val = PCI_ERR_COR_REP_ROLL, - .correctable = true, - }, { - .name = "REP_TIMER", - .val = PCI_ERR_COR_REP_TIMER, - .correctable = true, - }, { - .name = "ADV_NONFATAL", - .val = PCI_ERR_COR_ADV_NONFATAL, - .correctable = true, - }, { - .name = "INTERNAL", - .val = PCI_ERR_COR_INTERNAL, - .correctable = true, - }, { - .name = "HL_OVERFLOW", - .val = PCI_ERR_COR_HL_OVERFLOW, - .correctable = true, - }, -}; - -static int pcie_aer_parse_error_string(const char *error_name, - uint32_t *status, bool *correctable) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) { - const PCIEAERErrorName *e = &pcie_aer_error_list[i]; - if (strcmp(error_name, e->name)) { - continue; - } - - *status = e->val; - *correctable = e->correctable; - return 0; - } - return -EINVAL; -} - -int do_pcie_aer_inject_error(Monitor *mon, - const QDict *qdict, QObject **ret_data) -{ - const char *id = qdict_get_str(qdict, "id"); - const char *error_name; - uint32_t error_status; - bool correctable; - PCIDevice *dev; - PCIEAERErr err; - int ret; - - ret = pci_qdev_find_device(id, &dev); - if (ret < 0) { - monitor_printf(mon, - "id or pci device path is invalid or device not " - "found. %s\n", id); - return ret; - } - if (!pci_is_express(dev)) { - monitor_printf(mon, "the device doesn't support pci express. %s\n", - id); - return -ENOSYS; - } - - error_name = qdict_get_str(qdict, "error_status"); - if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) { - char *e = NULL; - error_status = strtoul(error_name, &e, 0); - correctable = qdict_get_try_bool(qdict, "correctable", 0); - if (!e || *e != '\0') { - monitor_printf(mon, "invalid error status value. \"%s\"", - error_name); - return -EINVAL; - } - } - err.status = error_status; - err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn; - - err.flags = 0; - if (correctable) { - err.flags |= PCIE_AER_ERR_IS_CORRECTABLE; - } - if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) { - err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY; - } - if (qdict_haskey(qdict, "header0")) { - err.flags |= PCIE_AER_ERR_HEADER_VALID; - } - if (qdict_haskey(qdict, "prefix0")) { - err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT; - } - - err.header[0] = qdict_get_try_int(qdict, "header0", 0); - err.header[1] = qdict_get_try_int(qdict, "header1", 0); - err.header[2] = qdict_get_try_int(qdict, "header2", 0); - err.header[3] = qdict_get_try_int(qdict, "header3", 0); - - err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0); - err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0); - err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0); - err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0); - - ret = pcie_aer_inject_error(dev, &err); - *ret_data = qobject_from_jsonf("{'id': %s, " - "'domain': %d, 'bus': %d, 'devfn': %d, " - "'ret': %d}", - id, - pci_find_domain(dev->bus), - pci_bus_num(dev->bus), dev->devfn, - ret); - assert(*ret_data); - - return 0; -} diff --git a/hw/pcie_aer.h b/hw/pcie_aer.h deleted file mode 100644 index 7539500..0000000 --- a/hw/pcie_aer.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * pcie_aer.h - * - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef QEMU_PCIE_AER_H -#define QEMU_PCIE_AER_H - -#include "hw.h" - -/* definitions which PCIExpressDevice uses */ - -/* AER log */ -struct PCIEAERLog { - /* This structure is saved/loaded. - So explicitly size them instead of unsigned int */ - - /* the number of currently recorded log in log member */ - uint16_t log_num; - - /* - * The maximum number of the log. Errors can be logged up to this. - * - * This is configurable property. - * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT - * to avoid unreasonable memory usage. - * I bet that 128 log size would be big enough, otherwise too many errors - * for system to function normaly. But could consecutive errors occur? - */ -#define PCIE_AER_LOG_MAX_DEFAULT 8 -#define PCIE_AER_LOG_MAX_LIMIT 128 -#define PCIE_AER_LOG_MAX_UNSET 0xffff - uint16_t log_max; - - /* Error log. log_max-sized array */ - PCIEAERErr *log; -}; - -/* aer error message: error signaling message has only error sevirity and - source id. See 2.2.8.3 error signaling messages */ -struct PCIEAERMsg { - /* - * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN - * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE} - */ - uint32_t severity; - - uint16_t source_id; /* bdf */ -}; - -static inline bool -pcie_aer_msg_is_uncor(const PCIEAERMsg *msg) -{ - return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN || - msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN; -} - -/* error */ -struct PCIEAERErr { - uint32_t status; /* error status bits */ - uint16_t source_id; /* bdf */ - -#define PCIE_AER_ERR_IS_CORRECTABLE 0x1 /* correctable/uncorrectable */ -#define PCIE_AER_ERR_MAYBE_ADVISORY 0x2 /* maybe advisory non-fatal */ -#define PCIE_AER_ERR_HEADER_VALID 0x4 /* TLP header is logged */ -#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8 /* TLP Prefix is logged */ - uint16_t flags; - - uint32_t header[4]; /* TLP header */ - uint32_t prefix[4]; /* TLP header prefix */ -}; - -extern const VMStateDescription vmstate_pcie_aer_log; - -int pcie_aer_init(PCIDevice *dev, uint16_t offset); -void pcie_aer_exit(PCIDevice *dev); -void pcie_aer_write_config(PCIDevice *dev, - uint32_t addr, uint32_t val, int len); - -/* aer root port */ -void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector); -void pcie_aer_root_init(PCIDevice *dev); -void pcie_aer_root_reset(PCIDevice *dev); -void pcie_aer_root_write_config(PCIDevice *dev, - uint32_t addr, uint32_t val, int len, - uint32_t root_cmd_prev); - -/* error injection */ -int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err); - -#endif /* QEMU_PCIE_AER_H */ diff --git a/hw/pcie_host.c b/hw/pcie_host.c deleted file mode 100644 index c257fb4..0000000 --- a/hw/pcie_host.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * pcie_host.c - * utility functions for pci express host bridge. - * - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "hw.h" -#include "pci.h" -#include "pcie_host.h" -#include "exec-memory.h" - -/* - * PCI express mmcfig address - * bit 20 - 28: bus number - * bit 15 - 19: device number - * bit 12 - 14: function number - * bit 0 - 11: offset in configuration space of a given device - */ -#define PCIE_MMCFG_SIZE_MAX (1ULL << 28) -#define PCIE_MMCFG_SIZE_MIN (1ULL << 20) -#define PCIE_MMCFG_BUS_BIT 20 -#define PCIE_MMCFG_BUS_MASK 0x1ff -#define PCIE_MMCFG_DEVFN_BIT 12 -#define PCIE_MMCFG_DEVFN_MASK 0xff -#define PCIE_MMCFG_CONFOFFSET_MASK 0xfff -#define PCIE_MMCFG_BUS(addr) (((addr) >> PCIE_MMCFG_BUS_BIT) & \ - PCIE_MMCFG_BUS_MASK) -#define PCIE_MMCFG_DEVFN(addr) (((addr) >> PCIE_MMCFG_DEVFN_BIT) & \ - PCIE_MMCFG_DEVFN_MASK) -#define PCIE_MMCFG_CONFOFFSET(addr) ((addr) & PCIE_MMCFG_CONFOFFSET_MASK) - - -/* a helper function to get a PCIDevice for a given mmconfig address */ -static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, - uint32_t mmcfg_addr) -{ - return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), - PCIE_MMCFG_DEVFN(mmcfg_addr)); -} - -static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr, - uint64_t val, unsigned len) -{ - PCIExpressHost *e = opaque; - PCIBus *s = e->pci.bus; - PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); - uint32_t addr; - uint32_t limit; - - if (!pci_dev) { - return; - } - addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); - limit = pci_config_size(pci_dev); - if (limit <= addr) { - /* conventional pci device can be behind pcie-to-pci bridge. - 256 <= addr < 4K has no effects. */ - return; - } - pci_host_config_write_common(pci_dev, addr, limit, val, len); -} - -static uint64_t pcie_mmcfg_data_read(void *opaque, - hwaddr mmcfg_addr, - unsigned len) -{ - PCIExpressHost *e = opaque; - PCIBus *s = e->pci.bus; - PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); - uint32_t addr; - uint32_t limit; - - if (!pci_dev) { - return ~0x0; - } - addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); - limit = pci_config_size(pci_dev); - if (limit <= addr) { - /* conventional pci device can be behind pcie-to-pci bridge. - 256 <= addr < 4K has no effects. */ - return ~0x0; - } - return pci_host_config_read_common(pci_dev, addr, limit, len); -} - -static const MemoryRegionOps pcie_mmcfg_ops = { - .read = pcie_mmcfg_data_read, - .write = pcie_mmcfg_data_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -/* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */ -#define PCIE_BASE_ADDR_UNMAPPED ((hwaddr)-1ULL) - -int pcie_host_init(PCIExpressHost *e) -{ - e->base_addr = PCIE_BASE_ADDR_UNMAPPED; - - return 0; -} - -void pcie_host_mmcfg_unmap(PCIExpressHost *e) -{ - if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { - memory_region_del_subregion(get_system_memory(), &e->mmio); - memory_region_destroy(&e->mmio); - e->base_addr = PCIE_BASE_ADDR_UNMAPPED; - } -} - -void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, - uint32_t size) -{ - assert(!(size & (size - 1))); /* power of 2 */ - assert(size >= PCIE_MMCFG_SIZE_MIN); - assert(size <= PCIE_MMCFG_SIZE_MAX); - e->size = size; - memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size); - e->base_addr = addr; - memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio); -} - -void pcie_host_mmcfg_update(PCIExpressHost *e, - int enable, - hwaddr addr, - uint32_t size) -{ - pcie_host_mmcfg_unmap(e); - if (enable) { - pcie_host_mmcfg_map(e, addr, size); - } -} - -static const TypeInfo pcie_host_type_info = { - .name = TYPE_PCIE_HOST_BRIDGE, - .parent = TYPE_PCI_HOST_BRIDGE, - .abstract = true, - .instance_size = sizeof(PCIExpressHost), -}; - -static void pcie_host_register_types(void) -{ - type_register_static(&pcie_host_type_info); -} - -type_init(pcie_host_register_types) diff --git a/hw/pcie_host.h b/hw/pcie_host.h deleted file mode 100644 index 3921935..0000000 --- a/hw/pcie_host.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * pcie_host.h - * - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef PCIE_HOST_H -#define PCIE_HOST_H - -#include "pci_host.h" -#include "memory.h" - -#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge" -#define PCIE_HOST_BRIDGE(obj) \ - OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE) - -struct PCIExpressHost { - PCIHostState pci; - - /* express part */ - - /* base address where MMCONFIG area is mapped. */ - hwaddr base_addr; - - /* the size of MMCONFIG area. It's host bridge dependent */ - hwaddr size; - - /* MMCONFIG mmio area */ - MemoryRegion mmio; -}; - -int pcie_host_init(PCIExpressHost *e); -void pcie_host_mmcfg_unmap(PCIExpressHost *e); -void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size); -void pcie_host_mmcfg_update(PCIExpressHost *e, - int enable, - hwaddr addr, - uint32_t size); - -#endif /* PCIE_HOST_H */ diff --git a/hw/pcie_port.c b/hw/pcie_port.c deleted file mode 100644 index d6350e5..0000000 --- a/hw/pcie_port.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * pcie_port.c - * - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "pcie_port.h" - -void pcie_port_init_reg(PCIDevice *d) -{ - /* Unlike pci bridge, - 66MHz and fast back to back don't apply to pci express port. */ - pci_set_word(d->config + PCI_STATUS, 0); - pci_set_word(d->config + PCI_SEC_STATUS, 0); - - /* Unlike conventional pci bridge, some bits are hardwired to 0. */ - pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, - PCI_BRIDGE_CTL_PARITY | - PCI_BRIDGE_CTL_ISA | - PCI_BRIDGE_CTL_VGA | - PCI_BRIDGE_CTL_SERR | - PCI_BRIDGE_CTL_BUS_RESET); -} - -/************************************************************************** - * (chassis number, pcie physical slot number) -> pcie slot conversion - */ -struct PCIEChassis { - uint8_t number; - - QLIST_HEAD(, PCIESlot) slots; - QLIST_ENTRY(PCIEChassis) next; -}; - -static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis); - -static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number) -{ - struct PCIEChassis *c; - QLIST_FOREACH(c, &chassis, next) { - if (c->number == chassis_number) { - break; - } - } - return c; -} - -void pcie_chassis_create(uint8_t chassis_number) -{ - struct PCIEChassis *c; - c = pcie_chassis_find(chassis_number); - if (c) { - return; - } - c = g_malloc0(sizeof(*c)); - c->number = chassis_number; - QLIST_INIT(&c->slots); - QLIST_INSERT_HEAD(&chassis, c, next); -} - -static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c, - uint8_t slot) -{ - PCIESlot *s; - QLIST_FOREACH(s, &c->slots, next) { - if (s->slot == slot) { - break; - } - } - return s; -} - -PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot) -{ - struct PCIEChassis *c; - c = pcie_chassis_find(chassis_number); - if (!c) { - return NULL; - } - return pcie_chassis_find_slot_with_chassis(c, slot); -} - -int pcie_chassis_add_slot(struct PCIESlot *slot) -{ - struct PCIEChassis *c; - c = pcie_chassis_find(slot->chassis); - if (!c) { - return -ENODEV; - } - if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) { - return -EBUSY; - } - QLIST_INSERT_HEAD(&c->slots, slot, next); - return 0; -} - -void pcie_chassis_del_slot(PCIESlot *s) -{ - QLIST_REMOVE(s, next); -} diff --git a/hw/pcie_port.h b/hw/pcie_port.h deleted file mode 100644 index 3709583..0000000 --- a/hw/pcie_port.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * pcie_port.h - * - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef QEMU_PCIE_PORT_H -#define QEMU_PCIE_PORT_H - -#include "pci_bridge.h" -#include "pci_internals.h" - -struct PCIEPort { - PCIBridge br; - - /* pci express switch port */ - uint8_t port; -}; - -void pcie_port_init_reg(PCIDevice *d); - -struct PCIESlot { - PCIEPort port; - - /* pci express switch port with slot */ - uint8_t chassis; - uint16_t slot; - QLIST_ENTRY(PCIESlot) next; -}; - -void pcie_chassis_create(uint8_t chassis_number); -void pcie_main_chassis_create(void); -PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot); -int pcie_chassis_add_slot(struct PCIESlot *slot); -void pcie_chassis_del_slot(PCIESlot *s); - -#endif /* QEMU_PCIE_PORT_H */ diff --git a/hw/pcie_regs.h b/hw/pcie_regs.h deleted file mode 100644 index 4d123d9..0000000 --- a/hw/pcie_regs.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * constants for pcie configurations space from pci express spec. - * - * TODO: - * Those constants and macros should go to Linux pci_regs.h - * Once they're merged, they will go away. - */ -#ifndef QEMU_PCIE_REGS_H -#define QEMU_PCIE_REGS_H - - -/* express capability */ - -#define PCI_EXP_VER2_SIZEOF 0x3c /* express capability of ver. 2 */ -#define PCI_EXT_CAP_VER_SHIFT 16 -#define PCI_EXT_CAP_NEXT_SHIFT 20 -#define PCI_EXT_CAP_NEXT_MASK (0xffc << PCI_EXT_CAP_NEXT_SHIFT) - -#define PCI_EXT_CAP(id, ver, next) \ - ((id) | \ - ((ver) << PCI_EXT_CAP_VER_SHIFT) | \ - ((next) << PCI_EXT_CAP_NEXT_SHIFT)) - -#define PCI_EXT_CAP_ALIGN 4 -#define PCI_EXT_CAP_ALIGNUP(x) \ - (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1)) - -/* PCI_EXP_FLAGS */ -#define PCI_EXP_FLAGS_VER2 2 /* for now, supports only ver. 2 */ -#define PCI_EXP_FLAGS_IRQ_SHIFT (ffs(PCI_EXP_FLAGS_IRQ) - 1) -#define PCI_EXP_FLAGS_TYPE_SHIFT (ffs(PCI_EXP_FLAGS_TYPE) - 1) - - -/* PCI_EXP_LINK{CAP, STA} */ -/* link speed */ -#define PCI_EXP_LNK_LS_25 1 - -#define PCI_EXP_LNK_MLW_SHIFT (ffs(PCI_EXP_LNKCAP_MLW) - 1) -#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT) - -/* PCI_EXP_LINKCAP */ -#define PCI_EXP_LNKCAP_ASPMS_SHIFT (ffs(PCI_EXP_LNKCAP_ASPMS) - 1) -#define PCI_EXP_LNKCAP_ASPMS_0S (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT) - -#define PCI_EXP_LNKCAP_PN_SHIFT (ffs(PCI_EXP_LNKCAP_PN) - 1) - -#define PCI_EXP_SLTCAP_PSN_SHIFT (ffs(PCI_EXP_SLTCAP_PSN) - 1) - -#define PCI_EXP_SLTCTL_IND_RESERVED 0x0 -#define PCI_EXP_SLTCTL_IND_ON 0x1 -#define PCI_EXP_SLTCTL_IND_BLINK 0x2 -#define PCI_EXP_SLTCTL_IND_OFF 0x3 -#define PCI_EXP_SLTCTL_AIC_SHIFT (ffs(PCI_EXP_SLTCTL_AIC) - 1) -#define PCI_EXP_SLTCTL_AIC_OFF \ - (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT) - -#define PCI_EXP_SLTCTL_PIC_SHIFT (ffs(PCI_EXP_SLTCTL_PIC) - 1) -#define PCI_EXP_SLTCTL_PIC_OFF \ - (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT) - -#define PCI_EXP_SLTCTL_SUPPORTED \ - (PCI_EXP_SLTCTL_ABPE | \ - PCI_EXP_SLTCTL_PDCE | \ - PCI_EXP_SLTCTL_CCIE | \ - PCI_EXP_SLTCTL_HPIE | \ - PCI_EXP_SLTCTL_AIC | \ - PCI_EXP_SLTCTL_PCC | \ - PCI_EXP_SLTCTL_EIC) - -#define PCI_EXP_DEVCAP2_EFF 0x100000 -#define PCI_EXP_DEVCAP2_EETLPP 0x200000 - -#define PCI_EXP_DEVCTL2_EETLPPB 0x80 - -/* ARI */ -#define PCI_ARI_VER 1 -#define PCI_ARI_SIZEOF 8 - -/* AER */ -#define PCI_ERR_VER 2 -#define PCI_ERR_SIZEOF 0x48 - -#define PCI_ERR_UNC_SDN 0x00000020 /* surprise down */ -#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */ -#define PCI_ERR_UNC_INTN 0x00400000 /* Internal Error */ -#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC Blcoked TLP */ -#define PCI_ERR_UNC_ATOP_EBLOCKED 0x01000000 /* atomic op egress blocked */ -#define PCI_ERR_UNC_TLP_PRF_BLOCKED 0x02000000 /* TLP Prefix Blocked */ -#define PCI_ERR_COR_ADV_NONFATAL 0x00002000 /* Advisory Non-Fatal */ -#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected Internal */ -#define PCI_ERR_COR_HL_OVERFLOW 0x00008000 /* Header Long Overflow */ -#define PCI_ERR_CAP_FEP_MASK 0x0000001f -#define PCI_ERR_CAP_MHRC 0x00000200 -#define PCI_ERR_CAP_MHRE 0x00000400 -#define PCI_ERR_CAP_TLP 0x00000800 - -#define PCI_ERR_HEADER_LOG_SIZE 16 -#define PCI_ERR_TLP_PREFIX_LOG 0x38 -#define PCI_ERR_TLP_PREFIX_LOG_SIZE 16 - -#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR 0x4000 - -/* aer root error command/status */ -#define PCI_ERR_ROOT_CMD_EN_MASK (PCI_ERR_ROOT_CMD_COR_EN | \ - PCI_ERR_ROOT_CMD_NONFATAL_EN | \ - PCI_ERR_ROOT_CMD_FATAL_EN) - -#define PCI_ERR_ROOT_IRQ_MAX 32 -#define PCI_ERR_ROOT_IRQ 0xf8000000 -#define PCI_ERR_ROOT_IRQ_SHIFT (ffs(PCI_ERR_ROOT_IRQ) - 1) -#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV | \ - PCI_ERR_ROOT_MULTI_COR_RCV | \ - PCI_ERR_ROOT_UNCOR_RCV | \ - PCI_ERR_ROOT_MULTI_UNCOR_RCV | \ - PCI_ERR_ROOT_FIRST_FATAL | \ - PCI_ERR_ROOT_NONFATAL_RCV | \ - PCI_ERR_ROOT_FATAL_RCV) - -#define PCI_ERR_UNC_SUPPORTED (PCI_ERR_UNC_DLP | \ - PCI_ERR_UNC_SDN | \ - PCI_ERR_UNC_POISON_TLP | \ - PCI_ERR_UNC_FCP | \ - PCI_ERR_UNC_COMP_TIME | \ - PCI_ERR_UNC_COMP_ABORT | \ - PCI_ERR_UNC_UNX_COMP | \ - PCI_ERR_UNC_RX_OVER | \ - PCI_ERR_UNC_MALF_TLP | \ - PCI_ERR_UNC_ECRC | \ - PCI_ERR_UNC_UNSUP | \ - PCI_ERR_UNC_ACSV | \ - PCI_ERR_UNC_INTN | \ - PCI_ERR_UNC_MCBTLP | \ - PCI_ERR_UNC_ATOP_EBLOCKED | \ - PCI_ERR_UNC_TLP_PRF_BLOCKED) - -#define PCI_ERR_UNC_SEVERITY_DEFAULT (PCI_ERR_UNC_DLP | \ - PCI_ERR_UNC_SDN | \ - PCI_ERR_UNC_FCP | \ - PCI_ERR_UNC_RX_OVER | \ - PCI_ERR_UNC_MALF_TLP | \ - PCI_ERR_UNC_INTN) - -#define PCI_ERR_COR_SUPPORTED (PCI_ERR_COR_RCVR | \ - PCI_ERR_COR_BAD_TLP | \ - PCI_ERR_COR_BAD_DLLP | \ - PCI_ERR_COR_REP_ROLL | \ - PCI_ERR_COR_REP_TIMER | \ - PCI_ERR_COR_ADV_NONFATAL | \ - PCI_ERR_COR_INTERNAL | \ - PCI_ERR_COR_HL_OVERFLOW) - -#define PCI_ERR_COR_MASK_DEFAULT (PCI_ERR_COR_ADV_NONFATAL | \ - PCI_ERR_COR_INTERNAL | \ - PCI_ERR_COR_HL_OVERFLOW) - -#endif /* QEMU_PCIE_REGS_H */ diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 8fe2123..cb7cf8f 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -10,7 +10,7 @@ obj-y += ppc_newworld.o # IBM pSeries (sPAPR) obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o -obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o +obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o obj-$(CONFIG_PSERIES) += spapr_events.o # PowerPC 4xx boards obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o diff --git a/hw/shpc.c b/hw/shpc.c deleted file mode 100644 index 4597bbd..0000000 --- a/hw/shpc.c +++ /dev/null @@ -1,681 +0,0 @@ -#include <strings.h> -#include <stdint.h> -#include "range.h" -#include "range.h" -#include "shpc.h" -#include "pci.h" -#include "pci_internals.h" -#include "msi.h" - -/* TODO: model power only and disabled slot states. */ -/* TODO: handle SERR and wakeups */ -/* TODO: consider enabling 66MHz support */ - -/* TODO: remove fully only on state DISABLED and LED off. - * track state to properly record this. */ - -/* SHPC Working Register Set */ -#define SHPC_BASE_OFFSET 0x00 /* 4 bytes */ -#define SHPC_SLOTS_33 0x04 /* 4 bytes. Also encodes PCI-X slots. */ -#define SHPC_SLOTS_66 0x08 /* 4 bytes. */ -#define SHPC_NSLOTS 0x0C /* 1 byte */ -#define SHPC_FIRST_DEV 0x0D /* 1 byte */ -#define SHPC_PHYS_SLOT 0x0E /* 2 byte */ -#define SHPC_PHYS_NUM_MAX 0x7ff -#define SHPC_PHYS_NUM_UP 0x2000 -#define SHPC_PHYS_MRL 0x4000 -#define SHPC_PHYS_BUTTON 0x8000 -#define SHPC_SEC_BUS 0x10 /* 2 bytes */ -#define SHPC_SEC_BUS_33 0x0 -#define SHPC_SEC_BUS_66 0x1 /* Unused */ -#define SHPC_SEC_BUS_MASK 0x7 -#define SHPC_MSI_CTL 0x12 /* 1 byte */ -#define SHPC_PROG_IFC 0x13 /* 1 byte */ -#define SHPC_PROG_IFC_1_0 0x1 -#define SHPC_CMD_CODE 0x14 /* 1 byte */ -#define SHPC_CMD_TRGT 0x15 /* 1 byte */ -#define SHPC_CMD_TRGT_MIN 0x1 -#define SHPC_CMD_TRGT_MAX 0x1f -#define SHPC_CMD_STATUS 0x16 /* 2 bytes */ -#define SHPC_CMD_STATUS_BUSY 0x1 -#define SHPC_CMD_STATUS_MRL_OPEN 0x2 -#define SHPC_CMD_STATUS_INVALID_CMD 0x4 -#define SHPC_CMD_STATUS_INVALID_MODE 0x8 -#define SHPC_INT_LOCATOR 0x18 /* 4 bytes */ -#define SHPC_INT_COMMAND 0x1 -#define SHPC_SERR_LOCATOR 0x1C /* 4 bytes */ -#define SHPC_SERR_INT 0x20 /* 4 bytes */ -#define SHPC_INT_DIS 0x1 -#define SHPC_SERR_DIS 0x2 -#define SHPC_CMD_INT_DIS 0x4 -#define SHPC_ARB_SERR_DIS 0x8 -#define SHPC_CMD_DETECTED 0x10000 -#define SHPC_ARB_DETECTED 0x20000 - /* 4 bytes * slot # (start from 0) */ -#define SHPC_SLOT_REG(s) (0x24 + (s) * 4) - /* 2 bytes */ -#define SHPC_SLOT_STATUS(s) (0x0 + SHPC_SLOT_REG(s)) - -/* Same slot state masks are used for command and status registers */ -#define SHPC_SLOT_STATE_MASK 0x03 -#define SHPC_SLOT_STATE_SHIFT \ - (ffs(SHPC_SLOT_STATE_MASK) - 1) - -#define SHPC_STATE_NO 0x0 -#define SHPC_STATE_PWRONLY 0x1 -#define SHPC_STATE_ENABLED 0x2 -#define SHPC_STATE_DISABLED 0x3 - -#define SHPC_SLOT_PWR_LED_MASK 0xC -#define SHPC_SLOT_PWR_LED_SHIFT \ - (ffs(SHPC_SLOT_PWR_LED_MASK) - 1) -#define SHPC_SLOT_ATTN_LED_MASK 0x30 -#define SHPC_SLOT_ATTN_LED_SHIFT \ - (ffs(SHPC_SLOT_ATTN_LED_MASK) - 1) - -#define SHPC_LED_NO 0x0 -#define SHPC_LED_ON 0x1 -#define SHPC_LED_BLINK 0x2 -#define SHPC_LED_OFF 0x3 - -#define SHPC_SLOT_STATUS_PWR_FAULT 0x40 -#define SHPC_SLOT_STATUS_BUTTON 0x80 -#define SHPC_SLOT_STATUS_MRL_OPEN 0x100 -#define SHPC_SLOT_STATUS_66 0x200 -#define SHPC_SLOT_STATUS_PRSNT_MASK 0xC00 -#define SHPC_SLOT_STATUS_PRSNT_EMPTY 0x3 -#define SHPC_SLOT_STATUS_PRSNT_25W 0x1 -#define SHPC_SLOT_STATUS_PRSNT_15W 0x2 -#define SHPC_SLOT_STATUS_PRSNT_7_5W 0x0 - -#define SHPC_SLOT_STATUS_PRSNT_PCIX 0x3000 - - - /* 1 byte */ -#define SHPC_SLOT_EVENT_LATCH(s) (0x2 + SHPC_SLOT_REG(s)) - /* 1 byte */ -#define SHPC_SLOT_EVENT_SERR_INT_DIS(d, s) (0x3 + SHPC_SLOT_REG(s)) -#define SHPC_SLOT_EVENT_PRESENCE 0x01 -#define SHPC_SLOT_EVENT_ISOLATED_FAULT 0x02 -#define SHPC_SLOT_EVENT_BUTTON 0x04 -#define SHPC_SLOT_EVENT_MRL 0x08 -#define SHPC_SLOT_EVENT_CONNECTED_FAULT 0x10 -/* Bits below are used for Serr/Int disable only */ -#define SHPC_SLOT_EVENT_MRL_SERR_DIS 0x20 -#define SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS 0x40 - -#define SHPC_MIN_SLOTS 1 -#define SHPC_MAX_SLOTS 31 -#define SHPC_SIZEOF(d) SHPC_SLOT_REG((d)->shpc->nslots) - -/* SHPC Slot identifiers */ - -/* Hotplug supported at 31 slots out of the total 32. We reserve slot 0, - and give the rest of them physical *and* pci numbers starting from 1, so - they match logical numbers. Note: this means that multiple slots must have - different chassis number values, to make chassis+physical slot unique. - TODO: make this configurable? */ -#define SHPC_IDX_TO_LOGICAL(slot) ((slot) + 1) -#define SHPC_LOGICAL_TO_IDX(target) ((target) - 1) -#define SHPC_IDX_TO_PCI(slot) ((slot) + 1) -#define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1) -#define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1) - -static int roundup_pow_of_two(int x) -{ - x |= (x >> 1); - x |= (x >> 2); - x |= (x >> 4); - x |= (x >> 8); - x |= (x >> 16); - return x + 1; -} - -static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk) -{ - uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); - return (pci_get_word(status) & msk) >> (ffs(msk) - 1); -} - -static void shpc_set_status(SHPCDevice *shpc, - int slot, uint8_t value, uint16_t msk) -{ - uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); - pci_word_test_and_clear_mask(status, msk); - pci_word_test_and_set_mask(status, value << (ffs(msk) - 1)); -} - -static void shpc_interrupt_update(PCIDevice *d) -{ - SHPCDevice *shpc = d->shpc; - int slot; - int level = 0; - uint32_t serr_int; - uint32_t int_locator = 0; - - /* Update interrupt locator register */ - for (slot = 0; slot < shpc->nslots; ++slot) { - uint8_t event = shpc->config[SHPC_SLOT_EVENT_LATCH(slot)]; - uint8_t disable = shpc->config[SHPC_SLOT_EVENT_SERR_INT_DIS(d, slot)]; - uint32_t mask = 1 << SHPC_IDX_TO_LOGICAL(slot); - if (event & ~disable) { - int_locator |= mask; - } - } - serr_int = pci_get_long(shpc->config + SHPC_SERR_INT); - if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_DIS)) { - int_locator |= SHPC_INT_COMMAND; - } - pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator); - level = (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0; - if (msi_enabled(d) && shpc->msi_requested != level) - msi_notify(d, 0); - else - qemu_set_irq(d->irq[0], level); - shpc->msi_requested = level; -} - -static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed) -{ - switch (speed) { - case SHPC_SEC_BUS_33: - shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK; - shpc->config[SHPC_SEC_BUS] |= speed; - break; - default: - pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, - SHPC_CMD_STATUS_INVALID_MODE); - } -} - -void shpc_reset(PCIDevice *d) -{ - SHPCDevice *shpc = d->shpc; - int nslots = shpc->nslots; - int i; - memset(shpc->config, 0, SHPC_SIZEOF(d)); - pci_set_byte(shpc->config + SHPC_NSLOTS, nslots); - pci_set_long(shpc->config + SHPC_SLOTS_33, nslots); - pci_set_long(shpc->config + SHPC_SLOTS_66, 0); - pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0)); - pci_set_word(shpc->config + SHPC_PHYS_SLOT, - SHPC_IDX_TO_PHYSICAL(0) | - SHPC_PHYS_NUM_UP | - SHPC_PHYS_MRL | - SHPC_PHYS_BUTTON); - pci_set_long(shpc->config + SHPC_SERR_INT, SHPC_INT_DIS | - SHPC_SERR_DIS | - SHPC_CMD_INT_DIS | - SHPC_ARB_SERR_DIS); - pci_set_byte(shpc->config + SHPC_PROG_IFC, SHPC_PROG_IFC_1_0); - pci_set_word(shpc->config + SHPC_SEC_BUS, SHPC_SEC_BUS_33); - for (i = 0; i < shpc->nslots; ++i) { - pci_set_byte(shpc->config + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), - SHPC_SLOT_EVENT_PRESENCE | - SHPC_SLOT_EVENT_ISOLATED_FAULT | - SHPC_SLOT_EVENT_BUTTON | - SHPC_SLOT_EVENT_MRL | - SHPC_SLOT_EVENT_CONNECTED_FAULT | - SHPC_SLOT_EVENT_MRL_SERR_DIS | - SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); - if (shpc->sec_bus->devices[PCI_DEVFN(SHPC_IDX_TO_PCI(i), 0)]) { - shpc_set_status(shpc, i, SHPC_STATE_ENABLED, SHPC_SLOT_STATE_MASK); - shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_MRL_OPEN); - shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_7_5W, - SHPC_SLOT_STATUS_PRSNT_MASK); - shpc_set_status(shpc, i, SHPC_LED_ON, SHPC_SLOT_PWR_LED_MASK); - } else { - shpc_set_status(shpc, i, SHPC_STATE_DISABLED, SHPC_SLOT_STATE_MASK); - shpc_set_status(shpc, i, 1, SHPC_SLOT_STATUS_MRL_OPEN); - shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_EMPTY, - SHPC_SLOT_STATUS_PRSNT_MASK); - shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK); - } - shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66); - } - shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33); - shpc->msi_requested = 0; - shpc_interrupt_update(d); -} - -static void shpc_invalid_command(SHPCDevice *shpc) -{ - pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, - SHPC_CMD_STATUS_INVALID_CMD); -} - -static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot) -{ - int devfn; - int pci_slot = SHPC_IDX_TO_PCI(slot); - for (devfn = PCI_DEVFN(pci_slot, 0); - devfn <= PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1); - ++devfn) { - PCIDevice *affected_dev = shpc->sec_bus->devices[devfn]; - if (affected_dev) { - qdev_free(&affected_dev->qdev); - } - } -} - -static void shpc_slot_command(SHPCDevice *shpc, uint8_t target, - uint8_t state, uint8_t power, uint8_t attn) -{ - uint8_t current_state; - int slot = SHPC_LOGICAL_TO_IDX(target); - if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) { - shpc_invalid_command(shpc); - return; - } - current_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); - if (current_state == SHPC_STATE_ENABLED && state == SHPC_STATE_PWRONLY) { - shpc_invalid_command(shpc); - return; - } - - switch (power) { - case SHPC_LED_NO: - break; - default: - /* TODO: send event to monitor */ - shpc_set_status(shpc, slot, power, SHPC_SLOT_PWR_LED_MASK); - } - switch (attn) { - case SHPC_LED_NO: - break; - default: - /* TODO: send event to monitor */ - shpc_set_status(shpc, slot, attn, SHPC_SLOT_ATTN_LED_MASK); - } - - if ((current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_PWRONLY) || - (current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_ENABLED)) { - shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); - } else if ((current_state == SHPC_STATE_ENABLED || - current_state == SHPC_STATE_PWRONLY) && - state == SHPC_STATE_DISABLED) { - shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); - power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); - /* TODO: track what monitor requested. */ - /* Look at LED to figure out whether it's ok to remove the device. */ - if (power == SHPC_LED_OFF) { - shpc_free_devices_in_slot(shpc, slot); - shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, - SHPC_SLOT_STATUS_PRSNT_MASK); - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= - SHPC_SLOT_EVENT_BUTTON | - SHPC_SLOT_EVENT_MRL | - SHPC_SLOT_EVENT_PRESENCE; - } - } -} - -static void shpc_command(SHPCDevice *shpc) -{ - uint8_t code = pci_get_byte(shpc->config + SHPC_CMD_CODE); - uint8_t speed; - uint8_t target; - uint8_t attn; - uint8_t power; - uint8_t state; - int i; - - /* Clear status from the previous command. */ - pci_word_test_and_clear_mask(shpc->config + SHPC_CMD_STATUS, - SHPC_CMD_STATUS_BUSY | - SHPC_CMD_STATUS_MRL_OPEN | - SHPC_CMD_STATUS_INVALID_CMD | - SHPC_CMD_STATUS_INVALID_MODE); - switch (code) { - case 0x00 ... 0x3f: - target = shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX; - state = (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_SHIFT; - power = (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_LED_SHIFT; - attn = (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_LED_SHIFT; - shpc_slot_command(shpc, target, state, power, attn); - break; - case 0x40 ... 0x47: - speed = code & SHPC_SEC_BUS_MASK; - shpc_set_sec_bus_speed(shpc, speed); - break; - case 0x48: - /* Power only all slots */ - /* first verify no slots are enabled */ - for (i = 0; i < shpc->nslots; ++i) { - state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); - if (state == SHPC_STATE_ENABLED) { - shpc_invalid_command(shpc); - goto done; - } - } - for (i = 0; i < shpc->nslots; ++i) { - if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, - SHPC_STATE_PWRONLY, SHPC_LED_ON, SHPC_LED_NO); - } else { - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, - SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); - } - } - break; - case 0x49: - /* Enable all slots */ - /* TODO: Spec says this shall fail if some are already enabled. - * This doesn't make sense - why not? a spec bug? */ - for (i = 0; i < shpc->nslots; ++i) { - state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); - if (state == SHPC_STATE_ENABLED) { - shpc_invalid_command(shpc); - goto done; - } - } - for (i = 0; i < shpc->nslots; ++i) { - if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, - SHPC_STATE_ENABLED, SHPC_LED_ON, SHPC_LED_NO); - } else { - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, - SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); - } - } - break; - default: - shpc_invalid_command(shpc); - break; - } -done: - pci_long_test_and_set_mask(shpc->config + SHPC_SERR_INT, SHPC_CMD_DETECTED); -} - -static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, int l) -{ - SHPCDevice *shpc = d->shpc; - int i; - if (addr >= SHPC_SIZEOF(d)) { - return; - } - l = MIN(l, SHPC_SIZEOF(d) - addr); - - /* TODO: code duplicated from pci.c */ - for (i = 0; i < l; val >>= 8, ++i) { - unsigned a = addr + i; - uint8_t wmask = shpc->wmask[a]; - uint8_t w1cmask = shpc->w1cmask[a]; - assert(!(wmask & w1cmask)); - shpc->config[a] = (shpc->config[a] & ~wmask) | (val & wmask); - shpc->config[a] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ - } - if (ranges_overlap(addr, l, SHPC_CMD_CODE, 2)) { - shpc_command(shpc); - } - shpc_interrupt_update(d); -} - -static uint64_t shpc_read(PCIDevice *d, unsigned addr, int l) -{ - uint64_t val = 0x0; - if (addr >= SHPC_SIZEOF(d)) { - return val; - } - l = MIN(l, SHPC_SIZEOF(d) - addr); - memcpy(&val, d->shpc->config + addr, l); - return val; -} - -/* SHPC Bridge Capability */ -#define SHPC_CAP_LENGTH 0x08 -#define SHPC_CAP_DWORD_SELECT 0x2 /* 1 byte */ -#define SHPC_CAP_CxP 0x3 /* 1 byte: CSP, CIP */ -#define SHPC_CAP_DWORD_DATA 0x4 /* 4 bytes */ -#define SHPC_CAP_CSP_MASK 0x4 -#define SHPC_CAP_CIP_MASK 0x8 - -static uint8_t shpc_cap_dword(PCIDevice *d) -{ - return pci_get_byte(d->config + d->shpc->cap + SHPC_CAP_DWORD_SELECT); -} - -/* Update dword data capability register */ -static void shpc_cap_update_dword(PCIDevice *d) -{ - unsigned data; - data = shpc_read(d, shpc_cap_dword(d) * 4, 4); - pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, data); -} - -/* Add SHPC capability to the config space for the device. */ -static int shpc_cap_add_config(PCIDevice *d) -{ - uint8_t *config; - int config_offset; - config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC, - 0, SHPC_CAP_LENGTH); - if (config_offset < 0) { - return config_offset; - } - config = d->config + config_offset; - - pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0); - pci_set_byte(config + SHPC_CAP_CxP, 0); - pci_set_long(config + SHPC_CAP_DWORD_DATA, 0); - d->shpc->cap = config_offset; - /* Make dword select and data writeable. */ - pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff); - pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff); - return 0; -} - -static uint64_t shpc_mmio_read(void *opaque, hwaddr addr, - unsigned size) -{ - return shpc_read(opaque, addr, size); -} - -static void shpc_mmio_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - shpc_write(opaque, addr, val, size); -} - -static const MemoryRegionOps shpc_mmio_ops = { - .read = shpc_mmio_read, - .write = shpc_mmio_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - /* SHPC ECN requires dword accesses, but the original 1.0 spec doesn't. - * It's easier to suppport all sizes than worry about it. */ - .min_access_size = 1, - .max_access_size = 4, - }, -}; - -static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev, - PCIHotplugState hotplug_state) -{ - int pci_slot = PCI_SLOT(affected_dev->devfn); - uint8_t state; - uint8_t led; - PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); - SHPCDevice *shpc = d->shpc; - int slot = SHPC_PCI_TO_IDX(pci_slot); - if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) { - error_report("Unsupported PCI slot %d for standard hotplug " - "controller. Valid slots are between %d and %d.", - pci_slot, SHPC_IDX_TO_PCI(0), - SHPC_IDX_TO_PCI(shpc->nslots) - 1); - return -1; - } - /* Don't send event when device is enabled during qemu machine creation: - * it is present on boot, no hotplug event is necessary. We do send an - * event when the device is disabled later. */ - if (hotplug_state == PCI_COLDPLUG_ENABLED) { - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, - SHPC_SLOT_STATUS_PRSNT_MASK); - return 0; - } - if (hotplug_state == PCI_HOTPLUG_DISABLED) { - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON; - state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); - led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); - if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) { - shpc_free_devices_in_slot(shpc, slot); - shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, - SHPC_SLOT_STATUS_PRSNT_MASK); - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= - SHPC_SLOT_EVENT_MRL | - SHPC_SLOT_EVENT_PRESENCE; - } - } else { - /* This could be a cancellation of the previous removal. - * We check MRL state to figure out. */ - if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) { - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, - SHPC_SLOT_STATUS_PRSNT_MASK); - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= - SHPC_SLOT_EVENT_BUTTON | - SHPC_SLOT_EVENT_MRL | - SHPC_SLOT_EVENT_PRESENCE; - } else { - /* Press attention button to cancel removal */ - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= - SHPC_SLOT_EVENT_BUTTON; - } - } - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66); - shpc_interrupt_update(d); - return 0; -} - -/* Initialize the SHPC structure in bridge's BAR. */ -int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset) -{ - int i, ret; - int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */ - SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc)); - shpc->sec_bus = sec_bus; - ret = shpc_cap_add_config(d); - if (ret) { - g_free(d->shpc); - return ret; - } - if (nslots < SHPC_MIN_SLOTS) { - return 0; - } - if (nslots > SHPC_MAX_SLOTS || - SHPC_IDX_TO_PCI(nslots) > PCI_SLOT_MAX) { - /* TODO: report an error mesage that makes sense. */ - return -EINVAL; - } - shpc->nslots = nslots; - shpc->config = g_malloc0(SHPC_SIZEOF(d)); - shpc->cmask = g_malloc0(SHPC_SIZEOF(d)); - shpc->wmask = g_malloc0(SHPC_SIZEOF(d)); - shpc->w1cmask = g_malloc0(SHPC_SIZEOF(d)); - - shpc_reset(d); - - pci_set_long(shpc->config + SHPC_BASE_OFFSET, offset); - - pci_set_byte(shpc->wmask + SHPC_CMD_CODE, 0xff); - pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); - pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); - pci_set_long(shpc->wmask + SHPC_SERR_INT, - SHPC_INT_DIS | - SHPC_SERR_DIS | - SHPC_CMD_INT_DIS | - SHPC_ARB_SERR_DIS); - pci_set_long(shpc->w1cmask + SHPC_SERR_INT, - SHPC_CMD_DETECTED | - SHPC_ARB_DETECTED); - for (i = 0; i < nslots; ++i) { - pci_set_byte(shpc->wmask + - SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), - SHPC_SLOT_EVENT_PRESENCE | - SHPC_SLOT_EVENT_ISOLATED_FAULT | - SHPC_SLOT_EVENT_BUTTON | - SHPC_SLOT_EVENT_MRL | - SHPC_SLOT_EVENT_CONNECTED_FAULT | - SHPC_SLOT_EVENT_MRL_SERR_DIS | - SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); - pci_set_byte(shpc->w1cmask + - SHPC_SLOT_EVENT_LATCH(i), - SHPC_SLOT_EVENT_PRESENCE | - SHPC_SLOT_EVENT_ISOLATED_FAULT | - SHPC_SLOT_EVENT_BUTTON | - SHPC_SLOT_EVENT_MRL | - SHPC_SLOT_EVENT_CONNECTED_FAULT); - } - - /* TODO: init cmask */ - memory_region_init_io(&shpc->mmio, &shpc_mmio_ops, d, "shpc-mmio", - SHPC_SIZEOF(d)); - shpc_cap_update_dword(d); - memory_region_add_subregion(bar, offset, &shpc->mmio); - pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev); - - d->cap_present |= QEMU_PCI_CAP_SHPC; - return 0; -} - -int shpc_bar_size(PCIDevice *d) -{ - return roundup_pow_of_two(SHPC_SLOT_REG(SHPC_MAX_SLOTS)); -} - -void shpc_cleanup(PCIDevice *d, MemoryRegion *bar) -{ - SHPCDevice *shpc = d->shpc; - d->cap_present &= ~QEMU_PCI_CAP_SHPC; - memory_region_del_subregion(bar, &shpc->mmio); - /* TODO: cleanup config space changes? */ - g_free(shpc->config); - g_free(shpc->cmask); - g_free(shpc->wmask); - g_free(shpc->w1cmask); - memory_region_destroy(&shpc->mmio); - g_free(shpc); -} - -void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) -{ - if (!ranges_overlap(addr, l, d->shpc->cap, SHPC_CAP_LENGTH)) { - return; - } - if (ranges_overlap(addr, l, d->shpc->cap + SHPC_CAP_DWORD_DATA, 4)) { - unsigned dword_data; - dword_data = pci_get_long(d->shpc->config + d->shpc->cap - + SHPC_CAP_DWORD_DATA); - shpc_write(d, shpc_cap_dword(d) * 4, dword_data, 4); - } - /* Update cap dword data in case guest is going to read it. */ - shpc_cap_update_dword(d); -} - -static void shpc_save(QEMUFile *f, void *pv, size_t size) -{ - PCIDevice *d = container_of(pv, PCIDevice, shpc); - qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); -} - -static int shpc_load(QEMUFile *f, void *pv, size_t size) -{ - PCIDevice *d = container_of(pv, PCIDevice, shpc); - int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); - if (ret != SHPC_SIZEOF(d)) { - return -EINVAL; - } - /* Make sure we don't lose notifications. An extra interrupt is harmless. */ - d->shpc->msi_requested = 0; - shpc_interrupt_update(d); - return 0; -} - -VMStateInfo shpc_vmstate_info = { - .name = "shpc", - .get = shpc_load, - .put = shpc_save, -}; diff --git a/hw/shpc.h b/hw/shpc.h deleted file mode 100644 index 130b71d..0000000 --- a/hw/shpc.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef SHPC_H -#define SHPC_H - -#include "qemu-common.h" -#include "memory.h" -#include "vmstate.h" - -struct SHPCDevice { - /* Capability offset in device's config space */ - int cap; - - /* # of hot-pluggable slots */ - int nslots; - - /* SHPC WRS: working register set */ - uint8_t *config; - - /* Used to enable checks on load. Note that writable bits are - * never checked even if set in cmask. */ - uint8_t *cmask; - - /* Used to implement R/W bytes */ - uint8_t *wmask; - - /* Used to implement RW1C(Write 1 to Clear) bytes */ - uint8_t *w1cmask; - - /* MMIO for the SHPC BAR */ - MemoryRegion mmio; - - /* Bus controlled by this SHPC */ - PCIBus *sec_bus; - - /* MSI already requested for this event */ - int msi_requested; -}; - -void shpc_reset(PCIDevice *d); -int shpc_bar_size(PCIDevice *dev); -int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off); -void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar); -void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len); - -extern VMStateInfo shpc_vmstate_info; -#define SHPC_VMSTATE(_field, _type) \ - VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0) - -#endif diff --git a/hw/slotid_cap.c b/hw/slotid_cap.c deleted file mode 100644 index 0106452..0000000 --- a/hw/slotid_cap.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "slotid_cap.h" -#include "pci.h" - -#define SLOTID_CAP_LENGTH 4 -#define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1) - -int slotid_cap_init(PCIDevice *d, int nslots, - uint8_t chassis, - unsigned offset) -{ - int cap; - if (!chassis) { - error_report("Bridge chassis not specified. Each bridge is required " - "to be assigned a unique chassis id > 0."); - return -EINVAL; - } - if (nslots < 0 || nslots > (PCI_SID_ESR_NSLOTS >> SLOTID_NSLOTS_SHIFT)) { - /* TODO: error report? */ - return -EINVAL; - } - - cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset, SLOTID_CAP_LENGTH); - if (cap < 0) { - return cap; - } - /* We make each chassis unique, this way each bridge is First in Chassis */ - d->config[cap + PCI_SID_ESR] = PCI_SID_ESR_FIC | - (nslots << SLOTID_NSLOTS_SHIFT); - d->cmask[cap + PCI_SID_ESR] = 0xff; - d->config[cap + PCI_SID_CHASSIS_NR] = chassis; - /* Note: Chassis number register is non-volatile, - so we don't reset it. */ - /* TODO: store in eeprom? */ - d->wmask[cap + PCI_SID_CHASSIS_NR] = 0xff; - - d->cap_present |= QEMU_PCI_CAP_SLOTID; - return 0; -} - -void slotid_cap_cleanup(PCIDevice *d) -{ - /* TODO: cleanup config space? */ - d->cap_present &= ~QEMU_PCI_CAP_SLOTID; -} diff --git a/hw/slotid_cap.h b/hw/slotid_cap.h deleted file mode 100644 index 70db047..0000000 --- a/hw/slotid_cap.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef PCI_SLOTID_CAP_H -#define PCI_SLOTID_CAP_H - -#include "qemu-common.h" - -int slotid_cap_init(PCIDevice *dev, int nslots, - uint8_t chassis, - unsigned offset); -void slotid_cap_cleanup(PCIDevice *dev); - -#endif -- MST ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci 2012-12-12 13:14 ` [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci Michael S. Tsirkin @ 2012-12-12 19:53 ` Blue Swirl 2012-12-12 20:56 ` Michael S. Tsirkin 0 siblings, 1 reply; 19+ messages in thread From: Blue Swirl @ 2012-12-12 19:53 UTC (permalink / raw) To: Michael S. Tsirkin; +Cc: qemu-devel On Wed, Dec 12, 2012 at 1:14 PM, Michael S. Tsirkin <mst@redhat.com> wrote: > Move files and modify makefiles to pick them at the > new location. Please fix coding style before moving. For easier review, please use git flag -M to detect renames. > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com> > --- > hw/Makefile.objs | 10 +- > hw/i386/Makefile.objs | 2 +- > hw/msi.c | 395 --------- > hw/msi.h | 50 -- > hw/msix.c | 562 ------------- > hw/msix.h | 41 - > hw/pci-hotplug.c | 293 ------- > hw/pci-stub.c | 47 -- > hw/pci.c | 2168 ------------------------------------------------ > hw/pci.h | 684 --------------- > hw/pci/Makefile.objs | 6 + > hw/pci/msi.c | 395 +++++++++ > hw/pci/msi.h | 50 ++ > hw/pci/msix.c | 562 +++++++++++++ > hw/pci/msix.h | 41 + > hw/pci/pci-hotplug.c | 293 +++++++ > hw/pci/pci-stub.c | 47 ++ > hw/pci/pci.c | 2168 ++++++++++++++++++++++++++++++++++++++++++++++++ > hw/pci/pci.h | 684 +++++++++++++++ > hw/pci/pci_bridge.c | 363 ++++++++ > hw/pci/pci_bridge.h | 66 ++ > hw/pci/pci_host.c | 180 ++++ > hw/pci/pci_host.h | 62 ++ > hw/pci/pci_ids.h | 147 ++++ > hw/pci/pci_internals.h | 78 ++ > hw/pci/pci_regs.h | 717 ++++++++++++++++ > hw/pci/pcie.c | 555 +++++++++++++ > hw/pci/pcie.h | 142 ++++ > hw/pci/pcie_aer.c | 1032 +++++++++++++++++++++++ > hw/pci/pcie_aer.h | 106 +++ > hw/pci/pcie_host.c | 161 ++++ > hw/pci/pcie_host.h | 54 ++ > hw/pci/pcie_port.c | 114 +++ > hw/pci/pcie_port.h | 51 ++ > hw/pci/pcie_regs.h | 156 ++++ > hw/pci/shpc.c | 681 +++++++++++++++ > hw/pci/shpc.h | 48 ++ > hw/pci/slotid_cap.c | 44 + > hw/pci/slotid_cap.h | 11 + > hw/pci_bridge.c | 363 -------- > hw/pci_bridge.h | 66 -- > hw/pci_host.c | 180 ---- > hw/pci_host.h | 62 -- > hw/pci_ids.h | 147 ---- > hw/pci_internals.h | 78 -- > hw/pci_regs.h | 717 ---------------- > hw/pcie.c | 555 ------------- > hw/pcie.h | 142 ---- > hw/pcie_aer.c | 1032 ----------------------- > hw/pcie_aer.h | 106 --- > hw/pcie_host.c | 161 ---- > hw/pcie_host.h | 54 -- > hw/pcie_port.c | 114 --- > hw/pcie_port.h | 51 -- > hw/pcie_regs.h | 156 ---- > hw/ppc/Makefile.objs | 2 +- > hw/shpc.c | 681 --------------- > hw/shpc.h | 48 -- > hw/slotid_cap.c | 44 - > hw/slotid_cap.h | 11 - > 60 files changed, 9018 insertions(+), 9018 deletions(-) > delete mode 100644 hw/msi.c > delete mode 100644 hw/msi.h > delete mode 100644 hw/msix.c > delete mode 100644 hw/msix.h > delete mode 100644 hw/pci-hotplug.c > delete mode 100644 hw/pci-stub.c > delete mode 100644 hw/pci.c > delete mode 100644 hw/pci.h > create mode 100644 hw/pci/Makefile.objs > create mode 100644 hw/pci/msi.c > create mode 100644 hw/pci/msi.h > create mode 100644 hw/pci/msix.c > create mode 100644 hw/pci/msix.h > create mode 100644 hw/pci/pci-hotplug.c > create mode 100644 hw/pci/pci-stub.c > create mode 100644 hw/pci/pci.c > create mode 100644 hw/pci/pci.h > create mode 100644 hw/pci/pci_bridge.c > create mode 100644 hw/pci/pci_bridge.h > create mode 100644 hw/pci/pci_host.c > create mode 100644 hw/pci/pci_host.h > create mode 100644 hw/pci/pci_ids.h > create mode 100644 hw/pci/pci_internals.h > create mode 100644 hw/pci/pci_regs.h > create mode 100644 hw/pci/pcie.c > create mode 100644 hw/pci/pcie.h > create mode 100644 hw/pci/pcie_aer.c > create mode 100644 hw/pci/pcie_aer.h > create mode 100644 hw/pci/pcie_host.c > create mode 100644 hw/pci/pcie_host.h > create mode 100644 hw/pci/pcie_port.c > create mode 100644 hw/pci/pcie_port.h > create mode 100644 hw/pci/pcie_regs.h > create mode 100644 hw/pci/shpc.c > create mode 100644 hw/pci/shpc.h > create mode 100644 hw/pci/slotid_cap.c > create mode 100644 hw/pci/slotid_cap.h > delete mode 100644 hw/pci_bridge.c > delete mode 100644 hw/pci_bridge.h > delete mode 100644 hw/pci_host.c > delete mode 100644 hw/pci_host.h > delete mode 100644 hw/pci_ids.h > delete mode 100644 hw/pci_internals.h > delete mode 100644 hw/pci_regs.h > delete mode 100644 hw/pcie.c > delete mode 100644 hw/pcie.h > delete mode 100644 hw/pcie_aer.c > delete mode 100644 hw/pcie_aer.h > delete mode 100644 hw/pcie_host.c > delete mode 100644 hw/pcie_host.h > delete mode 100644 hw/pcie_port.c > delete mode 100644 hw/pcie_port.h > delete mode 100644 hw/pcie_regs.h > delete mode 100644 hw/shpc.c > delete mode 100644 hw/shpc.h > delete mode 100644 hw/slotid_cap.c > delete mode 100644 hw/slotid_cap.h > > diff --git a/hw/Makefile.objs b/hw/Makefile.objs > index d581d8d..228acd6 100644 > --- a/hw/Makefile.objs > +++ b/hw/Makefile.objs > @@ -1,14 +1,10 @@ > -common-obj-y = usb/ ide/ > +common-obj-y = usb/ ide/ pci/ > common-obj-y += loader.o > common-obj-$(CONFIG_VIRTIO) += virtio-console.o > common-obj-$(CONFIG_VIRTIO) += virtio-rng.o > common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o > common-obj-y += fw_cfg.o > -common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o > -common-obj-$(CONFIG_PCI) += msix.o msi.o > -common-obj-$(CONFIG_PCI) += shpc.o > -common-obj-$(CONFIG_PCI) += slotid_cap.o > -common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o > +common-obj-$(CONFIG_PCI) += pci_bridge_dev.o > common-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o > common-obj-$(CONFIG_PCI) += i82801b11.o > common-obj-y += watchdog.o > @@ -102,8 +98,6 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o > # PCI watchdog devices > common-obj-$(CONFIG_PCI) += wdt_i6300esb.o > > -common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o > - > # PCI network cards > common-obj-$(CONFIG_NE2000_PCI) += ne2000.o > common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o > diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs > index 0d3f6a8..257f3c1 100644 > --- a/hw/i386/Makefile.objs > +++ b/hw/i386/Makefile.objs > @@ -2,7 +2,7 @@ obj-y += mc146818rtc.o pc.o > obj-y += apic_common.o apic.o kvmvapic.o > obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o > obj-y += vmport.o > -obj-y += pci-hotplug.o smbios.o wdt_ib700.o > +obj-y += pci/pci-hotplug.o smbios.o wdt_ib700.o > obj-y += debugcon.o multiboot.o > obj-y += pc_piix.o > obj-y += pc_sysfw.o > diff --git a/hw/msi.c b/hw/msi.c > deleted file mode 100644 > index 33037a8..0000000 > --- a/hw/msi.c > +++ /dev/null > @@ -1,395 +0,0 @@ > -/* > - * msi.c > - * > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#include "msi.h" > -#include "range.h" > - > -/* Eventually those constants should go to Linux pci_regs.h */ > -#define PCI_MSI_PENDING_32 0x10 > -#define PCI_MSI_PENDING_64 0x14 > - > -/* PCI_MSI_ADDRESS_LO */ > -#define PCI_MSI_ADDRESS_LO_MASK (~0x3) > - > -/* If we get rid of cap allocator, we won't need those. */ > -#define PCI_MSI_32_SIZEOF 0x0a > -#define PCI_MSI_64_SIZEOF 0x0e > -#define PCI_MSI_32M_SIZEOF 0x14 > -#define PCI_MSI_64M_SIZEOF 0x18 > - > -#define PCI_MSI_VECTORS_MAX 32 > - > -/* Flag for interrupt controller to declare MSI/MSI-X support */ > -bool msi_supported; > - > -/* If we get rid of cap allocator, we won't need this. */ > -static inline uint8_t msi_cap_sizeof(uint16_t flags) > -{ > - switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) { > - case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT: > - return PCI_MSI_64M_SIZEOF; > - case PCI_MSI_FLAGS_64BIT: > - return PCI_MSI_64_SIZEOF; > - case PCI_MSI_FLAGS_MASKBIT: > - return PCI_MSI_32M_SIZEOF; > - case 0: > - return PCI_MSI_32_SIZEOF; > - default: > - abort(); > - break; > - } > - return 0; > -} > - > -//#define MSI_DEBUG > - > -#ifdef MSI_DEBUG > -# define MSI_DPRINTF(fmt, ...) \ > - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > -#else > -# define MSI_DPRINTF(fmt, ...) do { } while (0) > -#endif > -#define MSI_DEV_PRINTF(dev, fmt, ...) \ > - MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > - > -static inline unsigned int msi_nr_vectors(uint16_t flags) > -{ > - return 1U << > - ((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1)); > -} > - > -static inline uint8_t msi_flags_off(const PCIDevice* dev) > -{ > - return dev->msi_cap + PCI_MSI_FLAGS; > -} > - > -static inline uint8_t msi_address_lo_off(const PCIDevice* dev) > -{ > - return dev->msi_cap + PCI_MSI_ADDRESS_LO; > -} > - > -static inline uint8_t msi_address_hi_off(const PCIDevice* dev) > -{ > - return dev->msi_cap + PCI_MSI_ADDRESS_HI; > -} > - > -static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit) > -{ > - return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32); > -} > - > -static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit) > -{ > - return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32); > -} > - > -static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit) > -{ > - return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_PENDING_32); > -} > - > -/* > - * Special API for POWER to configure the vectors through > - * a side channel. Should never be used by devices. > - */ > -void msi_set_message(PCIDevice *dev, MSIMessage msg) > -{ > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > - > - if (msi64bit) { > - pci_set_quad(dev->config + msi_address_lo_off(dev), msg.address); > - } else { > - pci_set_long(dev->config + msi_address_lo_off(dev), msg.address); > - } > - pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data); > -} > - > -MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) > -{ > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > - unsigned int nr_vectors = msi_nr_vectors(flags); > - MSIMessage msg; > - > - assert(vector < nr_vectors); > - > - if (msi64bit) { > - msg.address = pci_get_quad(dev->config + msi_address_lo_off(dev)); > - } else { > - msg.address = pci_get_long(dev->config + msi_address_lo_off(dev)); > - } > - > - /* upper bit 31:16 is zero */ > - msg.data = pci_get_word(dev->config + msi_data_off(dev, msi64bit)); > - if (nr_vectors > 1) { > - msg.data &= ~(nr_vectors - 1); > - msg.data |= vector; > - } > - > - return msg; > -} > - > -bool msi_enabled(const PCIDevice *dev) > -{ > - return msi_present(dev) && > - (pci_get_word(dev->config + msi_flags_off(dev)) & > - PCI_MSI_FLAGS_ENABLE); > -} > - > -int msi_init(struct PCIDevice *dev, uint8_t offset, > - unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask) > -{ > - unsigned int vectors_order; > - uint16_t flags; > - uint8_t cap_size; > - int config_offset; > - > - if (!msi_supported) { > - return -ENOTSUP; > - } > - > - MSI_DEV_PRINTF(dev, > - "init offset: 0x%"PRIx8" vector: %"PRId8 > - " 64bit %d mask %d\n", > - offset, nr_vectors, msi64bit, msi_per_vector_mask); > - > - assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */ > - assert(nr_vectors > 0); > - assert(nr_vectors <= PCI_MSI_VECTORS_MAX); > - /* the nr of MSI vectors is up to 32 */ > - vectors_order = ffs(nr_vectors) - 1; > - > - flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1); > - if (msi64bit) { > - flags |= PCI_MSI_FLAGS_64BIT; > - } > - if (msi_per_vector_mask) { > - flags |= PCI_MSI_FLAGS_MASKBIT; > - } > - > - cap_size = msi_cap_sizeof(flags); > - config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size); > - if (config_offset < 0) { > - return config_offset; > - } > - > - dev->msi_cap = config_offset; > - dev->cap_present |= QEMU_PCI_CAP_MSI; > - > - pci_set_word(dev->config + msi_flags_off(dev), flags); > - pci_set_word(dev->wmask + msi_flags_off(dev), > - PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); > - pci_set_long(dev->wmask + msi_address_lo_off(dev), > - PCI_MSI_ADDRESS_LO_MASK); > - if (msi64bit) { > - pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff); > - } > - pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff); > - > - if (msi_per_vector_mask) { > - /* Make mask bits 0 to nr_vectors - 1 writable. */ > - pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit), > - 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors)); > - } > - return config_offset; > -} > - > -void msi_uninit(struct PCIDevice *dev) > -{ > - uint16_t flags; > - uint8_t cap_size; > - > - if (!msi_present(dev)) { > - return; > - } > - flags = pci_get_word(dev->config + msi_flags_off(dev)); > - cap_size = msi_cap_sizeof(flags); > - pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size); > - dev->cap_present &= ~QEMU_PCI_CAP_MSI; > - > - MSI_DEV_PRINTF(dev, "uninit\n"); > -} > - > -void msi_reset(PCIDevice *dev) > -{ > - uint16_t flags; > - bool msi64bit; > - > - if (!msi_present(dev)) { > - return; > - } > - > - flags = pci_get_word(dev->config + msi_flags_off(dev)); > - flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); > - msi64bit = flags & PCI_MSI_FLAGS_64BIT; > - > - pci_set_word(dev->config + msi_flags_off(dev), flags); > - pci_set_long(dev->config + msi_address_lo_off(dev), 0); > - if (msi64bit) { > - pci_set_long(dev->config + msi_address_hi_off(dev), 0); > - } > - pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0); > - if (flags & PCI_MSI_FLAGS_MASKBIT) { > - pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0); > - pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0); > - } > - MSI_DEV_PRINTF(dev, "reset\n"); > -} > - > -static bool msi_is_masked(const PCIDevice *dev, unsigned int vector) > -{ > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > - uint32_t mask; > - assert(vector < PCI_MSI_VECTORS_MAX); > - > - if (!(flags & PCI_MSI_FLAGS_MASKBIT)) { > - return false; > - } > - > - mask = pci_get_long(dev->config + > - msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT)); > - return mask & (1U << vector); > -} > - > -void msi_notify(PCIDevice *dev, unsigned int vector) > -{ > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > - unsigned int nr_vectors = msi_nr_vectors(flags); > - MSIMessage msg; > - > - assert(vector < nr_vectors); > - if (msi_is_masked(dev, vector)) { > - assert(flags & PCI_MSI_FLAGS_MASKBIT); > - pci_long_test_and_set_mask( > - dev->config + msi_pending_off(dev, msi64bit), 1U << vector); > - MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector); > - return; > - } > - > - msg = msi_get_message(dev, vector); > - > - MSI_DEV_PRINTF(dev, > - "notify vector 0x%x" > - " address: 0x%"PRIx64" data: 0x%"PRIx32"\n", > - vector, msg.address, msg.data); > - stl_le_phys(msg.address, msg.data); > -} > - > -/* Normally called by pci_default_write_config(). */ > -void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len) > -{ > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > - bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT; > - unsigned int nr_vectors; > - uint8_t log_num_vecs; > - uint8_t log_max_vecs; > - unsigned int vector; > - uint32_t pending; > - > - if (!msi_present(dev) || > - !ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) { > - return; > - } > - > -#ifdef MSI_DEBUG > - MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n", > - addr, val, len); > - MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32, > - flags, > - pci_get_long(dev->config + msi_address_lo_off(dev))); > - if (msi64bit) { > - fprintf(stderr, " address-hi: 0x%"PRIx32, > - pci_get_long(dev->config + msi_address_hi_off(dev))); > - } > - fprintf(stderr, " data: 0x%"PRIx16, > - pci_get_word(dev->config + msi_data_off(dev, msi64bit))); > - if (flags & PCI_MSI_FLAGS_MASKBIT) { > - fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32, > - pci_get_long(dev->config + msi_mask_off(dev, msi64bit)), > - pci_get_long(dev->config + msi_pending_off(dev, msi64bit))); > - } > - fprintf(stderr, "\n"); > -#endif > - > - if (!(flags & PCI_MSI_FLAGS_ENABLE)) { > - return; > - } > - > - /* > - * Now MSI is enabled, clear INTx# interrupts. > - * the driver is prohibited from writing enable bit to mask > - * a service request. But the guest OS could do this. > - * So we just discard the interrupts as moderate fallback. > - * > - * 6.8.3.3. Enabling Operation > - * While enabled for MSI or MSI-X operation, a function is prohibited > - * from using its INTx# pin (if implemented) to request > - * service (MSI, MSI-X, and INTx# are mutually exclusive). > - */ > - pci_device_deassert_intx(dev); > - > - /* > - * nr_vectors might be set bigger than capable. So clamp it. > - * This is not legal by spec, so we can do anything we like, > - * just don't crash the host > - */ > - log_num_vecs = > - (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1); > - log_max_vecs = > - (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1); > - if (log_num_vecs > log_max_vecs) { > - flags &= ~PCI_MSI_FLAGS_QSIZE; > - flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1); > - pci_set_word(dev->config + msi_flags_off(dev), flags); > - } > - > - if (!msi_per_vector_mask) { > - /* if per vector masking isn't supported, > - there is no pending interrupt. */ > - return; > - } > - > - nr_vectors = msi_nr_vectors(flags); > - > - /* This will discard pending interrupts, if any. */ > - pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit)); > - pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors); > - pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending); > - > - /* deliver pending interrupts which are unmasked */ > - for (vector = 0; vector < nr_vectors; ++vector) { > - if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) { > - continue; > - } > - > - pci_long_test_and_clear_mask( > - dev->config + msi_pending_off(dev, msi64bit), 1U << vector); > - msi_notify(dev, vector); > - } > -} > - > -unsigned int msi_nr_vectors_allocated(const PCIDevice *dev) > -{ > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > - return msi_nr_vectors(flags); > -} > diff --git a/hw/msi.h b/hw/msi.h > deleted file mode 100644 > index 150b09a..0000000 > --- a/hw/msi.h > +++ /dev/null > @@ -1,50 +0,0 @@ > -/* > - * msi.h > - * > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#ifndef QEMU_MSI_H > -#define QEMU_MSI_H > - > -#include "qemu-common.h" > -#include "pci.h" > - > -struct MSIMessage { > - uint64_t address; > - uint32_t data; > -}; > - > -extern bool msi_supported; > - > -void msi_set_message(PCIDevice *dev, MSIMessage msg); > -MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector); > -bool msi_enabled(const PCIDevice *dev); > -int msi_init(struct PCIDevice *dev, uint8_t offset, > - unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask); > -void msi_uninit(struct PCIDevice *dev); > -void msi_reset(PCIDevice *dev); > -void msi_notify(PCIDevice *dev, unsigned int vector); > -void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); > -unsigned int msi_nr_vectors_allocated(const PCIDevice *dev); > - > -static inline bool msi_present(const PCIDevice *dev) > -{ > - return dev->cap_present & QEMU_PCI_CAP_MSI; > -} > - > -#endif /* QEMU_MSI_H */ > diff --git a/hw/msix.c b/hw/msix.c > deleted file mode 100644 > index 136ef09..0000000 > --- a/hw/msix.c > +++ /dev/null > @@ -1,562 +0,0 @@ > -/* > - * MSI-X device support > - * > - * This module includes support for MSI-X in pci devices. > - * > - * Author: Michael S. Tsirkin <mst@redhat.com> > - * > - * 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 the > - * GNU GPL, version 2 or (at your option) any later version. > - */ > - > -#include "hw.h" > -#include "msi.h" > -#include "msix.h" > -#include "pci.h" > -#include "range.h" > - > -#define MSIX_CAP_LENGTH 12 > - > -/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */ > -#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1) > -#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8) > -#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8) > - > -static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) > -{ > - uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; > - MSIMessage msg; > - > - msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); > - msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); > - return msg; > -} > - > -/* > - * Special API for POWER to configure the vectors through > - * a side channel. Should never be used by devices. > - */ > -void msix_set_message(PCIDevice *dev, int vector, struct MSIMessage msg) > -{ > - uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; > - > - pci_set_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR, msg.address); > - pci_set_long(table_entry + PCI_MSIX_ENTRY_DATA, msg.data); > - table_entry[PCI_MSIX_ENTRY_VECTOR_CTRL] &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; > -} > - > -static uint8_t msix_pending_mask(int vector) > -{ > - return 1 << (vector % 8); > -} > - > -static uint8_t *msix_pending_byte(PCIDevice *dev, int vector) > -{ > - return dev->msix_pba + vector / 8; > -} > - > -static int msix_is_pending(PCIDevice *dev, int vector) > -{ > - return *msix_pending_byte(dev, vector) & msix_pending_mask(vector); > -} > - > -static void msix_set_pending(PCIDevice *dev, int vector) > -{ > - *msix_pending_byte(dev, vector) |= msix_pending_mask(vector); > -} > - > -static void msix_clr_pending(PCIDevice *dev, int vector) > -{ > - *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector); > -} > - > -static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask) > -{ > - unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; > - return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT; > -} > - > -static bool msix_is_masked(PCIDevice *dev, int vector) > -{ > - return msix_vector_masked(dev, vector, dev->msix_function_masked); > -} > - > -static void msix_fire_vector_notifier(PCIDevice *dev, > - unsigned int vector, bool is_masked) > -{ > - MSIMessage msg; > - int ret; > - > - if (!dev->msix_vector_use_notifier) { > - return; > - } > - if (is_masked) { > - dev->msix_vector_release_notifier(dev, vector); > - } else { > - msg = msix_get_message(dev, vector); > - ret = dev->msix_vector_use_notifier(dev, vector, msg); > - assert(ret >= 0); > - } > -} > - > -static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked) > -{ > - bool is_masked = msix_is_masked(dev, vector); > - > - if (is_masked == was_masked) { > - return; > - } > - > - msix_fire_vector_notifier(dev, vector, is_masked); > - > - if (!is_masked && msix_is_pending(dev, vector)) { > - msix_clr_pending(dev, vector); > - msix_notify(dev, vector); > - } > -} > - > -static void msix_update_function_masked(PCIDevice *dev) > -{ > - dev->msix_function_masked = !msix_enabled(dev) || > - (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK); > -} > - > -/* Handle MSI-X capability config write. */ > -void msix_write_config(PCIDevice *dev, uint32_t addr, > - uint32_t val, int len) > -{ > - unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET; > - int vector; > - bool was_masked; > - > - if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) { > - return; > - } > - > - was_masked = dev->msix_function_masked; > - msix_update_function_masked(dev); > - > - if (!msix_enabled(dev)) { > - return; > - } > - > - pci_device_deassert_intx(dev); > - > - if (dev->msix_function_masked == was_masked) { > - return; > - } > - > - for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > - msix_handle_mask_update(dev, vector, > - msix_vector_masked(dev, vector, was_masked)); > - } > -} > - > -static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr, > - unsigned size) > -{ > - PCIDevice *dev = opaque; > - > - return pci_get_long(dev->msix_table + addr); > -} > - > -static void msix_table_mmio_write(void *opaque, hwaddr addr, > - uint64_t val, unsigned size) > -{ > - PCIDevice *dev = opaque; > - int vector = addr / PCI_MSIX_ENTRY_SIZE; > - bool was_masked; > - > - was_masked = msix_is_masked(dev, vector); > - pci_set_long(dev->msix_table + addr, val); > - msix_handle_mask_update(dev, vector, was_masked); > -} > - > -static const MemoryRegionOps msix_table_mmio_ops = { > - .read = msix_table_mmio_read, > - .write = msix_table_mmio_write, > - /* TODO: MSIX should be LITTLE_ENDIAN. */ > - .endianness = DEVICE_NATIVE_ENDIAN, > - .valid = { > - .min_access_size = 4, > - .max_access_size = 4, > - }, > -}; > - > -static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, > - unsigned size) > -{ > - PCIDevice *dev = opaque; > - > - return pci_get_long(dev->msix_pba + addr); > -} > - > -static const MemoryRegionOps msix_pba_mmio_ops = { > - .read = msix_pba_mmio_read, > - /* TODO: MSIX should be LITTLE_ENDIAN. */ > - .endianness = DEVICE_NATIVE_ENDIAN, > - .valid = { > - .min_access_size = 4, > - .max_access_size = 4, > - }, > -}; > - > -static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) > -{ > - int vector; > - > - for (vector = 0; vector < nentries; ++vector) { > - unsigned offset = > - vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; > - bool was_masked = msix_is_masked(dev, vector); > - > - dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT; > - msix_handle_mask_update(dev, vector, was_masked); > - } > -} > - > -/* Initialize the MSI-X structures */ > -int msix_init(struct PCIDevice *dev, unsigned short nentries, > - MemoryRegion *table_bar, uint8_t table_bar_nr, > - unsigned table_offset, MemoryRegion *pba_bar, > - uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos) > -{ > - int cap; > - unsigned table_size, pba_size; > - uint8_t *config; > - > - /* Nothing to do if MSI is not supported by interrupt controller */ > - if (!msi_supported) { > - return -ENOTSUP; > - } > - > - if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) { > - return -EINVAL; > - } > - > - table_size = nentries * PCI_MSIX_ENTRY_SIZE; > - pba_size = QEMU_ALIGN_UP(nentries, 64) / 8; > - > - /* Sanity test: table & pba don't overlap, fit within BARs, min aligned */ > - if ((table_bar_nr == pba_bar_nr && > - ranges_overlap(table_offset, table_size, pba_offset, pba_size)) || > - table_offset + table_size > memory_region_size(table_bar) || > - pba_offset + pba_size > memory_region_size(pba_bar) || > - (table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) { > - return -EINVAL; > - } > - > - cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH); > - if (cap < 0) { > - return cap; > - } > - > - dev->msix_cap = cap; > - dev->cap_present |= QEMU_PCI_CAP_MSIX; > - config = dev->config + cap; > - > - pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1); > - dev->msix_entries_nr = nentries; > - dev->msix_function_masked = true; > - > - pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_nr); > - pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr); > - > - /* Make flags bit writable. */ > - dev->wmask[cap + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK | > - MSIX_MASKALL_MASK; > - > - dev->msix_table = g_malloc0(table_size); > - dev->msix_pba = g_malloc0(pba_size); > - dev->msix_entry_used = g_malloc0(nentries * sizeof *dev->msix_entry_used); > - > - msix_mask_all(dev, nentries); > - > - memory_region_init_io(&dev->msix_table_mmio, &msix_table_mmio_ops, dev, > - "msix-table", table_size); > - memory_region_add_subregion(table_bar, table_offset, &dev->msix_table_mmio); > - memory_region_init_io(&dev->msix_pba_mmio, &msix_pba_mmio_ops, dev, > - "msix-pba", pba_size); > - memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio); > - > - return 0; > -} > - > -int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, > - uint8_t bar_nr) > -{ > - int ret; > - char *name; > - > - /* > - * Migration compatibility dictates that this remains a 4k > - * BAR with the vector table in the lower half and PBA in > - * the upper half. Do not use these elsewhere! > - */ > -#define MSIX_EXCLUSIVE_BAR_SIZE 4096 > -#define MSIX_EXCLUSIVE_BAR_TABLE_OFFSET 0 > -#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2) > -#define MSIX_EXCLUSIVE_CAP_OFFSET 0 > - > - if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) { > - return -EINVAL; > - } > - > - name = g_strdup_printf("%s-msix", dev->name); > - memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE); > - g_free(name); > - > - ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr, > - MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar, > - bar_nr, MSIX_EXCLUSIVE_BAR_PBA_OFFSET, > - MSIX_EXCLUSIVE_CAP_OFFSET); > - if (ret) { > - memory_region_destroy(&dev->msix_exclusive_bar); > - return ret; > - } > - > - pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY, > - &dev->msix_exclusive_bar); > - > - return 0; > -} > - > -static void msix_free_irq_entries(PCIDevice *dev) > -{ > - int vector; > - > - for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > - dev->msix_entry_used[vector] = 0; > - msix_clr_pending(dev, vector); > - } > -} > - > -static void msix_clear_all_vectors(PCIDevice *dev) > -{ > - int vector; > - > - for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > - msix_clr_pending(dev, vector); > - } > -} > - > -/* Clean up resources for the device. */ > -void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar) > -{ > - if (!msix_present(dev)) { > - return; > - } > - pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH); > - dev->msix_cap = 0; > - msix_free_irq_entries(dev); > - dev->msix_entries_nr = 0; > - memory_region_del_subregion(pba_bar, &dev->msix_pba_mmio); > - memory_region_destroy(&dev->msix_pba_mmio); > - g_free(dev->msix_pba); > - dev->msix_pba = NULL; > - memory_region_del_subregion(table_bar, &dev->msix_table_mmio); > - memory_region_destroy(&dev->msix_table_mmio); > - g_free(dev->msix_table); > - dev->msix_table = NULL; > - g_free(dev->msix_entry_used); > - dev->msix_entry_used = NULL; > - dev->cap_present &= ~QEMU_PCI_CAP_MSIX; > -} > - > -void msix_uninit_exclusive_bar(PCIDevice *dev) > -{ > - if (msix_present(dev)) { > - msix_uninit(dev, &dev->msix_exclusive_bar, &dev->msix_exclusive_bar); > - memory_region_destroy(&dev->msix_exclusive_bar); > - } > -} > - > -void msix_save(PCIDevice *dev, QEMUFile *f) > -{ > - unsigned n = dev->msix_entries_nr; > - > - if (!msix_present(dev)) { > - return; > - } > - > - qemu_put_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); > - qemu_put_buffer(f, dev->msix_pba, (n + 7) / 8); > -} > - > -/* Should be called after restoring the config space. */ > -void msix_load(PCIDevice *dev, QEMUFile *f) > -{ > - unsigned n = dev->msix_entries_nr; > - unsigned int vector; > - > - if (!msix_present(dev)) { > - return; > - } > - > - msix_clear_all_vectors(dev); > - qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); > - qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8); > - msix_update_function_masked(dev); > - > - for (vector = 0; vector < n; vector++) { > - msix_handle_mask_update(dev, vector, true); > - } > -} > - > -/* Does device support MSI-X? */ > -int msix_present(PCIDevice *dev) > -{ > - return dev->cap_present & QEMU_PCI_CAP_MSIX; > -} > - > -/* Is MSI-X enabled? */ > -int msix_enabled(PCIDevice *dev) > -{ > - return (dev->cap_present & QEMU_PCI_CAP_MSIX) && > - (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > - MSIX_ENABLE_MASK); > -} > - > -/* Send an MSI-X message */ > -void msix_notify(PCIDevice *dev, unsigned vector) > -{ > - MSIMessage msg; > - > - if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) > - return; > - if (msix_is_masked(dev, vector)) { > - msix_set_pending(dev, vector); > - return; > - } > - > - msg = msix_get_message(dev, vector); > - > - stl_le_phys(msg.address, msg.data); > -} > - > -void msix_reset(PCIDevice *dev) > -{ > - if (!msix_present(dev)) { > - return; > - } > - msix_clear_all_vectors(dev); > - dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &= > - ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET]; > - memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE); > - memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8); > - msix_mask_all(dev, dev->msix_entries_nr); > -} > - > -/* PCI spec suggests that devices make it possible for software to configure > - * less vectors than supported by the device, but does not specify a standard > - * mechanism for devices to do so. > - * > - * We support this by asking devices to declare vectors software is going to > - * actually use, and checking this on the notification path. Devices that > - * don't want to follow the spec suggestion can declare all vectors as used. */ > - > -/* Mark vector as used. */ > -int msix_vector_use(PCIDevice *dev, unsigned vector) > -{ > - if (vector >= dev->msix_entries_nr) > - return -EINVAL; > - dev->msix_entry_used[vector]++; > - return 0; > -} > - > -/* Mark vector as unused. */ > -void msix_vector_unuse(PCIDevice *dev, unsigned vector) > -{ > - if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) { > - return; > - } > - if (--dev->msix_entry_used[vector]) { > - return; > - } > - msix_clr_pending(dev, vector); > -} > - > -void msix_unuse_all_vectors(PCIDevice *dev) > -{ > - if (!msix_present(dev)) { > - return; > - } > - msix_free_irq_entries(dev); > -} > - > -unsigned int msix_nr_vectors_allocated(const PCIDevice *dev) > -{ > - return dev->msix_entries_nr; > -} > - > -static int msix_set_notifier_for_vector(PCIDevice *dev, unsigned int vector) > -{ > - MSIMessage msg; > - > - if (msix_is_masked(dev, vector)) { > - return 0; > - } > - msg = msix_get_message(dev, vector); > - return dev->msix_vector_use_notifier(dev, vector, msg); > -} > - > -static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector) > -{ > - if (msix_is_masked(dev, vector)) { > - return; > - } > - dev->msix_vector_release_notifier(dev, vector); > -} > - > -int msix_set_vector_notifiers(PCIDevice *dev, > - MSIVectorUseNotifier use_notifier, > - MSIVectorReleaseNotifier release_notifier) > -{ > - int vector, ret; > - > - assert(use_notifier && release_notifier); > - > - dev->msix_vector_use_notifier = use_notifier; > - dev->msix_vector_release_notifier = release_notifier; > - > - if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > - (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { > - for (vector = 0; vector < dev->msix_entries_nr; vector++) { > - ret = msix_set_notifier_for_vector(dev, vector); > - if (ret < 0) { > - goto undo; > - } > - } > - } > - return 0; > - > -undo: > - while (--vector >= 0) { > - msix_unset_notifier_for_vector(dev, vector); > - } > - dev->msix_vector_use_notifier = NULL; > - dev->msix_vector_release_notifier = NULL; > - return ret; > -} > - > -void msix_unset_vector_notifiers(PCIDevice *dev) > -{ > - int vector; > - > - assert(dev->msix_vector_use_notifier && > - dev->msix_vector_release_notifier); > - > - if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > - (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { > - for (vector = 0; vector < dev->msix_entries_nr; vector++) { > - msix_unset_notifier_for_vector(dev, vector); > - } > - } > - dev->msix_vector_use_notifier = NULL; > - dev->msix_vector_release_notifier = NULL; > -} > diff --git a/hw/msix.h b/hw/msix.h > deleted file mode 100644 > index 15211cb..0000000 > --- a/hw/msix.h > +++ /dev/null > @@ -1,41 +0,0 @@ > -#ifndef QEMU_MSIX_H > -#define QEMU_MSIX_H > - > -#include "qemu-common.h" > -#include "pci.h" > - > -void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg); > -int msix_init(PCIDevice *dev, unsigned short nentries, > - MemoryRegion *table_bar, uint8_t table_bar_nr, > - unsigned table_offset, MemoryRegion *pba_bar, > - uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos); > -int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, > - uint8_t bar_nr); > - > -void msix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len); > - > -void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, > - MemoryRegion *pba_bar); > -void msix_uninit_exclusive_bar(PCIDevice *dev); > - > -unsigned int msix_nr_vectors_allocated(const PCIDevice *dev); > - > -void msix_save(PCIDevice *dev, QEMUFile *f); > -void msix_load(PCIDevice *dev, QEMUFile *f); > - > -int msix_enabled(PCIDevice *dev); > -int msix_present(PCIDevice *dev); > - > -int msix_vector_use(PCIDevice *dev, unsigned vector); > -void msix_vector_unuse(PCIDevice *dev, unsigned vector); > -void msix_unuse_all_vectors(PCIDevice *dev); > - > -void msix_notify(PCIDevice *dev, unsigned vector); > - > -void msix_reset(PCIDevice *dev); > - > -int msix_set_vector_notifiers(PCIDevice *dev, > - MSIVectorUseNotifier use_notifier, > - MSIVectorReleaseNotifier release_notifier); > -void msix_unset_vector_notifiers(PCIDevice *dev); > -#endif > diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c > deleted file mode 100644 > index 0ca5546..0000000 > --- a/hw/pci-hotplug.c > +++ /dev/null > @@ -1,293 +0,0 @@ > -/* > - * QEMU PCI hotplug support > - * > - * Copyright (c) 2004 Fabrice Bellard > - * > - * Permission is hereby granted, free of charge, to any person obtaining a copy > - * of this software and associated documentation files (the "Software"), to deal > - * in the Software without restriction, including without limitation the rights > - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > - * copies of the Software, and to permit persons to whom the Software is > - * furnished to do so, subject to the following conditions: > - * > - * The above copyright notice and this permission notice shall be included in > - * all copies or substantial portions of the Software. > - * > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > - * THE SOFTWARE. > - */ > - > -#include "hw.h" > -#include "boards.h" > -#include "pci.h" > -#include "net.h" > -#include "pc.h" > -#include "monitor.h" > -#include "scsi.h" > -#include "virtio-blk.h" > -#include "qemu-config.h" > -#include "blockdev.h" > -#include "error.h" > - > -#if defined(TARGET_I386) > -static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, > - const char *devaddr, > - const char *opts_str) > -{ > - Error *local_err = NULL; > - QemuOpts *opts; > - PCIBus *bus; > - int ret, devfn; > - > - bus = pci_get_bus_devfn(&devfn, devaddr); > - if (!bus) { > - monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); > - return NULL; > - } > - if (!((BusState*)bus)->allow_hotplug) { > - monitor_printf(mon, "PCI bus doesn't support hotplug\n"); > - return NULL; > - } > - > - opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0); > - if (!opts) { > - return NULL; > - } > - > - qemu_opt_set(opts, "type", "nic"); > - > - ret = net_client_init(opts, 0, &local_err); > - if (error_is_set(&local_err)) { > - qerror_report_err(local_err); > - error_free(local_err); > - return NULL; > - } > - if (nd_table[ret].devaddr) { > - monitor_printf(mon, "Parameter addr not supported\n"); > - return NULL; > - } > - return pci_nic_init(&nd_table[ret], "rtl8139", devaddr); > -} > - > -static int scsi_hot_add(Monitor *mon, DeviceState *adapter, > - DriveInfo *dinfo, int printinfo) > -{ > - SCSIBus *scsibus; > - SCSIDevice *scsidev; > - > - scsibus = (SCSIBus *) > - object_dynamic_cast(OBJECT(QLIST_FIRST(&adapter->child_bus)), > - TYPE_SCSI_BUS); > - if (!scsibus) { > - error_report("Device is not a SCSI adapter"); > - return -1; > - } > - > - /* > - * drive_init() tries to find a default for dinfo->unit. Doesn't > - * work at all for hotplug though as we assign the device to a > - * specific bus instead of the first bus with spare scsi ids. > - * > - * Ditch the calculated value and reload from option string (if > - * specified). > - */ > - dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1); > - dinfo->bus = scsibus->busnr; > - scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, > - false, -1); > - if (!scsidev) { > - return -1; > - } > - dinfo->unit = scsidev->id; > - > - if (printinfo) > - monitor_printf(mon, "OK bus %d, unit %d\n", > - scsibus->busnr, scsidev->id); > - return 0; > -} > - > -int pci_drive_hot_add(Monitor *mon, const QDict *qdict, > - DriveInfo *dinfo, int type) > -{ > - int dom, pci_bus; > - unsigned slot; > - PCIDevice *dev; > - const char *pci_addr = qdict_get_str(qdict, "pci_addr"); > - > - switch (type) { > - case IF_SCSI: > - if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) { > - goto err; > - } > - dev = pci_find_device(pci_find_root_bus(dom), pci_bus, > - PCI_DEVFN(slot, 0)); > - if (!dev) { > - monitor_printf(mon, "no pci device with address %s\n", pci_addr); > - goto err; > - } > - if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) != 0) { > - goto err; > - } > - break; > - default: > - monitor_printf(mon, "Can't hot-add drive to type %d\n", type); > - goto err; > - } > - > - return 0; > -err: > - return -1; > -} > - > -static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, > - const char *devaddr, > - const char *opts) > -{ > - PCIDevice *dev; > - DriveInfo *dinfo = NULL; > - int type = -1; > - char buf[128]; > - PCIBus *bus; > - int devfn; > - > - if (get_param_value(buf, sizeof(buf), "if", opts)) { > - if (!strcmp(buf, "scsi")) > - type = IF_SCSI; > - else if (!strcmp(buf, "virtio")) { > - type = IF_VIRTIO; > - } else { > - monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf); > - return NULL; > - } > - } else { > - monitor_printf(mon, "no if= specified\n"); > - return NULL; > - } > - > - if (get_param_value(buf, sizeof(buf), "file", opts)) { > - dinfo = add_init_drive(opts); > - if (!dinfo) > - return NULL; > - if (dinfo->devaddr) { > - monitor_printf(mon, "Parameter addr not supported\n"); > - return NULL; > - } > - } else { > - dinfo = NULL; > - } > - > - bus = pci_get_bus_devfn(&devfn, devaddr); > - if (!bus) { > - monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); > - return NULL; > - } > - if (!((BusState*)bus)->allow_hotplug) { > - monitor_printf(mon, "PCI bus doesn't support hotplug\n"); > - return NULL; > - } > - > - switch (type) { > - case IF_SCSI: > - dev = pci_create(bus, devfn, "lsi53c895a"); > - if (qdev_init(&dev->qdev) < 0) > - dev = NULL; > - if (dev && dinfo) { > - if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) { > - qdev_unplug(&dev->qdev, NULL); > - dev = NULL; > - } > - } > - break; > - case IF_VIRTIO: > - if (!dinfo) { > - monitor_printf(mon, "virtio requires a backing file/device.\n"); > - return NULL; > - } > - dev = pci_create(bus, devfn, "virtio-blk-pci"); > - if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) { > - qdev_free(&dev->qdev); > - dev = NULL; > - break; > - } > - if (qdev_init(&dev->qdev) < 0) > - dev = NULL; > - break; > - default: > - dev = NULL; > - } > - return dev; > -} > - > -void pci_device_hot_add(Monitor *mon, const QDict *qdict) > -{ > - PCIDevice *dev = NULL; > - const char *pci_addr = qdict_get_str(qdict, "pci_addr"); > - const char *type = qdict_get_str(qdict, "type"); > - const char *opts = qdict_get_try_str(qdict, "opts"); > - > - /* strip legacy tag */ > - if (!strncmp(pci_addr, "pci_addr=", 9)) { > - pci_addr += 9; > - } > - > - if (!opts) { > - opts = ""; > - } > - > - if (!strcmp(pci_addr, "auto")) > - pci_addr = NULL; > - > - if (strcmp(type, "nic") == 0) { > - dev = qemu_pci_hot_add_nic(mon, pci_addr, opts); > - } else if (strcmp(type, "storage") == 0) { > - dev = qemu_pci_hot_add_storage(mon, pci_addr, opts); > - } else { > - monitor_printf(mon, "invalid type: %s\n", type); > - } > - > - if (dev) { > - monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n", > - pci_find_domain(dev->bus), > - pci_bus_num(dev->bus), PCI_SLOT(dev->devfn), > - PCI_FUNC(dev->devfn)); > - } else > - monitor_printf(mon, "failed to add %s\n", opts); > -} > -#endif > - > -static int pci_device_hot_remove(Monitor *mon, const char *pci_addr) > -{ > - PCIDevice *d; > - int dom, bus; > - unsigned slot; > - Error *local_err = NULL; > - > - if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) { > - return -1; > - } > - > - d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0)); > - if (!d) { > - monitor_printf(mon, "slot %d empty\n", slot); > - return -1; > - } > - > - qdev_unplug(&d->qdev, &local_err); > - if (error_is_set(&local_err)) { > - monitor_printf(mon, "%s\n", error_get_pretty(local_err)); > - error_free(local_err); > - return -1; > - } > - > - return 0; > -} > - > -void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict) > -{ > - pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr")); > -} > diff --git a/hw/pci-stub.c b/hw/pci-stub.c > deleted file mode 100644 > index 134c448..0000000 > --- a/hw/pci-stub.c > +++ /dev/null > @@ -1,47 +0,0 @@ > -/* > - * PCI stubs for platforms that don't support pci bus. > - * > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - * > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#include "sysemu.h" > -#include "monitor.h" > -#include "pci.h" > -#include "qmp-commands.h" > - > -PciInfoList *qmp_query_pci(Error **errp) > -{ > - error_set(errp, QERR_UNSUPPORTED); > - return NULL; > -} > - > -static void pci_error_message(Monitor *mon) > -{ > - monitor_printf(mon, "PCI devices not supported\n"); > -} > - > -int do_pcie_aer_inject_error(Monitor *mon, > - const QDict *qdict, QObject **ret_data) > -{ > - pci_error_message(mon); > - return -ENOSYS; > -} > - > -void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) > -{ > - pci_error_message(mon); > -} > diff --git a/hw/pci.c b/hw/pci.c > deleted file mode 100644 > index 97a0cd7..0000000 > --- a/hw/pci.c > +++ /dev/null > @@ -1,2168 +0,0 @@ > -/* > - * QEMU PCI bus manager > - * > - * Copyright (c) 2004 Fabrice Bellard > - * > - * Permission is hereby granted, free of charge, to any person obtaining a copy > - * of this software and associated documentation files (the "Software"), to deal > - * in the Software without restriction, including without limitation the rights > - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > - * copies of the Software, and to permit persons to whom the Software is > - * furnished to do so, subject to the following conditions: > - * > - * The above copyright notice and this permission notice shall be included in > - * all copies or substantial portions of the Software. > - * > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > - * THE SOFTWARE. > - */ > -#include "hw.h" > -#include "pci.h" > -#include "pci_bridge.h" > -#include "pci_internals.h" > -#include "monitor.h" > -#include "net.h" > -#include "sysemu.h" > -#include "loader.h" > -#include "range.h" > -#include "qmp-commands.h" > -#include "msi.h" > -#include "msix.h" > -#include "exec-memory.h" > - > -//#define DEBUG_PCI > -#ifdef DEBUG_PCI > -# define PCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) > -#else > -# define PCI_DPRINTF(format, ...) do { } while (0) > -#endif > - > -static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); > -static char *pcibus_get_dev_path(DeviceState *dev); > -static char *pcibus_get_fw_dev_path(DeviceState *dev); > -static int pcibus_reset(BusState *qbus); > - > -static Property pci_props[] = { > - DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), > - DEFINE_PROP_STRING("romfile", PCIDevice, romfile), > - DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1), > - DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present, > - QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false), > - DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present, > - QEMU_PCI_CAP_SERR_BITNR, true), > - DEFINE_PROP_END_OF_LIST() > -}; > - > -static void pci_bus_class_init(ObjectClass *klass, void *data) > -{ > - BusClass *k = BUS_CLASS(klass); > - > - k->print_dev = pcibus_dev_print; > - k->get_dev_path = pcibus_get_dev_path; > - k->get_fw_dev_path = pcibus_get_fw_dev_path; > - k->reset = pcibus_reset; > -} > - > -static const TypeInfo pci_bus_info = { > - .name = TYPE_PCI_BUS, > - .parent = TYPE_BUS, > - .instance_size = sizeof(PCIBus), > - .class_init = pci_bus_class_init, > -}; > - > -static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); > -static void pci_update_mappings(PCIDevice *d); > -static void pci_set_irq(void *opaque, int irq_num, int level); > -static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom); > -static void pci_del_option_rom(PCIDevice *pdev); > - > -static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET; > -static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU; > - > -struct PCIHostBus { > - int domain; > - struct PCIBus *bus; > - QLIST_ENTRY(PCIHostBus) next; > -}; > -static QLIST_HEAD(, PCIHostBus) host_buses; > - > -static const VMStateDescription vmstate_pcibus = { > - .name = "PCIBUS", > - .version_id = 1, > - .minimum_version_id = 1, > - .minimum_version_id_old = 1, > - .fields = (VMStateField []) { > - VMSTATE_INT32_EQUAL(nirq, PCIBus), > - VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32, int32_t), > - VMSTATE_END_OF_LIST() > - } > -}; > -static int pci_bar(PCIDevice *d, int reg) > -{ > - uint8_t type; > - > - if (reg != PCI_ROM_SLOT) > - return PCI_BASE_ADDRESS_0 + reg * 4; > - > - type = d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; > - return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; > -} > - > -static inline int pci_irq_state(PCIDevice *d, int irq_num) > -{ > - return (d->irq_state >> irq_num) & 0x1; > -} > - > -static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level) > -{ > - d->irq_state &= ~(0x1 << irq_num); > - d->irq_state |= level << irq_num; > -} > - > -static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) > -{ > - PCIBus *bus; > - for (;;) { > - bus = pci_dev->bus; > - irq_num = bus->map_irq(pci_dev, irq_num); > - if (bus->set_irq) > - break; > - pci_dev = bus->parent_dev; > - } > - bus->irq_count[irq_num] += change; > - bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); > -} > - > -int pci_bus_get_irq_level(PCIBus *bus, int irq_num) > -{ > - assert(irq_num >= 0); > - assert(irq_num < bus->nirq); > - return !!bus->irq_count[irq_num]; > -} > - > -/* Update interrupt status bit in config space on interrupt > - * state change. */ > -static void pci_update_irq_status(PCIDevice *dev) > -{ > - if (dev->irq_state) { > - dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT; > - } else { > - dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; > - } > -} > - > -void pci_device_deassert_intx(PCIDevice *dev) > -{ > - int i; > - for (i = 0; i < PCI_NUM_PINS; ++i) { > - qemu_set_irq(dev->irq[i], 0); > - } > -} > - > -/* > - * This function is called on #RST and FLR. > - * FLR if PCI_EXP_DEVCTL_BCR_FLR is set > - */ > -void pci_device_reset(PCIDevice *dev) > -{ > - int r; > - > - qdev_reset_all(&dev->qdev); > - > - dev->irq_state = 0; > - pci_update_irq_status(dev); > - pci_device_deassert_intx(dev); > - /* Clear all writable bits */ > - pci_word_test_and_clear_mask(dev->config + PCI_COMMAND, > - pci_get_word(dev->wmask + PCI_COMMAND) | > - pci_get_word(dev->w1cmask + PCI_COMMAND)); > - pci_word_test_and_clear_mask(dev->config + PCI_STATUS, > - pci_get_word(dev->wmask + PCI_STATUS) | > - pci_get_word(dev->w1cmask + PCI_STATUS)); > - dev->config[PCI_CACHE_LINE_SIZE] = 0x0; > - dev->config[PCI_INTERRUPT_LINE] = 0x0; > - for (r = 0; r < PCI_NUM_REGIONS; ++r) { > - PCIIORegion *region = &dev->io_regions[r]; > - if (!region->size) { > - continue; > - } > - > - if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) && > - region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > - pci_set_quad(dev->config + pci_bar(dev, r), region->type); > - } else { > - pci_set_long(dev->config + pci_bar(dev, r), region->type); > - } > - } > - pci_update_mappings(dev); > - > - msi_reset(dev); > - msix_reset(dev); > -} > - > -/* > - * Trigger pci bus reset under a given bus. > - * To be called on RST# assert. > - */ > -void pci_bus_reset(PCIBus *bus) > -{ > - int i; > - > - for (i = 0; i < bus->nirq; i++) { > - bus->irq_count[i] = 0; > - } > - for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { > - if (bus->devices[i]) { > - pci_device_reset(bus->devices[i]); > - } > - } > -} > - > -static int pcibus_reset(BusState *qbus) > -{ > - pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus)); > - > - /* topology traverse is done by pci_bus_reset(). > - Tell qbus/qdev walker not to traverse the tree */ > - return 1; > -} > - > -static void pci_host_bus_register(int domain, PCIBus *bus) > -{ > - struct PCIHostBus *host; > - host = g_malloc0(sizeof(*host)); > - host->domain = domain; > - host->bus = bus; > - QLIST_INSERT_HEAD(&host_buses, host, next); > -} > - > -PCIBus *pci_find_root_bus(int domain) > -{ > - struct PCIHostBus *host; > - > - QLIST_FOREACH(host, &host_buses, next) { > - if (host->domain == domain) { > - return host->bus; > - } > - } > - > - return NULL; > -} > - > -int pci_find_domain(const PCIBus *bus) > -{ > - PCIDevice *d; > - struct PCIHostBus *host; > - > - /* obtain root bus */ > - while ((d = bus->parent_dev) != NULL) { > - bus = d->bus; > - } > - > - QLIST_FOREACH(host, &host_buses, next) { > - if (host->bus == bus) { > - return host->domain; > - } > - } > - > - abort(); /* should not be reached */ > - return -1; > -} > - > -void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, > - const char *name, > - MemoryRegion *address_space_mem, > - MemoryRegion *address_space_io, > - uint8_t devfn_min) > -{ > - qbus_create_inplace(&bus->qbus, TYPE_PCI_BUS, parent, name); > - assert(PCI_FUNC(devfn_min) == 0); > - bus->devfn_min = devfn_min; > - bus->address_space_mem = address_space_mem; > - bus->address_space_io = address_space_io; > - > - /* host bridge */ > - QLIST_INIT(&bus->child); > - pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */ > - > - vmstate_register(NULL, -1, &vmstate_pcibus, bus); > -} > - > -PCIBus *pci_bus_new(DeviceState *parent, const char *name, > - MemoryRegion *address_space_mem, > - MemoryRegion *address_space_io, > - uint8_t devfn_min) > -{ > - PCIBus *bus; > - > - bus = g_malloc0(sizeof(*bus)); > - pci_bus_new_inplace(bus, parent, name, address_space_mem, > - address_space_io, devfn_min); > - OBJECT(bus)->free = g_free; > - return bus; > -} > - > -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > - void *irq_opaque, int nirq) > -{ > - bus->set_irq = set_irq; > - bus->map_irq = map_irq; > - bus->irq_opaque = irq_opaque; > - bus->nirq = nirq; > - bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0])); > -} > - > -void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev) > -{ > - bus->qbus.allow_hotplug = 1; > - bus->hotplug = hotplug; > - bus->hotplug_qdev = qdev; > -} > - > -PCIBus *pci_register_bus(DeviceState *parent, const char *name, > - pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > - void *irq_opaque, > - MemoryRegion *address_space_mem, > - MemoryRegion *address_space_io, > - uint8_t devfn_min, int nirq) > -{ > - PCIBus *bus; > - > - bus = pci_bus_new(parent, name, address_space_mem, > - address_space_io, devfn_min); > - pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq); > - return bus; > -} > - > -int pci_bus_num(PCIBus *s) > -{ > - if (!s->parent_dev) > - return 0; /* pci host bridge */ > - return s->parent_dev->config[PCI_SECONDARY_BUS]; > -} > - > -static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) > -{ > - PCIDevice *s = container_of(pv, PCIDevice, config); > - uint8_t *config; > - int i; > - > - assert(size == pci_config_size(s)); > - config = g_malloc(size); > - > - qemu_get_buffer(f, config, size); > - for (i = 0; i < size; ++i) { > - if ((config[i] ^ s->config[i]) & > - s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) { > - g_free(config); > - return -EINVAL; > - } > - } > - memcpy(s->config, config, size); > - > - pci_update_mappings(s); > - > - memory_region_set_enabled(&s->bus_master_enable_region, > - pci_get_word(s->config + PCI_COMMAND) > - & PCI_COMMAND_MASTER); > - > - g_free(config); > - return 0; > -} > - > -/* just put buffer */ > -static void put_pci_config_device(QEMUFile *f, void *pv, size_t size) > -{ > - const uint8_t **v = pv; > - assert(size == pci_config_size(container_of(pv, PCIDevice, config))); > - qemu_put_buffer(f, *v, size); > -} > - > -static VMStateInfo vmstate_info_pci_config = { > - .name = "pci config", > - .get = get_pci_config_device, > - .put = put_pci_config_device, > -}; > - > -static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) > -{ > - PCIDevice *s = container_of(pv, PCIDevice, irq_state); > - uint32_t irq_state[PCI_NUM_PINS]; > - int i; > - for (i = 0; i < PCI_NUM_PINS; ++i) { > - irq_state[i] = qemu_get_be32(f); > - if (irq_state[i] != 0x1 && irq_state[i] != 0) { > - fprintf(stderr, "irq state %d: must be 0 or 1.\n", > - irq_state[i]); > - return -EINVAL; > - } > - } > - > - for (i = 0; i < PCI_NUM_PINS; ++i) { > - pci_set_irq_state(s, i, irq_state[i]); > - } > - > - return 0; > -} > - > -static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size) > -{ > - int i; > - PCIDevice *s = container_of(pv, PCIDevice, irq_state); > - > - for (i = 0; i < PCI_NUM_PINS; ++i) { > - qemu_put_be32(f, pci_irq_state(s, i)); > - } > -} > - > -static VMStateInfo vmstate_info_pci_irq_state = { > - .name = "pci irq state", > - .get = get_pci_irq_state, > - .put = put_pci_irq_state, > -}; > - > -const VMStateDescription vmstate_pci_device = { > - .name = "PCIDevice", > - .version_id = 2, > - .minimum_version_id = 1, > - .minimum_version_id_old = 1, > - .fields = (VMStateField []) { > - VMSTATE_INT32_LE(version_id, PCIDevice), > - VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, > - vmstate_info_pci_config, > - PCI_CONFIG_SPACE_SIZE), > - VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, > - vmstate_info_pci_irq_state, > - PCI_NUM_PINS * sizeof(int32_t)), > - VMSTATE_END_OF_LIST() > - } > -}; > - > -const VMStateDescription vmstate_pcie_device = { > - .name = "PCIEDevice", > - .version_id = 2, > - .minimum_version_id = 1, > - .minimum_version_id_old = 1, > - .fields = (VMStateField []) { > - VMSTATE_INT32_LE(version_id, PCIDevice), > - VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, > - vmstate_info_pci_config, > - PCIE_CONFIG_SPACE_SIZE), > - VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, > - vmstate_info_pci_irq_state, > - PCI_NUM_PINS * sizeof(int32_t)), > - VMSTATE_END_OF_LIST() > - } > -}; > - > -static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s) > -{ > - return pci_is_express(s) ? &vmstate_pcie_device : &vmstate_pci_device; > -} > - > -void pci_device_save(PCIDevice *s, QEMUFile *f) > -{ > - /* Clear interrupt status bit: it is implicit > - * in irq_state which we are saving. > - * This makes us compatible with old devices > - * which never set or clear this bit. */ > - s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; > - vmstate_save_state(f, pci_get_vmstate(s), s); > - /* Restore the interrupt status bit. */ > - pci_update_irq_status(s); > -} > - > -int pci_device_load(PCIDevice *s, QEMUFile *f) > -{ > - int ret; > - ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id); > - /* Restore the interrupt status bit. */ > - pci_update_irq_status(s); > - return ret; > -} > - > -static void pci_set_default_subsystem_id(PCIDevice *pci_dev) > -{ > - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, > - pci_default_sub_vendor_id); > - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, > - pci_default_sub_device_id); > -} > - > -/* > - * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL > - * [[<domain>:]<bus>:]<slot>.<func>, return -1 on error > - */ > -static int pci_parse_devaddr(const char *addr, int *domp, int *busp, > - unsigned int *slotp, unsigned int *funcp) > -{ > - const char *p; > - char *e; > - unsigned long val; > - unsigned long dom = 0, bus = 0; > - unsigned int slot = 0; > - unsigned int func = 0; > - > - p = addr; > - val = strtoul(p, &e, 16); > - if (e == p) > - return -1; > - if (*e == ':') { > - bus = val; > - p = e + 1; > - val = strtoul(p, &e, 16); > - if (e == p) > - return -1; > - if (*e == ':') { > - dom = bus; > - bus = val; > - p = e + 1; > - val = strtoul(p, &e, 16); > - if (e == p) > - return -1; > - } > - } > - > - slot = val; > - > - if (funcp != NULL) { > - if (*e != '.') > - return -1; > - > - p = e + 1; > - val = strtoul(p, &e, 16); > - if (e == p) > - return -1; > - > - func = val; > - } > - > - /* if funcp == NULL func is 0 */ > - if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) > - return -1; > - > - if (*e) > - return -1; > - > - *domp = dom; > - *busp = bus; > - *slotp = slot; > - if (funcp != NULL) > - *funcp = func; > - return 0; > -} > - > -int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, > - unsigned *slotp) > -{ > - /* strip legacy tag */ > - if (!strncmp(addr, "pci_addr=", 9)) { > - addr += 9; > - } > - if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) { > - monitor_printf(mon, "Invalid pci address\n"); > - return -1; > - } > - return 0; > -} > - > -PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) > -{ > - int dom, bus; > - unsigned slot; > - > - if (!devaddr) { > - *devfnp = -1; > - return pci_find_bus_nr(pci_find_root_bus(0), 0); > - } > - > - if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) { > - return NULL; > - } > - > - *devfnp = PCI_DEVFN(slot, 0); > - return pci_find_bus_nr(pci_find_root_bus(dom), bus); > -} > - > -static void pci_init_cmask(PCIDevice *dev) > -{ > - pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff); > - pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff); > - dev->cmask[PCI_STATUS] = PCI_STATUS_CAP_LIST; > - dev->cmask[PCI_REVISION_ID] = 0xff; > - dev->cmask[PCI_CLASS_PROG] = 0xff; > - pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff); > - dev->cmask[PCI_HEADER_TYPE] = 0xff; > - dev->cmask[PCI_CAPABILITY_LIST] = 0xff; > -} > - > -static void pci_init_wmask(PCIDevice *dev) > -{ > - int config_size = pci_config_size(dev); > - > - dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff; > - dev->wmask[PCI_INTERRUPT_LINE] = 0xff; > - pci_set_word(dev->wmask + PCI_COMMAND, > - PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | > - PCI_COMMAND_INTX_DISABLE); > - if (dev->cap_present & QEMU_PCI_CAP_SERR) { > - pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR); > - } > - > - memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff, > - config_size - PCI_CONFIG_HEADER_SIZE); > -} > - > -static void pci_init_w1cmask(PCIDevice *dev) > -{ > - /* > - * Note: It's okay to set w1cmask even for readonly bits as > - * long as their value is hardwired to 0. > - */ > - pci_set_word(dev->w1cmask + PCI_STATUS, > - PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | > - PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | > - PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY); > -} > - > -static void pci_init_mask_bridge(PCIDevice *d) > -{ > - /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and > - PCI_SEC_LETENCY_TIMER */ > - memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4); > - > - /* base and limit */ > - d->wmask[PCI_IO_BASE] = PCI_IO_RANGE_MASK & 0xff; > - d->wmask[PCI_IO_LIMIT] = PCI_IO_RANGE_MASK & 0xff; > - pci_set_word(d->wmask + PCI_MEMORY_BASE, > - PCI_MEMORY_RANGE_MASK & 0xffff); > - pci_set_word(d->wmask + PCI_MEMORY_LIMIT, > - PCI_MEMORY_RANGE_MASK & 0xffff); > - pci_set_word(d->wmask + PCI_PREF_MEMORY_BASE, > - PCI_PREF_RANGE_MASK & 0xffff); > - pci_set_word(d->wmask + PCI_PREF_MEMORY_LIMIT, > - PCI_PREF_RANGE_MASK & 0xffff); > - > - /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */ > - memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8); > - > - /* Supported memory and i/o types */ > - d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_16; > - d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_16; > - pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE, > - PCI_PREF_RANGE_TYPE_64); > - pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT, > - PCI_PREF_RANGE_TYPE_64); > - > -/* TODO: add this define to pci_regs.h in linux and then in qemu. */ > -#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ > -#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */ > -#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */ > -#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ > -#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ > - pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, > - PCI_BRIDGE_CTL_PARITY | > - PCI_BRIDGE_CTL_SERR | > - PCI_BRIDGE_CTL_ISA | > - PCI_BRIDGE_CTL_VGA | > - PCI_BRIDGE_CTL_VGA_16BIT | > - PCI_BRIDGE_CTL_MASTER_ABORT | > - PCI_BRIDGE_CTL_BUS_RESET | > - PCI_BRIDGE_CTL_FAST_BACK | > - PCI_BRIDGE_CTL_DISCARD | > - PCI_BRIDGE_CTL_SEC_DISCARD | > - PCI_BRIDGE_CTL_DISCARD_SERR); > - /* Below does not do anything as we never set this bit, put here for > - * completeness. */ > - pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL, > - PCI_BRIDGE_CTL_DISCARD_STATUS); > - d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK; > - d->cmask[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_MASK; > - pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE, > - PCI_PREF_RANGE_TYPE_MASK); > - pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_LIMIT, > - PCI_PREF_RANGE_TYPE_MASK); > -} > - > -static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev) > -{ > - uint8_t slot = PCI_SLOT(dev->devfn); > - uint8_t func; > - > - if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { > - dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; > - } > - > - /* > - * multifunction bit is interpreted in two ways as follows. > - * - all functions must set the bit to 1. > - * Example: Intel X53 > - * - function 0 must set the bit, but the rest function (> 0) > - * is allowed to leave the bit to 0. > - * Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10, > - * > - * So OS (at least Linux) checks the bit of only function 0, > - * and doesn't see the bit of function > 0. > - * > - * The below check allows both interpretation. > - */ > - if (PCI_FUNC(dev->devfn)) { > - PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)]; > - if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) { > - /* function 0 should set multifunction bit */ > - error_report("PCI: single function device can't be populated " > - "in function %x.%x", slot, PCI_FUNC(dev->devfn)); > - return -1; > - } > - return 0; > - } > - > - if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { > - return 0; > - } > - /* function 0 indicates single function, so function > 0 must be NULL */ > - for (func = 1; func < PCI_FUNC_MAX; ++func) { > - if (bus->devices[PCI_DEVFN(slot, func)]) { > - error_report("PCI: %x.0 indicates single function, " > - "but %x.%x is already populated.", > - slot, slot, func); > - return -1; > - } > - } > - return 0; > -} > - > -static void pci_config_alloc(PCIDevice *pci_dev) > -{ > - int config_size = pci_config_size(pci_dev); > - > - pci_dev->config = g_malloc0(config_size); > - pci_dev->cmask = g_malloc0(config_size); > - pci_dev->wmask = g_malloc0(config_size); > - pci_dev->w1cmask = g_malloc0(config_size); > - pci_dev->used = g_malloc0(config_size); > -} > - > -static void pci_config_free(PCIDevice *pci_dev) > -{ > - g_free(pci_dev->config); > - g_free(pci_dev->cmask); > - g_free(pci_dev->wmask); > - g_free(pci_dev->w1cmask); > - g_free(pci_dev->used); > -} > - > -/* -1 for devfn means auto assign */ > -static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, > - const char *name, int devfn) > -{ > - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > - PCIConfigReadFunc *config_read = pc->config_read; > - PCIConfigWriteFunc *config_write = pc->config_write; > - > - if (devfn < 0) { > - for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices); > - devfn += PCI_FUNC_MAX) { > - if (!bus->devices[devfn]) > - goto found; > - } > - error_report("PCI: no slot/function available for %s, all in use", name); > - return NULL; > - found: ; > - } else if (bus->devices[devfn]) { > - error_report("PCI: slot %d function %d not available for %s, in use by %s", > - PCI_SLOT(devfn), PCI_FUNC(devfn), name, bus->devices[devfn]->name); > - return NULL; > - } > - pci_dev->bus = bus; > - if (bus->dma_context_fn) { > - pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, devfn); > - } else { > - /* FIXME: Make dma_context_fn use MemoryRegions instead, so this path is > - * taken unconditionally */ > - /* FIXME: inherit memory region from bus creator */ > - memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master", > - get_system_memory(), 0, > - memory_region_size(get_system_memory())); > - memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); > - address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region); > - pci_dev->dma = g_new(DMAContext, 1); > - dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL); > - } > - pci_dev->devfn = devfn; > - pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); > - pci_dev->irq_state = 0; > - pci_config_alloc(pci_dev); > - > - pci_config_set_vendor_id(pci_dev->config, pc->vendor_id); > - pci_config_set_device_id(pci_dev->config, pc->device_id); > - pci_config_set_revision(pci_dev->config, pc->revision); > - pci_config_set_class(pci_dev->config, pc->class_id); > - > - if (!pc->is_bridge) { > - if (pc->subsystem_vendor_id || pc->subsystem_id) { > - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, > - pc->subsystem_vendor_id); > - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, > - pc->subsystem_id); > - } else { > - pci_set_default_subsystem_id(pci_dev); > - } > - } else { > - /* subsystem_vendor_id/subsystem_id are only for header type 0 */ > - assert(!pc->subsystem_vendor_id); > - assert(!pc->subsystem_id); > - } > - pci_init_cmask(pci_dev); > - pci_init_wmask(pci_dev); > - pci_init_w1cmask(pci_dev); > - if (pc->is_bridge) { > - pci_init_mask_bridge(pci_dev); > - } > - if (pci_init_multifunction(bus, pci_dev)) { > - pci_config_free(pci_dev); > - return NULL; > - } > - > - if (!config_read) > - config_read = pci_default_read_config; > - if (!config_write) > - config_write = pci_default_write_config; > - pci_dev->config_read = config_read; > - pci_dev->config_write = config_write; > - bus->devices[devfn] = pci_dev; > - pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS); > - pci_dev->version_id = 2; /* Current pci device vmstate version */ > - return pci_dev; > -} > - > -static void do_pci_unregister_device(PCIDevice *pci_dev) > -{ > - qemu_free_irqs(pci_dev->irq); > - pci_dev->bus->devices[pci_dev->devfn] = NULL; > - pci_config_free(pci_dev); > - > - if (!pci_dev->bus->dma_context_fn) { > - address_space_destroy(&pci_dev->bus_master_as); > - memory_region_destroy(&pci_dev->bus_master_enable_region); > - g_free(pci_dev->dma); > - pci_dev->dma = NULL; > - } > -} > - > -static void pci_unregister_io_regions(PCIDevice *pci_dev) > -{ > - PCIIORegion *r; > - int i; > - > - for(i = 0; i < PCI_NUM_REGIONS; i++) { > - r = &pci_dev->io_regions[i]; > - if (!r->size || r->addr == PCI_BAR_UNMAPPED) > - continue; > - memory_region_del_subregion(r->address_space, r->memory); > - } > -} > - > -static int pci_unregister_device(DeviceState *dev) > -{ > - PCIDevice *pci_dev = PCI_DEVICE(dev); > - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > - > - pci_unregister_io_regions(pci_dev); > - pci_del_option_rom(pci_dev); > - > - if (pc->exit) { > - pc->exit(pci_dev); > - } > - > - do_pci_unregister_device(pci_dev); > - return 0; > -} > - > -void pci_register_bar(PCIDevice *pci_dev, int region_num, > - uint8_t type, MemoryRegion *memory) > -{ > - PCIIORegion *r; > - uint32_t addr; > - uint64_t wmask; > - pcibus_t size = memory_region_size(memory); > - > - assert(region_num >= 0); > - assert(region_num < PCI_NUM_REGIONS); > - if (size & (size-1)) { > - fprintf(stderr, "ERROR: PCI region size must be pow2 " > - "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size); > - exit(1); > - } > - > - r = &pci_dev->io_regions[region_num]; > - r->addr = PCI_BAR_UNMAPPED; > - r->size = size; > - r->type = type; > - r->memory = NULL; > - > - wmask = ~(size - 1); > - addr = pci_bar(pci_dev, region_num); > - if (region_num == PCI_ROM_SLOT) { > - /* ROM enable bit is writable */ > - wmask |= PCI_ROM_ADDRESS_ENABLE; > - } > - pci_set_long(pci_dev->config + addr, type); > - if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) && > - r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > - pci_set_quad(pci_dev->wmask + addr, wmask); > - pci_set_quad(pci_dev->cmask + addr, ~0ULL); > - } else { > - pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff); > - pci_set_long(pci_dev->cmask + addr, 0xffffffff); > - } > - pci_dev->io_regions[region_num].memory = memory; > - pci_dev->io_regions[region_num].address_space > - = type & PCI_BASE_ADDRESS_SPACE_IO > - ? pci_dev->bus->address_space_io > - : pci_dev->bus->address_space_mem; > -} > - > -pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num) > -{ > - return pci_dev->io_regions[region_num].addr; > -} > - > -static pcibus_t pci_bar_address(PCIDevice *d, > - int reg, uint8_t type, pcibus_t size) > -{ > - pcibus_t new_addr, last_addr; > - int bar = pci_bar(d, reg); > - uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); > - > - if (type & PCI_BASE_ADDRESS_SPACE_IO) { > - if (!(cmd & PCI_COMMAND_IO)) { > - return PCI_BAR_UNMAPPED; > - } > - new_addr = pci_get_long(d->config + bar) & ~(size - 1); > - last_addr = new_addr + size - 1; > - /* NOTE: we have only 64K ioports on PC */ > - if (last_addr <= new_addr || new_addr == 0 || last_addr > UINT16_MAX) { > - return PCI_BAR_UNMAPPED; > - } > - return new_addr; > - } > - > - if (!(cmd & PCI_COMMAND_MEMORY)) { > - return PCI_BAR_UNMAPPED; > - } > - if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > - new_addr = pci_get_quad(d->config + bar); > - } else { > - new_addr = pci_get_long(d->config + bar); > - } > - /* the ROM slot has a specific enable bit */ > - if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) { > - return PCI_BAR_UNMAPPED; > - } > - new_addr &= ~(size - 1); > - last_addr = new_addr + size - 1; > - /* NOTE: we do not support wrapping */ > - /* XXX: as we cannot support really dynamic > - mappings, we handle specific values as invalid > - mappings. */ > - if (last_addr <= new_addr || new_addr == 0 || > - last_addr == PCI_BAR_UNMAPPED) { > - return PCI_BAR_UNMAPPED; > - } > - > - /* Now pcibus_t is 64bit. > - * Check if 32 bit BAR wraps around explicitly. > - * Without this, PC ide doesn't work well. > - * TODO: remove this work around. > - */ > - if (!(type & PCI_BASE_ADDRESS_MEM_TYPE_64) && last_addr >= UINT32_MAX) { > - return PCI_BAR_UNMAPPED; > - } > - > - /* > - * OS is allowed to set BAR beyond its addressable > - * bits. For example, 32 bit OS can set 64bit bar > - * to >4G. Check it. TODO: we might need to support > - * it in the future for e.g. PAE. > - */ > - if (last_addr >= HWADDR_MAX) { > - return PCI_BAR_UNMAPPED; > - } > - > - return new_addr; > -} > - > -static void pci_update_mappings(PCIDevice *d) > -{ > - PCIIORegion *r; > - int i; > - pcibus_t new_addr; > - > - for(i = 0; i < PCI_NUM_REGIONS; i++) { > - r = &d->io_regions[i]; > - > - /* this region isn't registered */ > - if (!r->size) > - continue; > - > - new_addr = pci_bar_address(d, i, r->type, r->size); > - > - /* This bar isn't changed */ > - if (new_addr == r->addr) > - continue; > - > - /* now do the real mapping */ > - if (r->addr != PCI_BAR_UNMAPPED) { > - memory_region_del_subregion(r->address_space, r->memory); > - } > - r->addr = new_addr; > - if (r->addr != PCI_BAR_UNMAPPED) { > - memory_region_add_subregion_overlap(r->address_space, > - r->addr, r->memory, 1); > - } > - } > -} > - > -static inline int pci_irq_disabled(PCIDevice *d) > -{ > - return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE; > -} > - > -/* Called after interrupt disabled field update in config space, > - * assert/deassert interrupts if necessary. > - * Gets original interrupt disable bit value (before update). */ > -static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled) > -{ > - int i, disabled = pci_irq_disabled(d); > - if (disabled == was_irq_disabled) > - return; > - for (i = 0; i < PCI_NUM_PINS; ++i) { > - int state = pci_irq_state(d, i); > - pci_change_irq_level(d, i, disabled ? -state : state); > - } > -} > - > -uint32_t pci_default_read_config(PCIDevice *d, > - uint32_t address, int len) > -{ > - uint32_t val = 0; > - > - memcpy(&val, d->config + address, len); > - return le32_to_cpu(val); > -} > - > -void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) > -{ > - int i, was_irq_disabled = pci_irq_disabled(d); > - > - for (i = 0; i < l; val >>= 8, ++i) { > - uint8_t wmask = d->wmask[addr + i]; > - uint8_t w1cmask = d->w1cmask[addr + i]; > - assert(!(wmask & w1cmask)); > - d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask); > - d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ > - } > - if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) || > - ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) || > - ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) || > - range_covers_byte(addr, l, PCI_COMMAND)) > - pci_update_mappings(d); > - > - if (range_covers_byte(addr, l, PCI_COMMAND)) { > - pci_update_irq_disabled(d, was_irq_disabled); > - memory_region_set_enabled(&d->bus_master_enable_region, > - pci_get_word(d->config + PCI_COMMAND) > - & PCI_COMMAND_MASTER); > - } > - > - msi_write_config(d, addr, val, l); > - msix_write_config(d, addr, val, l); > -} > - > -/***********************************************************/ > -/* generic PCI irq support */ > - > -/* 0 <= irq_num <= 3. level must be 0 or 1 */ > -static void pci_set_irq(void *opaque, int irq_num, int level) > -{ > - PCIDevice *pci_dev = opaque; > - int change; > - > - change = level - pci_irq_state(pci_dev, irq_num); > - if (!change) > - return; > - > - pci_set_irq_state(pci_dev, irq_num, level); > - pci_update_irq_status(pci_dev); > - if (pci_irq_disabled(pci_dev)) > - return; > - pci_change_irq_level(pci_dev, irq_num, change); > -} > - > -/* Special hooks used by device assignment */ > -void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq) > -{ > - assert(!bus->parent_dev); > - bus->route_intx_to_irq = route_intx_to_irq; > -} > - > -PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) > -{ > - PCIBus *bus; > - > - do { > - bus = dev->bus; > - pin = bus->map_irq(dev, pin); > - dev = bus->parent_dev; > - } while (dev); > - > - if (!bus->route_intx_to_irq) { > - error_report("PCI: Bug - unimplemented PCI INTx routing (%s)\n", > - object_get_typename(OBJECT(bus->qbus.parent))); > - return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 }; > - } > - > - return bus->route_intx_to_irq(bus->irq_opaque, pin); > -} > - > -bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new) > -{ > - return old->mode != new->mode || old->irq != new->irq; > -} > - > -void pci_bus_fire_intx_routing_notifier(PCIBus *bus) > -{ > - PCIDevice *dev; > - PCIBus *sec; > - int i; > - > - for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { > - dev = bus->devices[i]; > - if (dev && dev->intx_routing_notifier) { > - dev->intx_routing_notifier(dev); > - } > - QLIST_FOREACH(sec, &bus->child, sibling) { > - pci_bus_fire_intx_routing_notifier(sec); > - } > - } > -} > - > -void pci_device_set_intx_routing_notifier(PCIDevice *dev, > - PCIINTxRoutingNotifier notifier) > -{ > - dev->intx_routing_notifier = notifier; > -} > - > -/* > - * PCI-to-PCI bridge specification > - * 9.1: Interrupt routing. Table 9-1 > - * > - * the PCI Express Base Specification, Revision 2.1 > - * 2.2.8.1: INTx interrutp signaling - Rules > - * the Implementation Note > - * Table 2-20 > - */ > -/* > - * 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD > - * 0-origin unlike PCI interrupt pin register. > - */ > -int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) > -{ > - return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; > -} > - > -/***********************************************************/ > -/* monitor info on PCI */ > - > -typedef struct { > - uint16_t class; > - const char *desc; > - const char *fw_name; > - uint16_t fw_ign_bits; > -} pci_class_desc; > - > -static const pci_class_desc pci_class_descriptions[] = > -{ > - { 0x0001, "VGA controller", "display"}, > - { 0x0100, "SCSI controller", "scsi"}, > - { 0x0101, "IDE controller", "ide"}, > - { 0x0102, "Floppy controller", "fdc"}, > - { 0x0103, "IPI controller", "ipi"}, > - { 0x0104, "RAID controller", "raid"}, > - { 0x0106, "SATA controller"}, > - { 0x0107, "SAS controller"}, > - { 0x0180, "Storage controller"}, > - { 0x0200, "Ethernet controller", "ethernet"}, > - { 0x0201, "Token Ring controller", "token-ring"}, > - { 0x0202, "FDDI controller", "fddi"}, > - { 0x0203, "ATM controller", "atm"}, > - { 0x0280, "Network controller"}, > - { 0x0300, "VGA controller", "display", 0x00ff}, > - { 0x0301, "XGA controller"}, > - { 0x0302, "3D controller"}, > - { 0x0380, "Display controller"}, > - { 0x0400, "Video controller", "video"}, > - { 0x0401, "Audio controller", "sound"}, > - { 0x0402, "Phone"}, > - { 0x0403, "Audio controller", "sound"}, > - { 0x0480, "Multimedia controller"}, > - { 0x0500, "RAM controller", "memory"}, > - { 0x0501, "Flash controller", "flash"}, > - { 0x0580, "Memory controller"}, > - { 0x0600, "Host bridge", "host"}, > - { 0x0601, "ISA bridge", "isa"}, > - { 0x0602, "EISA bridge", "eisa"}, > - { 0x0603, "MC bridge", "mca"}, > - { 0x0604, "PCI bridge", "pci"}, > - { 0x0605, "PCMCIA bridge", "pcmcia"}, > - { 0x0606, "NUBUS bridge", "nubus"}, > - { 0x0607, "CARDBUS bridge", "cardbus"}, > - { 0x0608, "RACEWAY bridge"}, > - { 0x0680, "Bridge"}, > - { 0x0700, "Serial port", "serial"}, > - { 0x0701, "Parallel port", "parallel"}, > - { 0x0800, "Interrupt controller", "interrupt-controller"}, > - { 0x0801, "DMA controller", "dma-controller"}, > - { 0x0802, "Timer", "timer"}, > - { 0x0803, "RTC", "rtc"}, > - { 0x0900, "Keyboard", "keyboard"}, > - { 0x0901, "Pen", "pen"}, > - { 0x0902, "Mouse", "mouse"}, > - { 0x0A00, "Dock station", "dock", 0x00ff}, > - { 0x0B00, "i386 cpu", "cpu", 0x00ff}, > - { 0x0c00, "Fireware contorller", "fireware"}, > - { 0x0c01, "Access bus controller", "access-bus"}, > - { 0x0c02, "SSA controller", "ssa"}, > - { 0x0c03, "USB controller", "usb"}, > - { 0x0c04, "Fibre channel controller", "fibre-channel"}, > - { 0x0c05, "SMBus"}, > - { 0, NULL} > -}; > - > -static void pci_for_each_device_under_bus(PCIBus *bus, > - void (*fn)(PCIBus *b, PCIDevice *d, > - void *opaque), > - void *opaque) > -{ > - PCIDevice *d; > - int devfn; > - > - for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > - d = bus->devices[devfn]; > - if (d) { > - fn(bus, d, opaque); > - } > - } > -} > - > -void pci_for_each_device(PCIBus *bus, int bus_num, > - void (*fn)(PCIBus *b, PCIDevice *d, void *opaque), > - void *opaque) > -{ > - bus = pci_find_bus_nr(bus, bus_num); > - > - if (bus) { > - pci_for_each_device_under_bus(bus, fn, opaque); > - } > -} > - > -static const pci_class_desc *get_class_desc(int class) > -{ > - const pci_class_desc *desc; > - > - desc = pci_class_descriptions; > - while (desc->desc && class != desc->class) { > - desc++; > - } > - > - return desc; > -} > - > -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num); > - > -static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev) > -{ > - PciMemoryRegionList *head = NULL, *cur_item = NULL; > - int i; > - > - for (i = 0; i < PCI_NUM_REGIONS; i++) { > - const PCIIORegion *r = &dev->io_regions[i]; > - PciMemoryRegionList *region; > - > - if (!r->size) { > - continue; > - } > - > - region = g_malloc0(sizeof(*region)); > - region->value = g_malloc0(sizeof(*region->value)); > - > - if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { > - region->value->type = g_strdup("io"); > - } else { > - region->value->type = g_strdup("memory"); > - region->value->has_prefetch = true; > - region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH); > - region->value->has_mem_type_64 = true; > - region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64); > - } > - > - region->value->bar = i; > - region->value->address = r->addr; > - region->value->size = r->size; > - > - /* XXX: waiting for the qapi to support GSList */ > - if (!cur_item) { > - head = cur_item = region; > - } else { > - cur_item->next = region; > - cur_item = region; > - } > - } > - > - return head; > -} > - > -static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus, > - int bus_num) > -{ > - PciBridgeInfo *info; > - > - info = g_malloc0(sizeof(*info)); > - > - info->bus.number = dev->config[PCI_PRIMARY_BUS]; > - info->bus.secondary = dev->config[PCI_SECONDARY_BUS]; > - info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS]; > - > - info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range)); > - info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); > - info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO); > - > - info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range)); > - info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > - info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > - > - info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range)); > - info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > - info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > - > - if (dev->config[PCI_SECONDARY_BUS] != 0) { > - PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]); > - if (child_bus) { > - info->has_devices = true; > - info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]); > - } > - } > - > - return info; > -} > - > -static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, > - int bus_num) > -{ > - const pci_class_desc *desc; > - PciDeviceInfo *info; > - uint8_t type; > - int class; > - > - info = g_malloc0(sizeof(*info)); > - info->bus = bus_num; > - info->slot = PCI_SLOT(dev->devfn); > - info->function = PCI_FUNC(dev->devfn); > - > - class = pci_get_word(dev->config + PCI_CLASS_DEVICE); > - info->class_info.class = class; > - desc = get_class_desc(class); > - if (desc->desc) { > - info->class_info.has_desc = true; > - info->class_info.desc = g_strdup(desc->desc); > - } > - > - info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID); > - info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID); > - info->regions = qmp_query_pci_regions(dev); > - info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : ""); > - > - if (dev->config[PCI_INTERRUPT_PIN] != 0) { > - info->has_irq = true; > - info->irq = dev->config[PCI_INTERRUPT_LINE]; > - } > - > - type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; > - if (type == PCI_HEADER_TYPE_BRIDGE) { > - info->has_pci_bridge = true; > - info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num); > - } > - > - return info; > -} > - > -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num) > -{ > - PciDeviceInfoList *info, *head = NULL, *cur_item = NULL; > - PCIDevice *dev; > - int devfn; > - > - for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > - dev = bus->devices[devfn]; > - if (dev) { > - info = g_malloc0(sizeof(*info)); > - info->value = qmp_query_pci_device(dev, bus, bus_num); > - > - /* XXX: waiting for the qapi to support GSList */ > - if (!cur_item) { > - head = cur_item = info; > - } else { > - cur_item->next = info; > - cur_item = info; > - } > - } > - } > - > - return head; > -} > - > -static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) > -{ > - PciInfo *info = NULL; > - > - bus = pci_find_bus_nr(bus, bus_num); > - if (bus) { > - info = g_malloc0(sizeof(*info)); > - info->bus = bus_num; > - info->devices = qmp_query_pci_devices(bus, bus_num); > - } > - > - return info; > -} > - > -PciInfoList *qmp_query_pci(Error **errp) > -{ > - PciInfoList *info, *head = NULL, *cur_item = NULL; > - struct PCIHostBus *host; > - > - QLIST_FOREACH(host, &host_buses, next) { > - info = g_malloc0(sizeof(*info)); > - info->value = qmp_query_pci_bus(host->bus, 0); > - > - /* XXX: waiting for the qapi to support GSList */ > - if (!cur_item) { > - head = cur_item = info; > - } else { > - cur_item->next = info; > - cur_item = info; > - } > - } > - > - return head; > -} > - > -static const char * const pci_nic_models[] = { > - "ne2k_pci", > - "i82551", > - "i82557b", > - "i82559er", > - "rtl8139", > - "e1000", > - "pcnet", > - "virtio", > - NULL > -}; > - > -static const char * const pci_nic_names[] = { > - "ne2k_pci", > - "i82551", > - "i82557b", > - "i82559er", > - "rtl8139", > - "e1000", > - "pcnet", > - "virtio-net-pci", > - NULL > -}; > - > -/* Initialize a PCI NIC. */ > -/* FIXME callers should check for failure, but don't */ > -PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, > - const char *default_devaddr) > -{ > - const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr; > - PCIBus *bus; > - int devfn; > - PCIDevice *pci_dev; > - DeviceState *dev; > - int i; > - > - i = qemu_find_nic_model(nd, pci_nic_models, default_model); > - if (i < 0) > - return NULL; > - > - bus = pci_get_bus_devfn(&devfn, devaddr); > - if (!bus) { > - error_report("Invalid PCI device address %s for device %s", > - devaddr, pci_nic_names[i]); > - return NULL; > - } > - > - pci_dev = pci_create(bus, devfn, pci_nic_names[i]); > - dev = &pci_dev->qdev; > - qdev_set_nic_properties(dev, nd); > - if (qdev_init(dev) < 0) > - return NULL; > - return pci_dev; > -} > - > -PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, > - const char *default_devaddr) > -{ > - PCIDevice *res; > - > - if (qemu_show_nic_models(nd->model, pci_nic_models)) > - exit(0); > - > - res = pci_nic_init(nd, default_model, default_devaddr); > - if (!res) > - exit(1); > - return res; > -} > - > -PCIDevice *pci_vga_init(PCIBus *bus) > -{ > - switch (vga_interface_type) { > - case VGA_CIRRUS: > - return pci_create_simple(bus, -1, "cirrus-vga"); > - case VGA_QXL: > - return pci_create_simple(bus, -1, "qxl-vga"); > - case VGA_STD: > - return pci_create_simple(bus, -1, "VGA"); > - case VGA_VMWARE: > - return pci_create_simple(bus, -1, "vmware-svga"); > - case VGA_NONE: > - default: /* Other non-PCI types. Checking for unsupported types is already > - done in vl.c. */ > - return NULL; > - } > -} > - > -/* Whether a given bus number is in range of the secondary > - * bus of the given bridge device. */ > -static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) > -{ > - return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) & > - PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ && > - dev->config[PCI_SECONDARY_BUS] < bus_num && > - bus_num <= dev->config[PCI_SUBORDINATE_BUS]; > -} > - > -static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) > -{ > - PCIBus *sec; > - > - if (!bus) { > - return NULL; > - } > - > - if (pci_bus_num(bus) == bus_num) { > - return bus; > - } > - > - /* Consider all bus numbers in range for the host pci bridge. */ > - if (bus->parent_dev && > - !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) { > - return NULL; > - } > - > - /* try child bus */ > - for (; bus; bus = sec) { > - QLIST_FOREACH(sec, &bus->child, sibling) { > - assert(sec->parent_dev); > - if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) { > - return sec; > - } > - if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) { > - break; > - } > - } > - } > - > - return NULL; > -} > - > -PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn) > -{ > - bus = pci_find_bus_nr(bus, bus_num); > - > - if (!bus) > - return NULL; > - > - return bus->devices[devfn]; > -} > - > -static int pci_qdev_init(DeviceState *qdev) > -{ > - PCIDevice *pci_dev = (PCIDevice *)qdev; > - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > - PCIBus *bus; > - int rc; > - bool is_default_rom; > - > - /* initialize cap_present for pci_is_express() and pci_config_size() */ > - if (pc->is_express) { > - pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; > - } > - > - bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); > - pci_dev = do_pci_register_device(pci_dev, bus, > - object_get_typename(OBJECT(qdev)), > - pci_dev->devfn); > - if (pci_dev == NULL) > - return -1; > - if (qdev->hotplugged && pc->no_hotplug) { > - qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev))); > - do_pci_unregister_device(pci_dev); > - return -1; > - } > - if (pc->init) { > - rc = pc->init(pci_dev); > - if (rc != 0) { > - do_pci_unregister_device(pci_dev); > - return rc; > - } > - } > - > - /* rom loading */ > - is_default_rom = false; > - if (pci_dev->romfile == NULL && pc->romfile != NULL) { > - pci_dev->romfile = g_strdup(pc->romfile); > - is_default_rom = true; > - } > - pci_add_option_rom(pci_dev, is_default_rom); > - > - if (bus->hotplug) { > - /* Let buses differentiate between hotplug and when device is > - * enabled during qemu machine creation. */ > - rc = bus->hotplug(bus->hotplug_qdev, pci_dev, > - qdev->hotplugged ? PCI_HOTPLUG_ENABLED: > - PCI_COLDPLUG_ENABLED); > - if (rc != 0) { > - int r = pci_unregister_device(&pci_dev->qdev); > - assert(!r); > - return rc; > - } > - } > - return 0; > -} > - > -static int pci_unplug_device(DeviceState *qdev) > -{ > - PCIDevice *dev = PCI_DEVICE(qdev); > - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); > - > - if (pc->no_hotplug) { > - qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev))); > - return -1; > - } > - return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, > - PCI_HOTPLUG_DISABLED); > -} > - > -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, > - const char *name) > -{ > - DeviceState *dev; > - > - dev = qdev_create(&bus->qbus, name); > - qdev_prop_set_int32(dev, "addr", devfn); > - qdev_prop_set_bit(dev, "multifunction", multifunction); > - return PCI_DEVICE(dev); > -} > - > -PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, > - bool multifunction, > - const char *name) > -{ > - PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction, name); > - qdev_init_nofail(&dev->qdev); > - return dev; > -} > - > -PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name) > -{ > - return pci_create_multifunction(bus, devfn, false, name); > -} > - > -PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) > -{ > - return pci_create_simple_multifunction(bus, devfn, false, name); > -} > - > -static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size) > -{ > - int offset = PCI_CONFIG_HEADER_SIZE; > - int i; > - for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) { > - if (pdev->used[i]) > - offset = i + 1; > - else if (i - offset + 1 == size) > - return offset; > - } > - return 0; > -} > - > -static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id, > - uint8_t *prev_p) > -{ > - uint8_t next, prev; > - > - if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST)) > - return 0; > - > - for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); > - prev = next + PCI_CAP_LIST_NEXT) > - if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id) > - break; > - > - if (prev_p) > - *prev_p = prev; > - return next; > -} > - > -static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset) > -{ > - uint8_t next, prev, found = 0; > - > - if (!(pdev->used[offset])) { > - return 0; > - } > - > - assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST); > - > - for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); > - prev = next + PCI_CAP_LIST_NEXT) { > - if (next <= offset && next > found) { > - found = next; > - } > - } > - return found; > -} > - > -/* Patch the PCI vendor and device ids in a PCI rom image if necessary. > - This is needed for an option rom which is used for more than one device. */ > -static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size) > -{ > - uint16_t vendor_id; > - uint16_t device_id; > - uint16_t rom_vendor_id; > - uint16_t rom_device_id; > - uint16_t rom_magic; > - uint16_t pcir_offset; > - uint8_t checksum; > - > - /* Words in rom data are little endian (like in PCI configuration), > - so they can be read / written with pci_get_word / pci_set_word. */ > - > - /* Only a valid rom will be patched. */ > - rom_magic = pci_get_word(ptr); > - if (rom_magic != 0xaa55) { > - PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic); > - return; > - } > - pcir_offset = pci_get_word(ptr + 0x18); > - if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) { > - PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset); > - return; > - } > - > - vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); > - device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); > - rom_vendor_id = pci_get_word(ptr + pcir_offset + 4); > - rom_device_id = pci_get_word(ptr + pcir_offset + 6); > - > - PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile, > - vendor_id, device_id, rom_vendor_id, rom_device_id); > - > - checksum = ptr[6]; > - > - if (vendor_id != rom_vendor_id) { > - /* Patch vendor id and checksum (at offset 6 for etherboot roms). */ > - checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8); > - checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8); > - PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > - ptr[6] = checksum; > - pci_set_word(ptr + pcir_offset + 4, vendor_id); > - } > - > - if (device_id != rom_device_id) { > - /* Patch device id and checksum (at offset 6 for etherboot roms). */ > - checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8); > - checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8); > - PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > - ptr[6] = checksum; > - pci_set_word(ptr + pcir_offset + 6, device_id); > - } > -} > - > -/* Add an option rom for the device */ > -static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) > -{ > - int size; > - char *path; > - void *ptr; > - char name[32]; > - const VMStateDescription *vmsd; > - > - if (!pdev->romfile) > - return 0; > - if (strlen(pdev->romfile) == 0) > - return 0; > - > - if (!pdev->rom_bar) { > - /* > - * Load rom via fw_cfg instead of creating a rom bar, > - * for 0.11 compatibility. > - */ > - int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE); > - if (class == 0x0300) { > - rom_add_vga(pdev->romfile); > - } else { > - rom_add_option(pdev->romfile, -1); > - } > - return 0; > - } > - > - path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); > - if (path == NULL) { > - path = g_strdup(pdev->romfile); > - } > - > - size = get_image_size(path); > - if (size < 0) { > - error_report("%s: failed to find romfile \"%s\"", > - __FUNCTION__, pdev->romfile); > - g_free(path); > - return -1; > - } > - if (size & (size - 1)) { > - size = 1 << qemu_fls(size); > - } > - > - vmsd = qdev_get_vmsd(DEVICE(pdev)); > - > - if (vmsd) { > - snprintf(name, sizeof(name), "%s.rom", vmsd->name); > - } else { > - snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev))); > - } > - pdev->has_rom = true; > - memory_region_init_ram(&pdev->rom, name, size); > - vmstate_register_ram(&pdev->rom, &pdev->qdev); > - ptr = memory_region_get_ram_ptr(&pdev->rom); > - load_image(path, ptr); > - g_free(path); > - > - if (is_default_rom) { > - /* Only the default rom images will be patched (if needed). */ > - pci_patch_ids(pdev, ptr, size); > - } > - > - qemu_put_ram_ptr(ptr); > - > - pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom); > - > - return 0; > -} > - > -static void pci_del_option_rom(PCIDevice *pdev) > -{ > - if (!pdev->has_rom) > - return; > - > - vmstate_unregister_ram(&pdev->rom, &pdev->qdev); > - memory_region_destroy(&pdev->rom); > - pdev->has_rom = false; > -} > - > -/* > - * if !offset > - * Reserve space and add capability to the linked list in pci config space > - * > - * if offset = 0, > - * Find and reserve space and add capability to the linked list > - * in pci config space */ > -int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, > - uint8_t offset, uint8_t size) > -{ > - uint8_t *config; > - int i, overlapping_cap; > - > - if (!offset) { > - offset = pci_find_space(pdev, size); > - if (!offset) { > - return -ENOSPC; > - } > - } else { > - /* Verify that capabilities don't overlap. Note: device assignment > - * depends on this check to verify that the device is not broken. > - * Should never trigger for emulated devices, but it's helpful > - * for debugging these. */ > - for (i = offset; i < offset + size; i++) { > - overlapping_cap = pci_find_capability_at_offset(pdev, i); > - if (overlapping_cap) { > - fprintf(stderr, "ERROR: %04x:%02x:%02x.%x " > - "Attempt to add PCI capability %x at offset " > - "%x overlaps existing capability %x at offset %x\n", > - pci_find_domain(pdev->bus), pci_bus_num(pdev->bus), > - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), > - cap_id, offset, overlapping_cap, i); > - return -EINVAL; > - } > - } > - } > - > - config = pdev->config + offset; > - config[PCI_CAP_LIST_ID] = cap_id; > - config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST]; > - pdev->config[PCI_CAPABILITY_LIST] = offset; > - pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST; > - memset(pdev->used + offset, 0xFF, QEMU_ALIGN_UP(size, 4)); > - /* Make capability read-only by default */ > - memset(pdev->wmask + offset, 0, size); > - /* Check capability by default */ > - memset(pdev->cmask + offset, 0xFF, size); > - return offset; > -} > - > -/* Unlink capability from the pci config space. */ > -void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) > -{ > - uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev); > - if (!offset) > - return; > - pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT]; > - /* Make capability writable again */ > - memset(pdev->wmask + offset, 0xff, size); > - memset(pdev->w1cmask + offset, 0, size); > - /* Clear cmask as device-specific registers can't be checked */ > - memset(pdev->cmask + offset, 0, size); > - memset(pdev->used + offset, 0, QEMU_ALIGN_UP(size, 4)); > - > - if (!pdev->config[PCI_CAPABILITY_LIST]) > - pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST; > -} > - > -uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id) > -{ > - return pci_find_capability_list(pdev, cap_id, NULL); > -} > - > -static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) > -{ > - PCIDevice *d = (PCIDevice *)dev; > - const pci_class_desc *desc; > - char ctxt[64]; > - PCIIORegion *r; > - int i, class; > - > - class = pci_get_word(d->config + PCI_CLASS_DEVICE); > - desc = pci_class_descriptions; > - while (desc->desc && class != desc->class) > - desc++; > - if (desc->desc) { > - snprintf(ctxt, sizeof(ctxt), "%s", desc->desc); > - } else { > - snprintf(ctxt, sizeof(ctxt), "Class %04x", class); > - } > - > - monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " > - "pci id %04x:%04x (sub %04x:%04x)\n", > - indent, "", ctxt, pci_bus_num(d->bus), > - PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), > - pci_get_word(d->config + PCI_VENDOR_ID), > - pci_get_word(d->config + PCI_DEVICE_ID), > - pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID), > - pci_get_word(d->config + PCI_SUBSYSTEM_ID)); > - for (i = 0; i < PCI_NUM_REGIONS; i++) { > - r = &d->io_regions[i]; > - if (!r->size) > - continue; > - monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS > - " [0x%"FMT_PCIBUS"]\n", > - indent, "", > - i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem", > - r->addr, r->addr + r->size - 1); > - } > -} > - > -static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len) > -{ > - PCIDevice *d = (PCIDevice *)dev; > - const char *name = NULL; > - const pci_class_desc *desc = pci_class_descriptions; > - int class = pci_get_word(d->config + PCI_CLASS_DEVICE); > - > - while (desc->desc && > - (class & ~desc->fw_ign_bits) != > - (desc->class & ~desc->fw_ign_bits)) { > - desc++; > - } > - > - if (desc->desc) { > - name = desc->fw_name; > - } > - > - if (name) { > - pstrcpy(buf, len, name); > - } else { > - snprintf(buf, len, "pci%04x,%04x", > - pci_get_word(d->config + PCI_VENDOR_ID), > - pci_get_word(d->config + PCI_DEVICE_ID)); > - } > - > - return buf; > -} > - > -static char *pcibus_get_fw_dev_path(DeviceState *dev) > -{ > - PCIDevice *d = (PCIDevice *)dev; > - char path[50], name[33]; > - int off; > - > - off = snprintf(path, sizeof(path), "%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 = container_of(dev, PCIDevice, qdev); > - PCIDevice *t; > - int slot_depth; > - /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function. > - * 00 is added here to make this format compatible with > - * domain:Bus:Slot.Func for systems without nested PCI bridges. > - * Slot.Function list specifies the slot and function numbers for all > - * devices on the path from root to the specific device. */ > - char domain[] = "DDDD:00"; > - char slot[] = ":SS.F"; > - int domain_len = sizeof domain - 1 /* For '\0' */; > - int slot_len = sizeof slot - 1 /* For '\0' */; > - int path_len; > - char *path, *p; > - int s; > - > - /* Calculate # of slots on path between device and root. */; > - slot_depth = 0; > - for (t = d; t; t = t->bus->parent_dev) { > - ++slot_depth; > - } > - > - path_len = domain_len + slot_len * slot_depth; > - > - /* Allocate memory, fill in the terminating null byte. */ > - path = g_malloc(path_len + 1 /* For '\0' */); > - path[path_len] = '\0'; > - > - /* First field is the domain. */ > - s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus)); > - assert(s == domain_len); > - memcpy(path, domain, domain_len); > - > - /* Fill in slot numbers. We walk up from device to root, so need to print > - * them in the reverse order, last to first. */ > - p = path + path_len; > - for (t = d; t; t = t->bus->parent_dev) { > - p -= slot_len; > - s = snprintf(slot, sizeof slot, ":%02x.%x", > - PCI_SLOT(t->devfn), PCI_FUNC(t->devfn)); > - assert(s == slot_len); > - memcpy(p, slot, slot_len); > - } > - > - return path; > -} > - > -static int pci_qdev_find_recursive(PCIBus *bus, > - const char *id, PCIDevice **pdev) > -{ > - DeviceState *qdev = qdev_find_recursive(&bus->qbus, id); > - if (!qdev) { > - return -ENODEV; > - } > - > - /* roughly check if given qdev is pci device */ > - if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) { > - *pdev = PCI_DEVICE(qdev); > - return 0; > - } > - return -EINVAL; > -} > - > -int pci_qdev_find_device(const char *id, PCIDevice **pdev) > -{ > - struct PCIHostBus *host; > - int rc = -ENODEV; > - > - QLIST_FOREACH(host, &host_buses, next) { > - int tmp = pci_qdev_find_recursive(host->bus, id, pdev); > - if (!tmp) { > - rc = 0; > - break; > - } > - if (tmp != -ENODEV) { > - rc = tmp; > - } > - } > - > - return rc; > -} > - > -MemoryRegion *pci_address_space(PCIDevice *dev) > -{ > - return dev->bus->address_space_mem; > -} > - > -MemoryRegion *pci_address_space_io(PCIDevice *dev) > -{ > - return dev->bus->address_space_io; > -} > - > -static void pci_device_class_init(ObjectClass *klass, void *data) > -{ > - DeviceClass *k = DEVICE_CLASS(klass); > - k->init = pci_qdev_init; > - k->unplug = pci_unplug_device; > - k->exit = pci_unregister_device; > - k->bus_type = TYPE_PCI_BUS; > - k->props = pci_props; > -} > - > -void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque) > -{ > - bus->dma_context_fn = fn; > - bus->dma_context_opaque = opaque; > -} > - > -static TypeInfo pci_device_type_info = { > - .name = TYPE_PCI_DEVICE, > - .parent = TYPE_DEVICE, > - .instance_size = sizeof(PCIDevice), > - .abstract = true, > - .class_size = sizeof(PCIDeviceClass), > - .class_init = pci_device_class_init, > -}; > - > -static void pci_register_types(void) > -{ > - type_register_static(&pci_bus_info); > - type_register_static(&pci_device_type_info); > -} > - > -type_init(pci_register_types) > diff --git a/hw/pci.h b/hw/pci.h > deleted file mode 100644 > index 4da0c2a..0000000 > --- a/hw/pci.h > +++ /dev/null > @@ -1,684 +0,0 @@ > -#ifndef QEMU_PCI_H > -#define QEMU_PCI_H > - > -#include "qemu-common.h" > - > -#include "qdev.h" > -#include "memory.h" > -#include "dma.h" > - > -/* PCI includes legacy ISA access. */ > -#include "isa.h" > - > -#include "pcie.h" > - > -/* PCI bus */ > - > -#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) > -#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) > -#define PCI_FUNC(devfn) ((devfn) & 0x07) > -#define PCI_SLOT_MAX 32 > -#define PCI_FUNC_MAX 8 > - > -/* Class, Vendor and Device IDs from Linux's pci_ids.h */ > -#include "pci_ids.h" > - > -/* QEMU-specific Vendor and Device ID definitions */ > - > -/* IBM (0x1014) */ > -#define PCI_DEVICE_ID_IBM_440GX 0x027f > -#define PCI_DEVICE_ID_IBM_OPENPIC2 0xffff > - > -/* Hitachi (0x1054) */ > -#define PCI_VENDOR_ID_HITACHI 0x1054 > -#define PCI_DEVICE_ID_HITACHI_SH7751R 0x350e > - > -/* Apple (0x106b) */ > -#define PCI_DEVICE_ID_APPLE_343S1201 0x0010 > -#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI 0x001e > -#define PCI_DEVICE_ID_APPLE_UNI_N_PCI 0x001f > -#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL 0x0022 > -#define PCI_DEVICE_ID_APPLE_IPID_USB 0x003f > - > -/* Realtek (0x10ec) */ > -#define PCI_DEVICE_ID_REALTEK_8029 0x8029 > - > -/* Xilinx (0x10ee) */ > -#define PCI_DEVICE_ID_XILINX_XC2VP30 0x0300 > - > -/* Marvell (0x11ab) */ > -#define PCI_DEVICE_ID_MARVELL_GT6412X 0x4620 > - > -/* QEMU/Bochs VGA (0x1234) */ > -#define PCI_VENDOR_ID_QEMU 0x1234 > -#define PCI_DEVICE_ID_QEMU_VGA 0x1111 > - > -/* VMWare (0x15ad) */ > -#define PCI_VENDOR_ID_VMWARE 0x15ad > -#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 > -#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 > -#define PCI_DEVICE_ID_VMWARE_NET 0x0720 > -#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 > -#define PCI_DEVICE_ID_VMWARE_IDE 0x1729 > - > -/* Intel (0x8086) */ > -#define PCI_DEVICE_ID_INTEL_82551IT 0x1209 > -#define PCI_DEVICE_ID_INTEL_82557 0x1229 > -#define PCI_DEVICE_ID_INTEL_82801IR 0x2922 > - > -/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */ > -#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 > -#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4 > -#define PCI_SUBDEVICE_ID_QEMU 0x1100 > - > -#define PCI_DEVICE_ID_VIRTIO_NET 0x1000 > -#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 > -#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 > -#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 > -#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 > -#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 > - > -#define FMT_PCIBUS PRIx64 > - > -typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, > - uint32_t address, uint32_t data, int len); > -typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, > - uint32_t address, int len); > -typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, > - pcibus_t addr, pcibus_t size, int type); > -typedef void PCIUnregisterFunc(PCIDevice *pci_dev); > - > -typedef struct PCIIORegion { > - pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ > -#define PCI_BAR_UNMAPPED (~(pcibus_t)0) > - pcibus_t size; > - uint8_t type; > - MemoryRegion *memory; > - MemoryRegion *address_space; > -} PCIIORegion; > - > -#define PCI_ROM_SLOT 6 > -#define PCI_NUM_REGIONS 7 > - > -#include "pci_regs.h" > - > -/* PCI HEADER_TYPE */ > -#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 > - > -/* Size of the standard PCI config header */ > -#define PCI_CONFIG_HEADER_SIZE 0x40 > -/* Size of the standard PCI config space */ > -#define PCI_CONFIG_SPACE_SIZE 0x100 > -/* Size of the standart PCIe config space: 4KB */ > -#define PCIE_CONFIG_SPACE_SIZE 0x1000 > - > -#define PCI_NUM_PINS 4 /* A-D */ > - > -/* Bits in cap_present field. */ > -enum { > - QEMU_PCI_CAP_MSI = 0x1, > - QEMU_PCI_CAP_MSIX = 0x2, > - QEMU_PCI_CAP_EXPRESS = 0x4, > - > - /* multifunction capable device */ > -#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3 > - QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR), > - > - /* command register SERR bit enabled */ > -#define QEMU_PCI_CAP_SERR_BITNR 4 > - QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR), > - /* Standard hot plug controller. */ > -#define QEMU_PCI_SHPC_BITNR 5 > - QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR), > -#define QEMU_PCI_SLOTID_BITNR 6 > - QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_BITNR), > -}; > - > -#define TYPE_PCI_DEVICE "pci-device" > -#define PCI_DEVICE(obj) \ > - OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE) > -#define PCI_DEVICE_CLASS(klass) \ > - OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE) > -#define PCI_DEVICE_GET_CLASS(obj) \ > - OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE) > - > -typedef struct PCIINTxRoute { > - enum { > - PCI_INTX_ENABLED, > - PCI_INTX_INVERTED, > - PCI_INTX_DISABLED, > - } mode; > - int irq; > -} PCIINTxRoute; > - > -typedef struct PCIDeviceClass { > - DeviceClass parent_class; > - > - int (*init)(PCIDevice *dev); > - PCIUnregisterFunc *exit; > - PCIConfigReadFunc *config_read; > - PCIConfigWriteFunc *config_write; > - > - uint16_t vendor_id; > - uint16_t device_id; > - uint8_t revision; > - uint16_t class_id; > - uint16_t subsystem_vendor_id; /* only for header type = 0 */ > - uint16_t subsystem_id; /* only for header type = 0 */ > - > - /* > - * pci-to-pci bridge or normal device. > - * This doesn't mean pci host switch. > - * When card bus bridge is supported, this would be enhanced. > - */ > - int is_bridge; > - > - /* pcie stuff */ > - int is_express; /* is this device pci express? */ > - > - /* device isn't hot-pluggable */ > - int no_hotplug; > - > - /* rom bar */ > - const char *romfile; > -} PCIDeviceClass; > - > -typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev); > -typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector, > - MSIMessage msg); > -typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector); > - > -struct PCIDevice { > - DeviceState qdev; > - > - /* PCI config space */ > - uint8_t *config; > - > - /* Used to enable config checks on load. Note that writable bits are > - * never checked even if set in cmask. */ > - uint8_t *cmask; > - > - /* Used to implement R/W bytes */ > - uint8_t *wmask; > - > - /* Used to implement RW1C(Write 1 to Clear) bytes */ > - uint8_t *w1cmask; > - > - /* Used to allocate config space for capabilities. */ > - uint8_t *used; > - > - /* the following fields are read only */ > - PCIBus *bus; > - int32_t devfn; > - char name[64]; > - PCIIORegion io_regions[PCI_NUM_REGIONS]; > - AddressSpace bus_master_as; > - MemoryRegion bus_master_enable_region; > - DMAContext *dma; > - > - /* do not access the following fields */ > - PCIConfigReadFunc *config_read; > - PCIConfigWriteFunc *config_write; > - > - /* IRQ objects for the INTA-INTD pins. */ > - qemu_irq *irq; > - > - /* Current IRQ levels. Used internally by the generic PCI code. */ > - uint8_t irq_state; > - > - /* Capability bits */ > - uint32_t cap_present; > - > - /* Offset of MSI-X capability in config space */ > - uint8_t msix_cap; > - > - /* MSI-X entries */ > - int msix_entries_nr; > - > - /* Space to store MSIX table & pending bit array */ > - uint8_t *msix_table; > - uint8_t *msix_pba; > - /* MemoryRegion container for msix exclusive BAR setup */ > - MemoryRegion msix_exclusive_bar; > - /* Memory Regions for MSIX table and pending bit entries. */ > - MemoryRegion msix_table_mmio; > - MemoryRegion msix_pba_mmio; > - /* Reference-count for entries actually in use by driver. */ > - unsigned *msix_entry_used; > - /* MSIX function mask set or MSIX disabled */ > - bool msix_function_masked; > - /* Version id needed for VMState */ > - int32_t version_id; > - > - /* Offset of MSI capability in config space */ > - uint8_t msi_cap; > - > - /* PCI Express */ > - PCIExpressDevice exp; > - > - /* SHPC */ > - SHPCDevice *shpc; > - > - /* Location of option rom */ > - char *romfile; > - bool has_rom; > - MemoryRegion rom; > - uint32_t rom_bar; > - > - /* INTx routing notifier */ > - PCIINTxRoutingNotifier intx_routing_notifier; > - > - /* MSI-X notifiers */ > - MSIVectorUseNotifier msix_vector_use_notifier; > - MSIVectorReleaseNotifier msix_vector_release_notifier; > -}; > - > -void pci_register_bar(PCIDevice *pci_dev, int region_num, > - uint8_t attr, MemoryRegion *memory); > -pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num); > - > -int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, > - uint8_t offset, uint8_t size); > - > -void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); > - > -uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id); > - > - > -uint32_t pci_default_read_config(PCIDevice *d, > - uint32_t address, int len); > -void pci_default_write_config(PCIDevice *d, > - uint32_t address, uint32_t val, int len); > -void pci_device_save(PCIDevice *s, QEMUFile *f); > -int pci_device_load(PCIDevice *s, QEMUFile *f); > -MemoryRegion *pci_address_space(PCIDevice *dev); > -MemoryRegion *pci_address_space_io(PCIDevice *dev); > - > -typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); > -typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); > -typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin); > - > -typedef enum { > - PCI_HOTPLUG_DISABLED, > - PCI_HOTPLUG_ENABLED, > - PCI_COLDPLUG_ENABLED, > -} PCIHotplugState; > - > -typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, > - PCIHotplugState state); > -void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, > - const char *name, > - MemoryRegion *address_space_mem, > - MemoryRegion *address_space_io, > - uint8_t devfn_min); > -PCIBus *pci_bus_new(DeviceState *parent, const char *name, > - MemoryRegion *address_space_mem, > - MemoryRegion *address_space_io, > - uint8_t devfn_min); > -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > - void *irq_opaque, int nirq); > -int pci_bus_get_irq_level(PCIBus *bus, int irq_num); > -void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev); > -/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */ > -int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin); > -PCIBus *pci_register_bus(DeviceState *parent, const char *name, > - pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > - void *irq_opaque, > - MemoryRegion *address_space_mem, > - MemoryRegion *address_space_io, > - uint8_t devfn_min, int nirq); > -void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn); > -PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin); > -bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new); > -void pci_bus_fire_intx_routing_notifier(PCIBus *bus); > -void pci_device_set_intx_routing_notifier(PCIDevice *dev, > - PCIINTxRoutingNotifier notifier); > -void pci_device_reset(PCIDevice *dev); > -void pci_bus_reset(PCIBus *bus); > - > -PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, > - const char *default_devaddr); > -PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, > - const char *default_devaddr); > - > -PCIDevice *pci_vga_init(PCIBus *bus); > - > -int pci_bus_num(PCIBus *s); > -void pci_for_each_device(PCIBus *bus, int bus_num, > - void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque), > - void *opaque); > -PCIBus *pci_find_root_bus(int domain); > -int pci_find_domain(const PCIBus *bus); > -PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn); > -int pci_qdev_find_device(const char *id, PCIDevice **pdev); > -PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr); > - > -int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, > - unsigned *slotp); > - > -void pci_device_deassert_intx(PCIDevice *dev); > - > -typedef DMAContext *(*PCIDMAContextFunc)(PCIBus *, void *, int); > - > -void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque); > - > -static inline void > -pci_set_byte(uint8_t *config, uint8_t val) > -{ > - *config = val; > -} > - > -static inline uint8_t > -pci_get_byte(const uint8_t *config) > -{ > - return *config; > -} > - > -static inline void > -pci_set_word(uint8_t *config, uint16_t val) > -{ > - cpu_to_le16wu((uint16_t *)config, val); > -} > - > -static inline uint16_t > -pci_get_word(const uint8_t *config) > -{ > - return le16_to_cpupu((const uint16_t *)config); > -} > - > -static inline void > -pci_set_long(uint8_t *config, uint32_t val) > -{ > - cpu_to_le32wu((uint32_t *)config, val); > -} > - > -static inline uint32_t > -pci_get_long(const uint8_t *config) > -{ > - return le32_to_cpupu((const uint32_t *)config); > -} > - > -static inline void > -pci_set_quad(uint8_t *config, uint64_t val) > -{ > - cpu_to_le64w((uint64_t *)config, val); > -} > - > -static inline uint64_t > -pci_get_quad(const uint8_t *config) > -{ > - return le64_to_cpup((const uint64_t *)config); > -} > - > -static inline void > -pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val) > -{ > - pci_set_word(&pci_config[PCI_VENDOR_ID], val); > -} > - > -static inline void > -pci_config_set_device_id(uint8_t *pci_config, uint16_t val) > -{ > - pci_set_word(&pci_config[PCI_DEVICE_ID], val); > -} > - > -static inline void > -pci_config_set_revision(uint8_t *pci_config, uint8_t val) > -{ > - pci_set_byte(&pci_config[PCI_REVISION_ID], val); > -} > - > -static inline void > -pci_config_set_class(uint8_t *pci_config, uint16_t val) > -{ > - pci_set_word(&pci_config[PCI_CLASS_DEVICE], val); > -} > - > -static inline void > -pci_config_set_prog_interface(uint8_t *pci_config, uint8_t val) > -{ > - pci_set_byte(&pci_config[PCI_CLASS_PROG], val); > -} > - > -static inline void > -pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val) > -{ > - pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val); > -} > - > -/* > - * helper functions to do bit mask operation on configuration space. > - * Just to set bit, use test-and-set and discard returned value. > - * Just to clear bit, use test-and-clear and discard returned value. > - * NOTE: They aren't atomic. > - */ > -static inline uint8_t > -pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask) > -{ > - uint8_t val = pci_get_byte(config); > - pci_set_byte(config, val & ~mask); > - return val & mask; > -} > - > -static inline uint8_t > -pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask) > -{ > - uint8_t val = pci_get_byte(config); > - pci_set_byte(config, val | mask); > - return val & mask; > -} > - > -static inline uint16_t > -pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask) > -{ > - uint16_t val = pci_get_word(config); > - pci_set_word(config, val & ~mask); > - return val & mask; > -} > - > -static inline uint16_t > -pci_word_test_and_set_mask(uint8_t *config, uint16_t mask) > -{ > - uint16_t val = pci_get_word(config); > - pci_set_word(config, val | mask); > - return val & mask; > -} > - > -static inline uint32_t > -pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask) > -{ > - uint32_t val = pci_get_long(config); > - pci_set_long(config, val & ~mask); > - return val & mask; > -} > - > -static inline uint32_t > -pci_long_test_and_set_mask(uint8_t *config, uint32_t mask) > -{ > - uint32_t val = pci_get_long(config); > - pci_set_long(config, val | mask); > - return val & mask; > -} > - > -static inline uint64_t > -pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask) > -{ > - uint64_t val = pci_get_quad(config); > - pci_set_quad(config, val & ~mask); > - return val & mask; > -} > - > -static inline uint64_t > -pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask) > -{ > - uint64_t val = pci_get_quad(config); > - pci_set_quad(config, val | mask); > - return val & mask; > -} > - > -/* Access a register specified by a mask */ > -static inline void > -pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg) > -{ > - uint8_t val = pci_get_byte(config); > - uint8_t rval = reg << (ffs(mask) - 1); > - pci_set_byte(config, (~mask & val) | (mask & rval)); > -} > - > -static inline uint8_t > -pci_get_byte_by_mask(uint8_t *config, uint8_t mask) > -{ > - uint8_t val = pci_get_byte(config); > - return (val & mask) >> (ffs(mask) - 1); > -} > - > -static inline void > -pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg) > -{ > - uint16_t val = pci_get_word(config); > - uint16_t rval = reg << (ffs(mask) - 1); > - pci_set_word(config, (~mask & val) | (mask & rval)); > -} > - > -static inline uint16_t > -pci_get_word_by_mask(uint8_t *config, uint16_t mask) > -{ > - uint16_t val = pci_get_word(config); > - return (val & mask) >> (ffs(mask) - 1); > -} > - > -static inline void > -pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg) > -{ > - uint32_t val = pci_get_long(config); > - uint32_t rval = reg << (ffs(mask) - 1); > - pci_set_long(config, (~mask & val) | (mask & rval)); > -} > - > -static inline uint32_t > -pci_get_long_by_mask(uint8_t *config, uint32_t mask) > -{ > - uint32_t val = pci_get_long(config); > - return (val & mask) >> (ffs(mask) - 1); > -} > - > -static inline void > -pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg) > -{ > - uint64_t val = pci_get_quad(config); > - uint64_t rval = reg << (ffs(mask) - 1); > - pci_set_quad(config, (~mask & val) | (mask & rval)); > -} > - > -static inline uint64_t > -pci_get_quad_by_mask(uint8_t *config, uint64_t mask) > -{ > - uint64_t val = pci_get_quad(config); > - return (val & mask) >> (ffs(mask) - 1); > -} > - > -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, > - const char *name); > -PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, > - bool multifunction, > - const char *name); > -PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); > -PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name); > - > -static inline int pci_is_express(const PCIDevice *d) > -{ > - return d->cap_present & QEMU_PCI_CAP_EXPRESS; > -} > - > -static inline uint32_t pci_config_size(const PCIDevice *d) > -{ > - return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; > -} > - > -/* DMA access functions */ > -static inline DMAContext *pci_dma_context(PCIDevice *dev) > -{ > - return dev->dma; > -} > - > -static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, > - void *buf, dma_addr_t len, DMADirection dir) > -{ > - dma_memory_rw(pci_dma_context(dev), addr, buf, len, dir); > - return 0; > -} > - > -static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr, > - void *buf, dma_addr_t len) > -{ > - return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE); > -} > - > -static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr, > - const void *buf, dma_addr_t len) > -{ > - return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE); > -} > - > -#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ > - static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \ > - dma_addr_t addr) \ > - { \ > - return ld##_l##_dma(pci_dma_context(dev), addr); \ > - } \ > - static inline void st##_s##_pci_dma(PCIDevice *dev, \ > - dma_addr_t addr, uint##_bits##_t val) \ > - { \ > - st##_s##_dma(pci_dma_context(dev), addr, val); \ > - } > - > -PCI_DMA_DEFINE_LDST(ub, b, 8); > -PCI_DMA_DEFINE_LDST(uw_le, w_le, 16) > -PCI_DMA_DEFINE_LDST(l_le, l_le, 32); > -PCI_DMA_DEFINE_LDST(q_le, q_le, 64); > -PCI_DMA_DEFINE_LDST(uw_be, w_be, 16) > -PCI_DMA_DEFINE_LDST(l_be, l_be, 32); > -PCI_DMA_DEFINE_LDST(q_be, q_be, 64); > - > -#undef PCI_DMA_DEFINE_LDST > - > -static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, > - dma_addr_t *plen, DMADirection dir) > -{ > - void *buf; > - > - buf = dma_memory_map(pci_dma_context(dev), addr, plen, dir); > - return buf; > -} > - > -static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len, > - DMADirection dir, dma_addr_t access_len) > -{ > - dma_memory_unmap(pci_dma_context(dev), buffer, len, dir, access_len); > -} > - > -static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev, > - int alloc_hint) > -{ > - qemu_sglist_init(qsg, alloc_hint, pci_dma_context(dev)); > -} > - > -extern const VMStateDescription vmstate_pci_device; > - > -#define VMSTATE_PCI_DEVICE(_field, _state) { \ > - .name = (stringify(_field)), \ > - .size = sizeof(PCIDevice), \ > - .vmsd = &vmstate_pci_device, \ > - .flags = VMS_STRUCT, \ > - .offset = vmstate_offset_value(_state, _field, PCIDevice), \ > -} > - > -#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { \ > - .name = (stringify(_field)), \ > - .size = sizeof(PCIDevice), \ > - .vmsd = &vmstate_pci_device, \ > - .flags = VMS_STRUCT|VMS_POINTER, \ > - .offset = vmstate_offset_pointer(_state, _field, PCIDevice), \ > -} > - > -#endif > diff --git a/hw/pci/Makefile.objs b/hw/pci/Makefile.objs > new file mode 100644 > index 0000000..9d21952 > --- /dev/null > +++ b/hw/pci/Makefile.objs > @@ -0,0 +1,6 @@ > +common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o > +common-obj-$(CONFIG_PCI) += msix.o msi.o > +common-obj-$(CONFIG_PCI) += shpc.o > +common-obj-$(CONFIG_PCI) += slotid_cap.o > +common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o > +common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o > diff --git a/hw/pci/msi.c b/hw/pci/msi.c > new file mode 100644 > index 0000000..33037a8 > --- /dev/null > +++ b/hw/pci/msi.c > @@ -0,0 +1,395 @@ > +/* > + * msi.c > + * > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "msi.h" > +#include "range.h" > + > +/* Eventually those constants should go to Linux pci_regs.h */ > +#define PCI_MSI_PENDING_32 0x10 > +#define PCI_MSI_PENDING_64 0x14 > + > +/* PCI_MSI_ADDRESS_LO */ > +#define PCI_MSI_ADDRESS_LO_MASK (~0x3) > + > +/* If we get rid of cap allocator, we won't need those. */ > +#define PCI_MSI_32_SIZEOF 0x0a > +#define PCI_MSI_64_SIZEOF 0x0e > +#define PCI_MSI_32M_SIZEOF 0x14 > +#define PCI_MSI_64M_SIZEOF 0x18 > + > +#define PCI_MSI_VECTORS_MAX 32 > + > +/* Flag for interrupt controller to declare MSI/MSI-X support */ > +bool msi_supported; > + > +/* If we get rid of cap allocator, we won't need this. */ > +static inline uint8_t msi_cap_sizeof(uint16_t flags) > +{ > + switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) { > + case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT: > + return PCI_MSI_64M_SIZEOF; > + case PCI_MSI_FLAGS_64BIT: > + return PCI_MSI_64_SIZEOF; > + case PCI_MSI_FLAGS_MASKBIT: > + return PCI_MSI_32M_SIZEOF; > + case 0: > + return PCI_MSI_32_SIZEOF; > + default: > + abort(); > + break; > + } > + return 0; > +} > + > +//#define MSI_DEBUG > + > +#ifdef MSI_DEBUG > +# define MSI_DPRINTF(fmt, ...) \ > + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > +#else > +# define MSI_DPRINTF(fmt, ...) do { } while (0) > +#endif > +#define MSI_DEV_PRINTF(dev, fmt, ...) \ > + MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > + > +static inline unsigned int msi_nr_vectors(uint16_t flags) > +{ > + return 1U << > + ((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1)); > +} > + > +static inline uint8_t msi_flags_off(const PCIDevice* dev) > +{ > + return dev->msi_cap + PCI_MSI_FLAGS; > +} > + > +static inline uint8_t msi_address_lo_off(const PCIDevice* dev) > +{ > + return dev->msi_cap + PCI_MSI_ADDRESS_LO; > +} > + > +static inline uint8_t msi_address_hi_off(const PCIDevice* dev) > +{ > + return dev->msi_cap + PCI_MSI_ADDRESS_HI; > +} > + > +static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit) > +{ > + return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32); > +} > + > +static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit) > +{ > + return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32); > +} > + > +static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit) > +{ > + return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_PENDING_32); > +} > + > +/* > + * Special API for POWER to configure the vectors through > + * a side channel. Should never be used by devices. > + */ > +void msi_set_message(PCIDevice *dev, MSIMessage msg) > +{ > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > + > + if (msi64bit) { > + pci_set_quad(dev->config + msi_address_lo_off(dev), msg.address); > + } else { > + pci_set_long(dev->config + msi_address_lo_off(dev), msg.address); > + } > + pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data); > +} > + > +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) > +{ > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > + unsigned int nr_vectors = msi_nr_vectors(flags); > + MSIMessage msg; > + > + assert(vector < nr_vectors); > + > + if (msi64bit) { > + msg.address = pci_get_quad(dev->config + msi_address_lo_off(dev)); > + } else { > + msg.address = pci_get_long(dev->config + msi_address_lo_off(dev)); > + } > + > + /* upper bit 31:16 is zero */ > + msg.data = pci_get_word(dev->config + msi_data_off(dev, msi64bit)); > + if (nr_vectors > 1) { > + msg.data &= ~(nr_vectors - 1); > + msg.data |= vector; > + } > + > + return msg; > +} > + > +bool msi_enabled(const PCIDevice *dev) > +{ > + return msi_present(dev) && > + (pci_get_word(dev->config + msi_flags_off(dev)) & > + PCI_MSI_FLAGS_ENABLE); > +} > + > +int msi_init(struct PCIDevice *dev, uint8_t offset, > + unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask) > +{ > + unsigned int vectors_order; > + uint16_t flags; > + uint8_t cap_size; > + int config_offset; > + > + if (!msi_supported) { > + return -ENOTSUP; > + } > + > + MSI_DEV_PRINTF(dev, > + "init offset: 0x%"PRIx8" vector: %"PRId8 > + " 64bit %d mask %d\n", > + offset, nr_vectors, msi64bit, msi_per_vector_mask); > + > + assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */ > + assert(nr_vectors > 0); > + assert(nr_vectors <= PCI_MSI_VECTORS_MAX); > + /* the nr of MSI vectors is up to 32 */ > + vectors_order = ffs(nr_vectors) - 1; > + > + flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1); > + if (msi64bit) { > + flags |= PCI_MSI_FLAGS_64BIT; > + } > + if (msi_per_vector_mask) { > + flags |= PCI_MSI_FLAGS_MASKBIT; > + } > + > + cap_size = msi_cap_sizeof(flags); > + config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size); > + if (config_offset < 0) { > + return config_offset; > + } > + > + dev->msi_cap = config_offset; > + dev->cap_present |= QEMU_PCI_CAP_MSI; > + > + pci_set_word(dev->config + msi_flags_off(dev), flags); > + pci_set_word(dev->wmask + msi_flags_off(dev), > + PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); > + pci_set_long(dev->wmask + msi_address_lo_off(dev), > + PCI_MSI_ADDRESS_LO_MASK); > + if (msi64bit) { > + pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff); > + } > + pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff); > + > + if (msi_per_vector_mask) { > + /* Make mask bits 0 to nr_vectors - 1 writable. */ > + pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit), > + 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors)); > + } > + return config_offset; > +} > + > +void msi_uninit(struct PCIDevice *dev) > +{ > + uint16_t flags; > + uint8_t cap_size; > + > + if (!msi_present(dev)) { > + return; > + } > + flags = pci_get_word(dev->config + msi_flags_off(dev)); > + cap_size = msi_cap_sizeof(flags); > + pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size); > + dev->cap_present &= ~QEMU_PCI_CAP_MSI; > + > + MSI_DEV_PRINTF(dev, "uninit\n"); > +} > + > +void msi_reset(PCIDevice *dev) > +{ > + uint16_t flags; > + bool msi64bit; > + > + if (!msi_present(dev)) { > + return; > + } > + > + flags = pci_get_word(dev->config + msi_flags_off(dev)); > + flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); > + msi64bit = flags & PCI_MSI_FLAGS_64BIT; > + > + pci_set_word(dev->config + msi_flags_off(dev), flags); > + pci_set_long(dev->config + msi_address_lo_off(dev), 0); > + if (msi64bit) { > + pci_set_long(dev->config + msi_address_hi_off(dev), 0); > + } > + pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0); > + if (flags & PCI_MSI_FLAGS_MASKBIT) { > + pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0); > + pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0); > + } > + MSI_DEV_PRINTF(dev, "reset\n"); > +} > + > +static bool msi_is_masked(const PCIDevice *dev, unsigned int vector) > +{ > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > + uint32_t mask; > + assert(vector < PCI_MSI_VECTORS_MAX); > + > + if (!(flags & PCI_MSI_FLAGS_MASKBIT)) { > + return false; > + } > + > + mask = pci_get_long(dev->config + > + msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT)); > + return mask & (1U << vector); > +} > + > +void msi_notify(PCIDevice *dev, unsigned int vector) > +{ > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > + unsigned int nr_vectors = msi_nr_vectors(flags); > + MSIMessage msg; > + > + assert(vector < nr_vectors); > + if (msi_is_masked(dev, vector)) { > + assert(flags & PCI_MSI_FLAGS_MASKBIT); > + pci_long_test_and_set_mask( > + dev->config + msi_pending_off(dev, msi64bit), 1U << vector); > + MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector); > + return; > + } > + > + msg = msi_get_message(dev, vector); > + > + MSI_DEV_PRINTF(dev, > + "notify vector 0x%x" > + " address: 0x%"PRIx64" data: 0x%"PRIx32"\n", > + vector, msg.address, msg.data); > + stl_le_phys(msg.address, msg.data); > +} > + > +/* Normally called by pci_default_write_config(). */ > +void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len) > +{ > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > + bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT; > + unsigned int nr_vectors; > + uint8_t log_num_vecs; > + uint8_t log_max_vecs; > + unsigned int vector; > + uint32_t pending; > + > + if (!msi_present(dev) || > + !ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) { > + return; > + } > + > +#ifdef MSI_DEBUG > + MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n", > + addr, val, len); > + MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32, > + flags, > + pci_get_long(dev->config + msi_address_lo_off(dev))); > + if (msi64bit) { > + fprintf(stderr, " address-hi: 0x%"PRIx32, > + pci_get_long(dev->config + msi_address_hi_off(dev))); > + } > + fprintf(stderr, " data: 0x%"PRIx16, > + pci_get_word(dev->config + msi_data_off(dev, msi64bit))); > + if (flags & PCI_MSI_FLAGS_MASKBIT) { > + fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32, > + pci_get_long(dev->config + msi_mask_off(dev, msi64bit)), > + pci_get_long(dev->config + msi_pending_off(dev, msi64bit))); > + } > + fprintf(stderr, "\n"); > +#endif > + > + if (!(flags & PCI_MSI_FLAGS_ENABLE)) { > + return; > + } > + > + /* > + * Now MSI is enabled, clear INTx# interrupts. > + * the driver is prohibited from writing enable bit to mask > + * a service request. But the guest OS could do this. > + * So we just discard the interrupts as moderate fallback. > + * > + * 6.8.3.3. Enabling Operation > + * While enabled for MSI or MSI-X operation, a function is prohibited > + * from using its INTx# pin (if implemented) to request > + * service (MSI, MSI-X, and INTx# are mutually exclusive). > + */ > + pci_device_deassert_intx(dev); > + > + /* > + * nr_vectors might be set bigger than capable. So clamp it. > + * This is not legal by spec, so we can do anything we like, > + * just don't crash the host > + */ > + log_num_vecs = > + (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1); > + log_max_vecs = > + (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1); > + if (log_num_vecs > log_max_vecs) { > + flags &= ~PCI_MSI_FLAGS_QSIZE; > + flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1); > + pci_set_word(dev->config + msi_flags_off(dev), flags); > + } > + > + if (!msi_per_vector_mask) { > + /* if per vector masking isn't supported, > + there is no pending interrupt. */ > + return; > + } > + > + nr_vectors = msi_nr_vectors(flags); > + > + /* This will discard pending interrupts, if any. */ > + pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit)); > + pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors); > + pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending); > + > + /* deliver pending interrupts which are unmasked */ > + for (vector = 0; vector < nr_vectors; ++vector) { > + if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) { > + continue; > + } > + > + pci_long_test_and_clear_mask( > + dev->config + msi_pending_off(dev, msi64bit), 1U << vector); > + msi_notify(dev, vector); > + } > +} > + > +unsigned int msi_nr_vectors_allocated(const PCIDevice *dev) > +{ > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > + return msi_nr_vectors(flags); > +} > diff --git a/hw/pci/msi.h b/hw/pci/msi.h > new file mode 100644 > index 0000000..150b09a > --- /dev/null > +++ b/hw/pci/msi.h > @@ -0,0 +1,50 @@ > +/* > + * msi.h > + * > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef QEMU_MSI_H > +#define QEMU_MSI_H > + > +#include "qemu-common.h" > +#include "pci.h" > + > +struct MSIMessage { > + uint64_t address; > + uint32_t data; > +}; > + > +extern bool msi_supported; > + > +void msi_set_message(PCIDevice *dev, MSIMessage msg); > +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector); > +bool msi_enabled(const PCIDevice *dev); > +int msi_init(struct PCIDevice *dev, uint8_t offset, > + unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask); > +void msi_uninit(struct PCIDevice *dev); > +void msi_reset(PCIDevice *dev); > +void msi_notify(PCIDevice *dev, unsigned int vector); > +void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); > +unsigned int msi_nr_vectors_allocated(const PCIDevice *dev); > + > +static inline bool msi_present(const PCIDevice *dev) > +{ > + return dev->cap_present & QEMU_PCI_CAP_MSI; > +} > + > +#endif /* QEMU_MSI_H */ > diff --git a/hw/pci/msix.c b/hw/pci/msix.c > new file mode 100644 > index 0000000..136ef09 > --- /dev/null > +++ b/hw/pci/msix.c > @@ -0,0 +1,562 @@ > +/* > + * MSI-X device support > + * > + * This module includes support for MSI-X in pci devices. > + * > + * Author: Michael S. Tsirkin <mst@redhat.com> > + * > + * 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 the > + * GNU GPL, version 2 or (at your option) any later version. > + */ > + > +#include "hw.h" > +#include "msi.h" > +#include "msix.h" > +#include "pci.h" > +#include "range.h" > + > +#define MSIX_CAP_LENGTH 12 > + > +/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */ > +#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1) > +#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8) > +#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8) > + > +static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) > +{ > + uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; > + MSIMessage msg; > + > + msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); > + msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); > + return msg; > +} > + > +/* > + * Special API for POWER to configure the vectors through > + * a side channel. Should never be used by devices. > + */ > +void msix_set_message(PCIDevice *dev, int vector, struct MSIMessage msg) > +{ > + uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; > + > + pci_set_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR, msg.address); > + pci_set_long(table_entry + PCI_MSIX_ENTRY_DATA, msg.data); > + table_entry[PCI_MSIX_ENTRY_VECTOR_CTRL] &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; > +} > + > +static uint8_t msix_pending_mask(int vector) > +{ > + return 1 << (vector % 8); > +} > + > +static uint8_t *msix_pending_byte(PCIDevice *dev, int vector) > +{ > + return dev->msix_pba + vector / 8; > +} > + > +static int msix_is_pending(PCIDevice *dev, int vector) > +{ > + return *msix_pending_byte(dev, vector) & msix_pending_mask(vector); > +} > + > +static void msix_set_pending(PCIDevice *dev, int vector) > +{ > + *msix_pending_byte(dev, vector) |= msix_pending_mask(vector); > +} > + > +static void msix_clr_pending(PCIDevice *dev, int vector) > +{ > + *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector); > +} > + > +static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask) > +{ > + unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; > + return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT; > +} > + > +static bool msix_is_masked(PCIDevice *dev, int vector) > +{ > + return msix_vector_masked(dev, vector, dev->msix_function_masked); > +} > + > +static void msix_fire_vector_notifier(PCIDevice *dev, > + unsigned int vector, bool is_masked) > +{ > + MSIMessage msg; > + int ret; > + > + if (!dev->msix_vector_use_notifier) { > + return; > + } > + if (is_masked) { > + dev->msix_vector_release_notifier(dev, vector); > + } else { > + msg = msix_get_message(dev, vector); > + ret = dev->msix_vector_use_notifier(dev, vector, msg); > + assert(ret >= 0); > + } > +} > + > +static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked) > +{ > + bool is_masked = msix_is_masked(dev, vector); > + > + if (is_masked == was_masked) { > + return; > + } > + > + msix_fire_vector_notifier(dev, vector, is_masked); > + > + if (!is_masked && msix_is_pending(dev, vector)) { > + msix_clr_pending(dev, vector); > + msix_notify(dev, vector); > + } > +} > + > +static void msix_update_function_masked(PCIDevice *dev) > +{ > + dev->msix_function_masked = !msix_enabled(dev) || > + (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK); > +} > + > +/* Handle MSI-X capability config write. */ > +void msix_write_config(PCIDevice *dev, uint32_t addr, > + uint32_t val, int len) > +{ > + unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET; > + int vector; > + bool was_masked; > + > + if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) { > + return; > + } > + > + was_masked = dev->msix_function_masked; > + msix_update_function_masked(dev); > + > + if (!msix_enabled(dev)) { > + return; > + } > + > + pci_device_deassert_intx(dev); > + > + if (dev->msix_function_masked == was_masked) { > + return; > + } > + > + for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > + msix_handle_mask_update(dev, vector, > + msix_vector_masked(dev, vector, was_masked)); > + } > +} > + > +static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr, > + unsigned size) > +{ > + PCIDevice *dev = opaque; > + > + return pci_get_long(dev->msix_table + addr); > +} > + > +static void msix_table_mmio_write(void *opaque, hwaddr addr, > + uint64_t val, unsigned size) > +{ > + PCIDevice *dev = opaque; > + int vector = addr / PCI_MSIX_ENTRY_SIZE; > + bool was_masked; > + > + was_masked = msix_is_masked(dev, vector); > + pci_set_long(dev->msix_table + addr, val); > + msix_handle_mask_update(dev, vector, was_masked); > +} > + > +static const MemoryRegionOps msix_table_mmio_ops = { > + .read = msix_table_mmio_read, > + .write = msix_table_mmio_write, > + /* TODO: MSIX should be LITTLE_ENDIAN. */ > + .endianness = DEVICE_NATIVE_ENDIAN, > + .valid = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > +}; > + > +static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, > + unsigned size) > +{ > + PCIDevice *dev = opaque; > + > + return pci_get_long(dev->msix_pba + addr); > +} > + > +static const MemoryRegionOps msix_pba_mmio_ops = { > + .read = msix_pba_mmio_read, > + /* TODO: MSIX should be LITTLE_ENDIAN. */ > + .endianness = DEVICE_NATIVE_ENDIAN, > + .valid = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > +}; > + > +static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) > +{ > + int vector; > + > + for (vector = 0; vector < nentries; ++vector) { > + unsigned offset = > + vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; > + bool was_masked = msix_is_masked(dev, vector); > + > + dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT; > + msix_handle_mask_update(dev, vector, was_masked); > + } > +} > + > +/* Initialize the MSI-X structures */ > +int msix_init(struct PCIDevice *dev, unsigned short nentries, > + MemoryRegion *table_bar, uint8_t table_bar_nr, > + unsigned table_offset, MemoryRegion *pba_bar, > + uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos) > +{ > + int cap; > + unsigned table_size, pba_size; > + uint8_t *config; > + > + /* Nothing to do if MSI is not supported by interrupt controller */ > + if (!msi_supported) { > + return -ENOTSUP; > + } > + > + if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) { > + return -EINVAL; > + } > + > + table_size = nentries * PCI_MSIX_ENTRY_SIZE; > + pba_size = QEMU_ALIGN_UP(nentries, 64) / 8; > + > + /* Sanity test: table & pba don't overlap, fit within BARs, min aligned */ > + if ((table_bar_nr == pba_bar_nr && > + ranges_overlap(table_offset, table_size, pba_offset, pba_size)) || > + table_offset + table_size > memory_region_size(table_bar) || > + pba_offset + pba_size > memory_region_size(pba_bar) || > + (table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) { > + return -EINVAL; > + } > + > + cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH); > + if (cap < 0) { > + return cap; > + } > + > + dev->msix_cap = cap; > + dev->cap_present |= QEMU_PCI_CAP_MSIX; > + config = dev->config + cap; > + > + pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1); > + dev->msix_entries_nr = nentries; > + dev->msix_function_masked = true; > + > + pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_nr); > + pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr); > + > + /* Make flags bit writable. */ > + dev->wmask[cap + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK | > + MSIX_MASKALL_MASK; > + > + dev->msix_table = g_malloc0(table_size); > + dev->msix_pba = g_malloc0(pba_size); > + dev->msix_entry_used = g_malloc0(nentries * sizeof *dev->msix_entry_used); > + > + msix_mask_all(dev, nentries); > + > + memory_region_init_io(&dev->msix_table_mmio, &msix_table_mmio_ops, dev, > + "msix-table", table_size); > + memory_region_add_subregion(table_bar, table_offset, &dev->msix_table_mmio); > + memory_region_init_io(&dev->msix_pba_mmio, &msix_pba_mmio_ops, dev, > + "msix-pba", pba_size); > + memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio); > + > + return 0; > +} > + > +int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, > + uint8_t bar_nr) > +{ > + int ret; > + char *name; > + > + /* > + * Migration compatibility dictates that this remains a 4k > + * BAR with the vector table in the lower half and PBA in > + * the upper half. Do not use these elsewhere! > + */ > +#define MSIX_EXCLUSIVE_BAR_SIZE 4096 > +#define MSIX_EXCLUSIVE_BAR_TABLE_OFFSET 0 > +#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2) > +#define MSIX_EXCLUSIVE_CAP_OFFSET 0 > + > + if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) { > + return -EINVAL; > + } > + > + name = g_strdup_printf("%s-msix", dev->name); > + memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE); > + g_free(name); > + > + ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr, > + MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar, > + bar_nr, MSIX_EXCLUSIVE_BAR_PBA_OFFSET, > + MSIX_EXCLUSIVE_CAP_OFFSET); > + if (ret) { > + memory_region_destroy(&dev->msix_exclusive_bar); > + return ret; > + } > + > + pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY, > + &dev->msix_exclusive_bar); > + > + return 0; > +} > + > +static void msix_free_irq_entries(PCIDevice *dev) > +{ > + int vector; > + > + for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > + dev->msix_entry_used[vector] = 0; > + msix_clr_pending(dev, vector); > + } > +} > + > +static void msix_clear_all_vectors(PCIDevice *dev) > +{ > + int vector; > + > + for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > + msix_clr_pending(dev, vector); > + } > +} > + > +/* Clean up resources for the device. */ > +void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar) > +{ > + if (!msix_present(dev)) { > + return; > + } > + pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH); > + dev->msix_cap = 0; > + msix_free_irq_entries(dev); > + dev->msix_entries_nr = 0; > + memory_region_del_subregion(pba_bar, &dev->msix_pba_mmio); > + memory_region_destroy(&dev->msix_pba_mmio); > + g_free(dev->msix_pba); > + dev->msix_pba = NULL; > + memory_region_del_subregion(table_bar, &dev->msix_table_mmio); > + memory_region_destroy(&dev->msix_table_mmio); > + g_free(dev->msix_table); > + dev->msix_table = NULL; > + g_free(dev->msix_entry_used); > + dev->msix_entry_used = NULL; > + dev->cap_present &= ~QEMU_PCI_CAP_MSIX; > +} > + > +void msix_uninit_exclusive_bar(PCIDevice *dev) > +{ > + if (msix_present(dev)) { > + msix_uninit(dev, &dev->msix_exclusive_bar, &dev->msix_exclusive_bar); > + memory_region_destroy(&dev->msix_exclusive_bar); > + } > +} > + > +void msix_save(PCIDevice *dev, QEMUFile *f) > +{ > + unsigned n = dev->msix_entries_nr; > + > + if (!msix_present(dev)) { > + return; > + } > + > + qemu_put_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); > + qemu_put_buffer(f, dev->msix_pba, (n + 7) / 8); > +} > + > +/* Should be called after restoring the config space. */ > +void msix_load(PCIDevice *dev, QEMUFile *f) > +{ > + unsigned n = dev->msix_entries_nr; > + unsigned int vector; > + > + if (!msix_present(dev)) { > + return; > + } > + > + msix_clear_all_vectors(dev); > + qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); > + qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8); > + msix_update_function_masked(dev); > + > + for (vector = 0; vector < n; vector++) { > + msix_handle_mask_update(dev, vector, true); > + } > +} > + > +/* Does device support MSI-X? */ > +int msix_present(PCIDevice *dev) > +{ > + return dev->cap_present & QEMU_PCI_CAP_MSIX; > +} > + > +/* Is MSI-X enabled? */ > +int msix_enabled(PCIDevice *dev) > +{ > + return (dev->cap_present & QEMU_PCI_CAP_MSIX) && > + (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > + MSIX_ENABLE_MASK); > +} > + > +/* Send an MSI-X message */ > +void msix_notify(PCIDevice *dev, unsigned vector) > +{ > + MSIMessage msg; > + > + if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) > + return; > + if (msix_is_masked(dev, vector)) { > + msix_set_pending(dev, vector); > + return; > + } > + > + msg = msix_get_message(dev, vector); > + > + stl_le_phys(msg.address, msg.data); > +} > + > +void msix_reset(PCIDevice *dev) > +{ > + if (!msix_present(dev)) { > + return; > + } > + msix_clear_all_vectors(dev); > + dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &= > + ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET]; > + memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE); > + memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8); > + msix_mask_all(dev, dev->msix_entries_nr); > +} > + > +/* PCI spec suggests that devices make it possible for software to configure > + * less vectors than supported by the device, but does not specify a standard > + * mechanism for devices to do so. > + * > + * We support this by asking devices to declare vectors software is going to > + * actually use, and checking this on the notification path. Devices that > + * don't want to follow the spec suggestion can declare all vectors as used. */ > + > +/* Mark vector as used. */ > +int msix_vector_use(PCIDevice *dev, unsigned vector) > +{ > + if (vector >= dev->msix_entries_nr) > + return -EINVAL; > + dev->msix_entry_used[vector]++; > + return 0; > +} > + > +/* Mark vector as unused. */ > +void msix_vector_unuse(PCIDevice *dev, unsigned vector) > +{ > + if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) { > + return; > + } > + if (--dev->msix_entry_used[vector]) { > + return; > + } > + msix_clr_pending(dev, vector); > +} > + > +void msix_unuse_all_vectors(PCIDevice *dev) > +{ > + if (!msix_present(dev)) { > + return; > + } > + msix_free_irq_entries(dev); > +} > + > +unsigned int msix_nr_vectors_allocated(const PCIDevice *dev) > +{ > + return dev->msix_entries_nr; > +} > + > +static int msix_set_notifier_for_vector(PCIDevice *dev, unsigned int vector) > +{ > + MSIMessage msg; > + > + if (msix_is_masked(dev, vector)) { > + return 0; > + } > + msg = msix_get_message(dev, vector); > + return dev->msix_vector_use_notifier(dev, vector, msg); > +} > + > +static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector) > +{ > + if (msix_is_masked(dev, vector)) { > + return; > + } > + dev->msix_vector_release_notifier(dev, vector); > +} > + > +int msix_set_vector_notifiers(PCIDevice *dev, > + MSIVectorUseNotifier use_notifier, > + MSIVectorReleaseNotifier release_notifier) > +{ > + int vector, ret; > + > + assert(use_notifier && release_notifier); > + > + dev->msix_vector_use_notifier = use_notifier; > + dev->msix_vector_release_notifier = release_notifier; > + > + if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > + (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { > + for (vector = 0; vector < dev->msix_entries_nr; vector++) { > + ret = msix_set_notifier_for_vector(dev, vector); > + if (ret < 0) { > + goto undo; > + } > + } > + } > + return 0; > + > +undo: > + while (--vector >= 0) { > + msix_unset_notifier_for_vector(dev, vector); > + } > + dev->msix_vector_use_notifier = NULL; > + dev->msix_vector_release_notifier = NULL; > + return ret; > +} > + > +void msix_unset_vector_notifiers(PCIDevice *dev) > +{ > + int vector; > + > + assert(dev->msix_vector_use_notifier && > + dev->msix_vector_release_notifier); > + > + if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > + (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { > + for (vector = 0; vector < dev->msix_entries_nr; vector++) { > + msix_unset_notifier_for_vector(dev, vector); > + } > + } > + dev->msix_vector_use_notifier = NULL; > + dev->msix_vector_release_notifier = NULL; > +} > diff --git a/hw/pci/msix.h b/hw/pci/msix.h > new file mode 100644 > index 0000000..15211cb > --- /dev/null > +++ b/hw/pci/msix.h > @@ -0,0 +1,41 @@ > +#ifndef QEMU_MSIX_H > +#define QEMU_MSIX_H > + > +#include "qemu-common.h" > +#include "pci.h" > + > +void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg); > +int msix_init(PCIDevice *dev, unsigned short nentries, > + MemoryRegion *table_bar, uint8_t table_bar_nr, > + unsigned table_offset, MemoryRegion *pba_bar, > + uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos); > +int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, > + uint8_t bar_nr); > + > +void msix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len); > + > +void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, > + MemoryRegion *pba_bar); > +void msix_uninit_exclusive_bar(PCIDevice *dev); > + > +unsigned int msix_nr_vectors_allocated(const PCIDevice *dev); > + > +void msix_save(PCIDevice *dev, QEMUFile *f); > +void msix_load(PCIDevice *dev, QEMUFile *f); > + > +int msix_enabled(PCIDevice *dev); > +int msix_present(PCIDevice *dev); > + > +int msix_vector_use(PCIDevice *dev, unsigned vector); > +void msix_vector_unuse(PCIDevice *dev, unsigned vector); > +void msix_unuse_all_vectors(PCIDevice *dev); > + > +void msix_notify(PCIDevice *dev, unsigned vector); > + > +void msix_reset(PCIDevice *dev); > + > +int msix_set_vector_notifiers(PCIDevice *dev, > + MSIVectorUseNotifier use_notifier, > + MSIVectorReleaseNotifier release_notifier); > +void msix_unset_vector_notifiers(PCIDevice *dev); > +#endif > diff --git a/hw/pci/pci-hotplug.c b/hw/pci/pci-hotplug.c > new file mode 100644 > index 0000000..0ca5546 > --- /dev/null > +++ b/hw/pci/pci-hotplug.c > @@ -0,0 +1,293 @@ > +/* > + * QEMU PCI hotplug support > + * > + * Copyright (c) 2004 Fabrice Bellard > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > + > +#include "hw.h" > +#include "boards.h" > +#include "pci.h" > +#include "net.h" > +#include "pc.h" > +#include "monitor.h" > +#include "scsi.h" > +#include "virtio-blk.h" > +#include "qemu-config.h" > +#include "blockdev.h" > +#include "error.h" > + > +#if defined(TARGET_I386) > +static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, > + const char *devaddr, > + const char *opts_str) > +{ > + Error *local_err = NULL; > + QemuOpts *opts; > + PCIBus *bus; > + int ret, devfn; > + > + bus = pci_get_bus_devfn(&devfn, devaddr); > + if (!bus) { > + monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); > + return NULL; > + } > + if (!((BusState*)bus)->allow_hotplug) { > + monitor_printf(mon, "PCI bus doesn't support hotplug\n"); > + return NULL; > + } > + > + opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0); > + if (!opts) { > + return NULL; > + } > + > + qemu_opt_set(opts, "type", "nic"); > + > + ret = net_client_init(opts, 0, &local_err); > + if (error_is_set(&local_err)) { > + qerror_report_err(local_err); > + error_free(local_err); > + return NULL; > + } > + if (nd_table[ret].devaddr) { > + monitor_printf(mon, "Parameter addr not supported\n"); > + return NULL; > + } > + return pci_nic_init(&nd_table[ret], "rtl8139", devaddr); > +} > + > +static int scsi_hot_add(Monitor *mon, DeviceState *adapter, > + DriveInfo *dinfo, int printinfo) > +{ > + SCSIBus *scsibus; > + SCSIDevice *scsidev; > + > + scsibus = (SCSIBus *) > + object_dynamic_cast(OBJECT(QLIST_FIRST(&adapter->child_bus)), > + TYPE_SCSI_BUS); > + if (!scsibus) { > + error_report("Device is not a SCSI adapter"); > + return -1; > + } > + > + /* > + * drive_init() tries to find a default for dinfo->unit. Doesn't > + * work at all for hotplug though as we assign the device to a > + * specific bus instead of the first bus with spare scsi ids. > + * > + * Ditch the calculated value and reload from option string (if > + * specified). > + */ > + dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1); > + dinfo->bus = scsibus->busnr; > + scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, > + false, -1); > + if (!scsidev) { > + return -1; > + } > + dinfo->unit = scsidev->id; > + > + if (printinfo) > + monitor_printf(mon, "OK bus %d, unit %d\n", > + scsibus->busnr, scsidev->id); > + return 0; > +} > + > +int pci_drive_hot_add(Monitor *mon, const QDict *qdict, > + DriveInfo *dinfo, int type) > +{ > + int dom, pci_bus; > + unsigned slot; > + PCIDevice *dev; > + const char *pci_addr = qdict_get_str(qdict, "pci_addr"); > + > + switch (type) { > + case IF_SCSI: > + if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) { > + goto err; > + } > + dev = pci_find_device(pci_find_root_bus(dom), pci_bus, > + PCI_DEVFN(slot, 0)); > + if (!dev) { > + monitor_printf(mon, "no pci device with address %s\n", pci_addr); > + goto err; > + } > + if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) != 0) { > + goto err; > + } > + break; > + default: > + monitor_printf(mon, "Can't hot-add drive to type %d\n", type); > + goto err; > + } > + > + return 0; > +err: > + return -1; > +} > + > +static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, > + const char *devaddr, > + const char *opts) > +{ > + PCIDevice *dev; > + DriveInfo *dinfo = NULL; > + int type = -1; > + char buf[128]; > + PCIBus *bus; > + int devfn; > + > + if (get_param_value(buf, sizeof(buf), "if", opts)) { > + if (!strcmp(buf, "scsi")) > + type = IF_SCSI; > + else if (!strcmp(buf, "virtio")) { > + type = IF_VIRTIO; > + } else { > + monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf); > + return NULL; > + } > + } else { > + monitor_printf(mon, "no if= specified\n"); > + return NULL; > + } > + > + if (get_param_value(buf, sizeof(buf), "file", opts)) { > + dinfo = add_init_drive(opts); > + if (!dinfo) > + return NULL; > + if (dinfo->devaddr) { > + monitor_printf(mon, "Parameter addr not supported\n"); > + return NULL; > + } > + } else { > + dinfo = NULL; > + } > + > + bus = pci_get_bus_devfn(&devfn, devaddr); > + if (!bus) { > + monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); > + return NULL; > + } > + if (!((BusState*)bus)->allow_hotplug) { > + monitor_printf(mon, "PCI bus doesn't support hotplug\n"); > + return NULL; > + } > + > + switch (type) { > + case IF_SCSI: > + dev = pci_create(bus, devfn, "lsi53c895a"); > + if (qdev_init(&dev->qdev) < 0) > + dev = NULL; > + if (dev && dinfo) { > + if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) { > + qdev_unplug(&dev->qdev, NULL); > + dev = NULL; > + } > + } > + break; > + case IF_VIRTIO: > + if (!dinfo) { > + monitor_printf(mon, "virtio requires a backing file/device.\n"); > + return NULL; > + } > + dev = pci_create(bus, devfn, "virtio-blk-pci"); > + if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) { > + qdev_free(&dev->qdev); > + dev = NULL; > + break; > + } > + if (qdev_init(&dev->qdev) < 0) > + dev = NULL; > + break; > + default: > + dev = NULL; > + } > + return dev; > +} > + > +void pci_device_hot_add(Monitor *mon, const QDict *qdict) > +{ > + PCIDevice *dev = NULL; > + const char *pci_addr = qdict_get_str(qdict, "pci_addr"); > + const char *type = qdict_get_str(qdict, "type"); > + const char *opts = qdict_get_try_str(qdict, "opts"); > + > + /* strip legacy tag */ > + if (!strncmp(pci_addr, "pci_addr=", 9)) { > + pci_addr += 9; > + } > + > + if (!opts) { > + opts = ""; > + } > + > + if (!strcmp(pci_addr, "auto")) > + pci_addr = NULL; > + > + if (strcmp(type, "nic") == 0) { > + dev = qemu_pci_hot_add_nic(mon, pci_addr, opts); > + } else if (strcmp(type, "storage") == 0) { > + dev = qemu_pci_hot_add_storage(mon, pci_addr, opts); > + } else { > + monitor_printf(mon, "invalid type: %s\n", type); > + } > + > + if (dev) { > + monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n", > + pci_find_domain(dev->bus), > + pci_bus_num(dev->bus), PCI_SLOT(dev->devfn), > + PCI_FUNC(dev->devfn)); > + } else > + monitor_printf(mon, "failed to add %s\n", opts); > +} > +#endif > + > +static int pci_device_hot_remove(Monitor *mon, const char *pci_addr) > +{ > + PCIDevice *d; > + int dom, bus; > + unsigned slot; > + Error *local_err = NULL; > + > + if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) { > + return -1; > + } > + > + d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0)); > + if (!d) { > + monitor_printf(mon, "slot %d empty\n", slot); > + return -1; > + } > + > + qdev_unplug(&d->qdev, &local_err); > + if (error_is_set(&local_err)) { > + monitor_printf(mon, "%s\n", error_get_pretty(local_err)); > + error_free(local_err); > + return -1; > + } > + > + return 0; > +} > + > +void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict) > +{ > + pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr")); > +} > diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c > new file mode 100644 > index 0000000..134c448 > --- /dev/null > +++ b/hw/pci/pci-stub.c > @@ -0,0 +1,47 @@ > +/* > + * PCI stubs for platforms that don't support pci bus. > + * > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "sysemu.h" > +#include "monitor.h" > +#include "pci.h" > +#include "qmp-commands.h" > + > +PciInfoList *qmp_query_pci(Error **errp) > +{ > + error_set(errp, QERR_UNSUPPORTED); > + return NULL; > +} > + > +static void pci_error_message(Monitor *mon) > +{ > + monitor_printf(mon, "PCI devices not supported\n"); > +} > + > +int do_pcie_aer_inject_error(Monitor *mon, > + const QDict *qdict, QObject **ret_data) > +{ > + pci_error_message(mon); > + return -ENOSYS; > +} > + > +void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) > +{ > + pci_error_message(mon); > +} > diff --git a/hw/pci/pci.c b/hw/pci/pci.c > new file mode 100644 > index 0000000..97a0cd7 > --- /dev/null > +++ b/hw/pci/pci.c > @@ -0,0 +1,2168 @@ > +/* > + * QEMU PCI bus manager > + * > + * Copyright (c) 2004 Fabrice Bellard > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > +#include "hw.h" > +#include "pci.h" > +#include "pci_bridge.h" > +#include "pci_internals.h" > +#include "monitor.h" > +#include "net.h" > +#include "sysemu.h" > +#include "loader.h" > +#include "range.h" > +#include "qmp-commands.h" > +#include "msi.h" > +#include "msix.h" > +#include "exec-memory.h" > + > +//#define DEBUG_PCI > +#ifdef DEBUG_PCI > +# define PCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) > +#else > +# define PCI_DPRINTF(format, ...) do { } while (0) > +#endif > + > +static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); > +static char *pcibus_get_dev_path(DeviceState *dev); > +static char *pcibus_get_fw_dev_path(DeviceState *dev); > +static int pcibus_reset(BusState *qbus); > + > +static Property pci_props[] = { > + DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), > + DEFINE_PROP_STRING("romfile", PCIDevice, romfile), > + DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1), > + DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present, > + QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false), > + DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present, > + QEMU_PCI_CAP_SERR_BITNR, true), > + DEFINE_PROP_END_OF_LIST() > +}; > + > +static void pci_bus_class_init(ObjectClass *klass, void *data) > +{ > + BusClass *k = BUS_CLASS(klass); > + > + k->print_dev = pcibus_dev_print; > + k->get_dev_path = pcibus_get_dev_path; > + k->get_fw_dev_path = pcibus_get_fw_dev_path; > + k->reset = pcibus_reset; > +} > + > +static const TypeInfo pci_bus_info = { > + .name = TYPE_PCI_BUS, > + .parent = TYPE_BUS, > + .instance_size = sizeof(PCIBus), > + .class_init = pci_bus_class_init, > +}; > + > +static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); > +static void pci_update_mappings(PCIDevice *d); > +static void pci_set_irq(void *opaque, int irq_num, int level); > +static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom); > +static void pci_del_option_rom(PCIDevice *pdev); > + > +static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET; > +static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU; > + > +struct PCIHostBus { > + int domain; > + struct PCIBus *bus; > + QLIST_ENTRY(PCIHostBus) next; > +}; > +static QLIST_HEAD(, PCIHostBus) host_buses; > + > +static const VMStateDescription vmstate_pcibus = { > + .name = "PCIBUS", > + .version_id = 1, > + .minimum_version_id = 1, > + .minimum_version_id_old = 1, > + .fields = (VMStateField []) { > + VMSTATE_INT32_EQUAL(nirq, PCIBus), > + VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32, int32_t), > + VMSTATE_END_OF_LIST() > + } > +}; > +static int pci_bar(PCIDevice *d, int reg) > +{ > + uint8_t type; > + > + if (reg != PCI_ROM_SLOT) > + return PCI_BASE_ADDRESS_0 + reg * 4; > + > + type = d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; > + return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; > +} > + > +static inline int pci_irq_state(PCIDevice *d, int irq_num) > +{ > + return (d->irq_state >> irq_num) & 0x1; > +} > + > +static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level) > +{ > + d->irq_state &= ~(0x1 << irq_num); > + d->irq_state |= level << irq_num; > +} > + > +static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) > +{ > + PCIBus *bus; > + for (;;) { > + bus = pci_dev->bus; > + irq_num = bus->map_irq(pci_dev, irq_num); > + if (bus->set_irq) > + break; > + pci_dev = bus->parent_dev; > + } > + bus->irq_count[irq_num] += change; > + bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); > +} > + > +int pci_bus_get_irq_level(PCIBus *bus, int irq_num) > +{ > + assert(irq_num >= 0); > + assert(irq_num < bus->nirq); > + return !!bus->irq_count[irq_num]; > +} > + > +/* Update interrupt status bit in config space on interrupt > + * state change. */ > +static void pci_update_irq_status(PCIDevice *dev) > +{ > + if (dev->irq_state) { > + dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT; > + } else { > + dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; > + } > +} > + > +void pci_device_deassert_intx(PCIDevice *dev) > +{ > + int i; > + for (i = 0; i < PCI_NUM_PINS; ++i) { > + qemu_set_irq(dev->irq[i], 0); > + } > +} > + > +/* > + * This function is called on #RST and FLR. > + * FLR if PCI_EXP_DEVCTL_BCR_FLR is set > + */ > +void pci_device_reset(PCIDevice *dev) > +{ > + int r; > + > + qdev_reset_all(&dev->qdev); > + > + dev->irq_state = 0; > + pci_update_irq_status(dev); > + pci_device_deassert_intx(dev); > + /* Clear all writable bits */ > + pci_word_test_and_clear_mask(dev->config + PCI_COMMAND, > + pci_get_word(dev->wmask + PCI_COMMAND) | > + pci_get_word(dev->w1cmask + PCI_COMMAND)); > + pci_word_test_and_clear_mask(dev->config + PCI_STATUS, > + pci_get_word(dev->wmask + PCI_STATUS) | > + pci_get_word(dev->w1cmask + PCI_STATUS)); > + dev->config[PCI_CACHE_LINE_SIZE] = 0x0; > + dev->config[PCI_INTERRUPT_LINE] = 0x0; > + for (r = 0; r < PCI_NUM_REGIONS; ++r) { > + PCIIORegion *region = &dev->io_regions[r]; > + if (!region->size) { > + continue; > + } > + > + if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) && > + region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > + pci_set_quad(dev->config + pci_bar(dev, r), region->type); > + } else { > + pci_set_long(dev->config + pci_bar(dev, r), region->type); > + } > + } > + pci_update_mappings(dev); > + > + msi_reset(dev); > + msix_reset(dev); > +} > + > +/* > + * Trigger pci bus reset under a given bus. > + * To be called on RST# assert. > + */ > +void pci_bus_reset(PCIBus *bus) > +{ > + int i; > + > + for (i = 0; i < bus->nirq; i++) { > + bus->irq_count[i] = 0; > + } > + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { > + if (bus->devices[i]) { > + pci_device_reset(bus->devices[i]); > + } > + } > +} > + > +static int pcibus_reset(BusState *qbus) > +{ > + pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus)); > + > + /* topology traverse is done by pci_bus_reset(). > + Tell qbus/qdev walker not to traverse the tree */ > + return 1; > +} > + > +static void pci_host_bus_register(int domain, PCIBus *bus) > +{ > + struct PCIHostBus *host; > + host = g_malloc0(sizeof(*host)); > + host->domain = domain; > + host->bus = bus; > + QLIST_INSERT_HEAD(&host_buses, host, next); > +} > + > +PCIBus *pci_find_root_bus(int domain) > +{ > + struct PCIHostBus *host; > + > + QLIST_FOREACH(host, &host_buses, next) { > + if (host->domain == domain) { > + return host->bus; > + } > + } > + > + return NULL; > +} > + > +int pci_find_domain(const PCIBus *bus) > +{ > + PCIDevice *d; > + struct PCIHostBus *host; > + > + /* obtain root bus */ > + while ((d = bus->parent_dev) != NULL) { > + bus = d->bus; > + } > + > + QLIST_FOREACH(host, &host_buses, next) { > + if (host->bus == bus) { > + return host->domain; > + } > + } > + > + abort(); /* should not be reached */ > + return -1; > +} > + > +void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, > + const char *name, > + MemoryRegion *address_space_mem, > + MemoryRegion *address_space_io, > + uint8_t devfn_min) > +{ > + qbus_create_inplace(&bus->qbus, TYPE_PCI_BUS, parent, name); > + assert(PCI_FUNC(devfn_min) == 0); > + bus->devfn_min = devfn_min; > + bus->address_space_mem = address_space_mem; > + bus->address_space_io = address_space_io; > + > + /* host bridge */ > + QLIST_INIT(&bus->child); > + pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */ > + > + vmstate_register(NULL, -1, &vmstate_pcibus, bus); > +} > + > +PCIBus *pci_bus_new(DeviceState *parent, const char *name, > + MemoryRegion *address_space_mem, > + MemoryRegion *address_space_io, > + uint8_t devfn_min) > +{ > + PCIBus *bus; > + > + bus = g_malloc0(sizeof(*bus)); > + pci_bus_new_inplace(bus, parent, name, address_space_mem, > + address_space_io, devfn_min); > + OBJECT(bus)->free = g_free; > + return bus; > +} > + > +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > + void *irq_opaque, int nirq) > +{ > + bus->set_irq = set_irq; > + bus->map_irq = map_irq; > + bus->irq_opaque = irq_opaque; > + bus->nirq = nirq; > + bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0])); > +} > + > +void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev) > +{ > + bus->qbus.allow_hotplug = 1; > + bus->hotplug = hotplug; > + bus->hotplug_qdev = qdev; > +} > + > +PCIBus *pci_register_bus(DeviceState *parent, const char *name, > + pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > + void *irq_opaque, > + MemoryRegion *address_space_mem, > + MemoryRegion *address_space_io, > + uint8_t devfn_min, int nirq) > +{ > + PCIBus *bus; > + > + bus = pci_bus_new(parent, name, address_space_mem, > + address_space_io, devfn_min); > + pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq); > + return bus; > +} > + > +int pci_bus_num(PCIBus *s) > +{ > + if (!s->parent_dev) > + return 0; /* pci host bridge */ > + return s->parent_dev->config[PCI_SECONDARY_BUS]; > +} > + > +static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) > +{ > + PCIDevice *s = container_of(pv, PCIDevice, config); > + uint8_t *config; > + int i; > + > + assert(size == pci_config_size(s)); > + config = g_malloc(size); > + > + qemu_get_buffer(f, config, size); > + for (i = 0; i < size; ++i) { > + if ((config[i] ^ s->config[i]) & > + s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) { > + g_free(config); > + return -EINVAL; > + } > + } > + memcpy(s->config, config, size); > + > + pci_update_mappings(s); > + > + memory_region_set_enabled(&s->bus_master_enable_region, > + pci_get_word(s->config + PCI_COMMAND) > + & PCI_COMMAND_MASTER); > + > + g_free(config); > + return 0; > +} > + > +/* just put buffer */ > +static void put_pci_config_device(QEMUFile *f, void *pv, size_t size) > +{ > + const uint8_t **v = pv; > + assert(size == pci_config_size(container_of(pv, PCIDevice, config))); > + qemu_put_buffer(f, *v, size); > +} > + > +static VMStateInfo vmstate_info_pci_config = { > + .name = "pci config", > + .get = get_pci_config_device, > + .put = put_pci_config_device, > +}; > + > +static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) > +{ > + PCIDevice *s = container_of(pv, PCIDevice, irq_state); > + uint32_t irq_state[PCI_NUM_PINS]; > + int i; > + for (i = 0; i < PCI_NUM_PINS; ++i) { > + irq_state[i] = qemu_get_be32(f); > + if (irq_state[i] != 0x1 && irq_state[i] != 0) { > + fprintf(stderr, "irq state %d: must be 0 or 1.\n", > + irq_state[i]); > + return -EINVAL; > + } > + } > + > + for (i = 0; i < PCI_NUM_PINS; ++i) { > + pci_set_irq_state(s, i, irq_state[i]); > + } > + > + return 0; > +} > + > +static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size) > +{ > + int i; > + PCIDevice *s = container_of(pv, PCIDevice, irq_state); > + > + for (i = 0; i < PCI_NUM_PINS; ++i) { > + qemu_put_be32(f, pci_irq_state(s, i)); > + } > +} > + > +static VMStateInfo vmstate_info_pci_irq_state = { > + .name = "pci irq state", > + .get = get_pci_irq_state, > + .put = put_pci_irq_state, > +}; > + > +const VMStateDescription vmstate_pci_device = { > + .name = "PCIDevice", > + .version_id = 2, > + .minimum_version_id = 1, > + .minimum_version_id_old = 1, > + .fields = (VMStateField []) { > + VMSTATE_INT32_LE(version_id, PCIDevice), > + VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, > + vmstate_info_pci_config, > + PCI_CONFIG_SPACE_SIZE), > + VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, > + vmstate_info_pci_irq_state, > + PCI_NUM_PINS * sizeof(int32_t)), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +const VMStateDescription vmstate_pcie_device = { > + .name = "PCIEDevice", > + .version_id = 2, > + .minimum_version_id = 1, > + .minimum_version_id_old = 1, > + .fields = (VMStateField []) { > + VMSTATE_INT32_LE(version_id, PCIDevice), > + VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, > + vmstate_info_pci_config, > + PCIE_CONFIG_SPACE_SIZE), > + VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, > + vmstate_info_pci_irq_state, > + PCI_NUM_PINS * sizeof(int32_t)), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s) > +{ > + return pci_is_express(s) ? &vmstate_pcie_device : &vmstate_pci_device; > +} > + > +void pci_device_save(PCIDevice *s, QEMUFile *f) > +{ > + /* Clear interrupt status bit: it is implicit > + * in irq_state which we are saving. > + * This makes us compatible with old devices > + * which never set or clear this bit. */ > + s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; > + vmstate_save_state(f, pci_get_vmstate(s), s); > + /* Restore the interrupt status bit. */ > + pci_update_irq_status(s); > +} > + > +int pci_device_load(PCIDevice *s, QEMUFile *f) > +{ > + int ret; > + ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id); > + /* Restore the interrupt status bit. */ > + pci_update_irq_status(s); > + return ret; > +} > + > +static void pci_set_default_subsystem_id(PCIDevice *pci_dev) > +{ > + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, > + pci_default_sub_vendor_id); > + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, > + pci_default_sub_device_id); > +} > + > +/* > + * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL > + * [[<domain>:]<bus>:]<slot>.<func>, return -1 on error > + */ > +static int pci_parse_devaddr(const char *addr, int *domp, int *busp, > + unsigned int *slotp, unsigned int *funcp) > +{ > + const char *p; > + char *e; > + unsigned long val; > + unsigned long dom = 0, bus = 0; > + unsigned int slot = 0; > + unsigned int func = 0; > + > + p = addr; > + val = strtoul(p, &e, 16); > + if (e == p) > + return -1; > + if (*e == ':') { > + bus = val; > + p = e + 1; > + val = strtoul(p, &e, 16); > + if (e == p) > + return -1; > + if (*e == ':') { > + dom = bus; > + bus = val; > + p = e + 1; > + val = strtoul(p, &e, 16); > + if (e == p) > + return -1; > + } > + } > + > + slot = val; > + > + if (funcp != NULL) { > + if (*e != '.') > + return -1; > + > + p = e + 1; > + val = strtoul(p, &e, 16); > + if (e == p) > + return -1; > + > + func = val; > + } > + > + /* if funcp == NULL func is 0 */ > + if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) > + return -1; > + > + if (*e) > + return -1; > + > + *domp = dom; > + *busp = bus; > + *slotp = slot; > + if (funcp != NULL) > + *funcp = func; > + return 0; > +} > + > +int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, > + unsigned *slotp) > +{ > + /* strip legacy tag */ > + if (!strncmp(addr, "pci_addr=", 9)) { > + addr += 9; > + } > + if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) { > + monitor_printf(mon, "Invalid pci address\n"); > + return -1; > + } > + return 0; > +} > + > +PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) > +{ > + int dom, bus; > + unsigned slot; > + > + if (!devaddr) { > + *devfnp = -1; > + return pci_find_bus_nr(pci_find_root_bus(0), 0); > + } > + > + if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) { > + return NULL; > + } > + > + *devfnp = PCI_DEVFN(slot, 0); > + return pci_find_bus_nr(pci_find_root_bus(dom), bus); > +} > + > +static void pci_init_cmask(PCIDevice *dev) > +{ > + pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff); > + pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff); > + dev->cmask[PCI_STATUS] = PCI_STATUS_CAP_LIST; > + dev->cmask[PCI_REVISION_ID] = 0xff; > + dev->cmask[PCI_CLASS_PROG] = 0xff; > + pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff); > + dev->cmask[PCI_HEADER_TYPE] = 0xff; > + dev->cmask[PCI_CAPABILITY_LIST] = 0xff; > +} > + > +static void pci_init_wmask(PCIDevice *dev) > +{ > + int config_size = pci_config_size(dev); > + > + dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff; > + dev->wmask[PCI_INTERRUPT_LINE] = 0xff; > + pci_set_word(dev->wmask + PCI_COMMAND, > + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | > + PCI_COMMAND_INTX_DISABLE); > + if (dev->cap_present & QEMU_PCI_CAP_SERR) { > + pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR); > + } > + > + memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff, > + config_size - PCI_CONFIG_HEADER_SIZE); > +} > + > +static void pci_init_w1cmask(PCIDevice *dev) > +{ > + /* > + * Note: It's okay to set w1cmask even for readonly bits as > + * long as their value is hardwired to 0. > + */ > + pci_set_word(dev->w1cmask + PCI_STATUS, > + PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | > + PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | > + PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY); > +} > + > +static void pci_init_mask_bridge(PCIDevice *d) > +{ > + /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and > + PCI_SEC_LETENCY_TIMER */ > + memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4); > + > + /* base and limit */ > + d->wmask[PCI_IO_BASE] = PCI_IO_RANGE_MASK & 0xff; > + d->wmask[PCI_IO_LIMIT] = PCI_IO_RANGE_MASK & 0xff; > + pci_set_word(d->wmask + PCI_MEMORY_BASE, > + PCI_MEMORY_RANGE_MASK & 0xffff); > + pci_set_word(d->wmask + PCI_MEMORY_LIMIT, > + PCI_MEMORY_RANGE_MASK & 0xffff); > + pci_set_word(d->wmask + PCI_PREF_MEMORY_BASE, > + PCI_PREF_RANGE_MASK & 0xffff); > + pci_set_word(d->wmask + PCI_PREF_MEMORY_LIMIT, > + PCI_PREF_RANGE_MASK & 0xffff); > + > + /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */ > + memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8); > + > + /* Supported memory and i/o types */ > + d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_16; > + d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_16; > + pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE, > + PCI_PREF_RANGE_TYPE_64); > + pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT, > + PCI_PREF_RANGE_TYPE_64); > + > +/* TODO: add this define to pci_regs.h in linux and then in qemu. */ > +#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ > +#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */ > +#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */ > +#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ > +#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ > + pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, > + PCI_BRIDGE_CTL_PARITY | > + PCI_BRIDGE_CTL_SERR | > + PCI_BRIDGE_CTL_ISA | > + PCI_BRIDGE_CTL_VGA | > + PCI_BRIDGE_CTL_VGA_16BIT | > + PCI_BRIDGE_CTL_MASTER_ABORT | > + PCI_BRIDGE_CTL_BUS_RESET | > + PCI_BRIDGE_CTL_FAST_BACK | > + PCI_BRIDGE_CTL_DISCARD | > + PCI_BRIDGE_CTL_SEC_DISCARD | > + PCI_BRIDGE_CTL_DISCARD_SERR); > + /* Below does not do anything as we never set this bit, put here for > + * completeness. */ > + pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL, > + PCI_BRIDGE_CTL_DISCARD_STATUS); > + d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK; > + d->cmask[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_MASK; > + pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE, > + PCI_PREF_RANGE_TYPE_MASK); > + pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_LIMIT, > + PCI_PREF_RANGE_TYPE_MASK); > +} > + > +static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev) > +{ > + uint8_t slot = PCI_SLOT(dev->devfn); > + uint8_t func; > + > + if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { > + dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; > + } > + > + /* > + * multifunction bit is interpreted in two ways as follows. > + * - all functions must set the bit to 1. > + * Example: Intel X53 > + * - function 0 must set the bit, but the rest function (> 0) > + * is allowed to leave the bit to 0. > + * Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10, > + * > + * So OS (at least Linux) checks the bit of only function 0, > + * and doesn't see the bit of function > 0. > + * > + * The below check allows both interpretation. > + */ > + if (PCI_FUNC(dev->devfn)) { > + PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)]; > + if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) { > + /* function 0 should set multifunction bit */ > + error_report("PCI: single function device can't be populated " > + "in function %x.%x", slot, PCI_FUNC(dev->devfn)); > + return -1; > + } > + return 0; > + } > + > + if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { > + return 0; > + } > + /* function 0 indicates single function, so function > 0 must be NULL */ > + for (func = 1; func < PCI_FUNC_MAX; ++func) { > + if (bus->devices[PCI_DEVFN(slot, func)]) { > + error_report("PCI: %x.0 indicates single function, " > + "but %x.%x is already populated.", > + slot, slot, func); > + return -1; > + } > + } > + return 0; > +} > + > +static void pci_config_alloc(PCIDevice *pci_dev) > +{ > + int config_size = pci_config_size(pci_dev); > + > + pci_dev->config = g_malloc0(config_size); > + pci_dev->cmask = g_malloc0(config_size); > + pci_dev->wmask = g_malloc0(config_size); > + pci_dev->w1cmask = g_malloc0(config_size); > + pci_dev->used = g_malloc0(config_size); > +} > + > +static void pci_config_free(PCIDevice *pci_dev) > +{ > + g_free(pci_dev->config); > + g_free(pci_dev->cmask); > + g_free(pci_dev->wmask); > + g_free(pci_dev->w1cmask); > + g_free(pci_dev->used); > +} > + > +/* -1 for devfn means auto assign */ > +static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, > + const char *name, int devfn) > +{ > + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > + PCIConfigReadFunc *config_read = pc->config_read; > + PCIConfigWriteFunc *config_write = pc->config_write; > + > + if (devfn < 0) { > + for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices); > + devfn += PCI_FUNC_MAX) { > + if (!bus->devices[devfn]) > + goto found; > + } > + error_report("PCI: no slot/function available for %s, all in use", name); > + return NULL; > + found: ; > + } else if (bus->devices[devfn]) { > + error_report("PCI: slot %d function %d not available for %s, in use by %s", > + PCI_SLOT(devfn), PCI_FUNC(devfn), name, bus->devices[devfn]->name); > + return NULL; > + } > + pci_dev->bus = bus; > + if (bus->dma_context_fn) { > + pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, devfn); > + } else { > + /* FIXME: Make dma_context_fn use MemoryRegions instead, so this path is > + * taken unconditionally */ > + /* FIXME: inherit memory region from bus creator */ > + memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master", > + get_system_memory(), 0, > + memory_region_size(get_system_memory())); > + memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); > + address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region); > + pci_dev->dma = g_new(DMAContext, 1); > + dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL); > + } > + pci_dev->devfn = devfn; > + pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); > + pci_dev->irq_state = 0; > + pci_config_alloc(pci_dev); > + > + pci_config_set_vendor_id(pci_dev->config, pc->vendor_id); > + pci_config_set_device_id(pci_dev->config, pc->device_id); > + pci_config_set_revision(pci_dev->config, pc->revision); > + pci_config_set_class(pci_dev->config, pc->class_id); > + > + if (!pc->is_bridge) { > + if (pc->subsystem_vendor_id || pc->subsystem_id) { > + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, > + pc->subsystem_vendor_id); > + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, > + pc->subsystem_id); > + } else { > + pci_set_default_subsystem_id(pci_dev); > + } > + } else { > + /* subsystem_vendor_id/subsystem_id are only for header type 0 */ > + assert(!pc->subsystem_vendor_id); > + assert(!pc->subsystem_id); > + } > + pci_init_cmask(pci_dev); > + pci_init_wmask(pci_dev); > + pci_init_w1cmask(pci_dev); > + if (pc->is_bridge) { > + pci_init_mask_bridge(pci_dev); > + } > + if (pci_init_multifunction(bus, pci_dev)) { > + pci_config_free(pci_dev); > + return NULL; > + } > + > + if (!config_read) > + config_read = pci_default_read_config; > + if (!config_write) > + config_write = pci_default_write_config; > + pci_dev->config_read = config_read; > + pci_dev->config_write = config_write; > + bus->devices[devfn] = pci_dev; > + pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS); > + pci_dev->version_id = 2; /* Current pci device vmstate version */ > + return pci_dev; > +} > + > +static void do_pci_unregister_device(PCIDevice *pci_dev) > +{ > + qemu_free_irqs(pci_dev->irq); > + pci_dev->bus->devices[pci_dev->devfn] = NULL; > + pci_config_free(pci_dev); > + > + if (!pci_dev->bus->dma_context_fn) { > + address_space_destroy(&pci_dev->bus_master_as); > + memory_region_destroy(&pci_dev->bus_master_enable_region); > + g_free(pci_dev->dma); > + pci_dev->dma = NULL; > + } > +} > + > +static void pci_unregister_io_regions(PCIDevice *pci_dev) > +{ > + PCIIORegion *r; > + int i; > + > + for(i = 0; i < PCI_NUM_REGIONS; i++) { > + r = &pci_dev->io_regions[i]; > + if (!r->size || r->addr == PCI_BAR_UNMAPPED) > + continue; > + memory_region_del_subregion(r->address_space, r->memory); > + } > +} > + > +static int pci_unregister_device(DeviceState *dev) > +{ > + PCIDevice *pci_dev = PCI_DEVICE(dev); > + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > + > + pci_unregister_io_regions(pci_dev); > + pci_del_option_rom(pci_dev); > + > + if (pc->exit) { > + pc->exit(pci_dev); > + } > + > + do_pci_unregister_device(pci_dev); > + return 0; > +} > + > +void pci_register_bar(PCIDevice *pci_dev, int region_num, > + uint8_t type, MemoryRegion *memory) > +{ > + PCIIORegion *r; > + uint32_t addr; > + uint64_t wmask; > + pcibus_t size = memory_region_size(memory); > + > + assert(region_num >= 0); > + assert(region_num < PCI_NUM_REGIONS); > + if (size & (size-1)) { > + fprintf(stderr, "ERROR: PCI region size must be pow2 " > + "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size); > + exit(1); > + } > + > + r = &pci_dev->io_regions[region_num]; > + r->addr = PCI_BAR_UNMAPPED; > + r->size = size; > + r->type = type; > + r->memory = NULL; > + > + wmask = ~(size - 1); > + addr = pci_bar(pci_dev, region_num); > + if (region_num == PCI_ROM_SLOT) { > + /* ROM enable bit is writable */ > + wmask |= PCI_ROM_ADDRESS_ENABLE; > + } > + pci_set_long(pci_dev->config + addr, type); > + if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) && > + r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > + pci_set_quad(pci_dev->wmask + addr, wmask); > + pci_set_quad(pci_dev->cmask + addr, ~0ULL); > + } else { > + pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff); > + pci_set_long(pci_dev->cmask + addr, 0xffffffff); > + } > + pci_dev->io_regions[region_num].memory = memory; > + pci_dev->io_regions[region_num].address_space > + = type & PCI_BASE_ADDRESS_SPACE_IO > + ? pci_dev->bus->address_space_io > + : pci_dev->bus->address_space_mem; > +} > + > +pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num) > +{ > + return pci_dev->io_regions[region_num].addr; > +} > + > +static pcibus_t pci_bar_address(PCIDevice *d, > + int reg, uint8_t type, pcibus_t size) > +{ > + pcibus_t new_addr, last_addr; > + int bar = pci_bar(d, reg); > + uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); > + > + if (type & PCI_BASE_ADDRESS_SPACE_IO) { > + if (!(cmd & PCI_COMMAND_IO)) { > + return PCI_BAR_UNMAPPED; > + } > + new_addr = pci_get_long(d->config + bar) & ~(size - 1); > + last_addr = new_addr + size - 1; > + /* NOTE: we have only 64K ioports on PC */ > + if (last_addr <= new_addr || new_addr == 0 || last_addr > UINT16_MAX) { > + return PCI_BAR_UNMAPPED; > + } > + return new_addr; > + } > + > + if (!(cmd & PCI_COMMAND_MEMORY)) { > + return PCI_BAR_UNMAPPED; > + } > + if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > + new_addr = pci_get_quad(d->config + bar); > + } else { > + new_addr = pci_get_long(d->config + bar); > + } > + /* the ROM slot has a specific enable bit */ > + if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) { > + return PCI_BAR_UNMAPPED; > + } > + new_addr &= ~(size - 1); > + last_addr = new_addr + size - 1; > + /* NOTE: we do not support wrapping */ > + /* XXX: as we cannot support really dynamic > + mappings, we handle specific values as invalid > + mappings. */ > + if (last_addr <= new_addr || new_addr == 0 || > + last_addr == PCI_BAR_UNMAPPED) { > + return PCI_BAR_UNMAPPED; > + } > + > + /* Now pcibus_t is 64bit. > + * Check if 32 bit BAR wraps around explicitly. > + * Without this, PC ide doesn't work well. > + * TODO: remove this work around. > + */ > + if (!(type & PCI_BASE_ADDRESS_MEM_TYPE_64) && last_addr >= UINT32_MAX) { > + return PCI_BAR_UNMAPPED; > + } > + > + /* > + * OS is allowed to set BAR beyond its addressable > + * bits. For example, 32 bit OS can set 64bit bar > + * to >4G. Check it. TODO: we might need to support > + * it in the future for e.g. PAE. > + */ > + if (last_addr >= HWADDR_MAX) { > + return PCI_BAR_UNMAPPED; > + } > + > + return new_addr; > +} > + > +static void pci_update_mappings(PCIDevice *d) > +{ > + PCIIORegion *r; > + int i; > + pcibus_t new_addr; > + > + for(i = 0; i < PCI_NUM_REGIONS; i++) { > + r = &d->io_regions[i]; > + > + /* this region isn't registered */ > + if (!r->size) > + continue; > + > + new_addr = pci_bar_address(d, i, r->type, r->size); > + > + /* This bar isn't changed */ > + if (new_addr == r->addr) > + continue; > + > + /* now do the real mapping */ > + if (r->addr != PCI_BAR_UNMAPPED) { > + memory_region_del_subregion(r->address_space, r->memory); > + } > + r->addr = new_addr; > + if (r->addr != PCI_BAR_UNMAPPED) { > + memory_region_add_subregion_overlap(r->address_space, > + r->addr, r->memory, 1); > + } > + } > +} > + > +static inline int pci_irq_disabled(PCIDevice *d) > +{ > + return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE; > +} > + > +/* Called after interrupt disabled field update in config space, > + * assert/deassert interrupts if necessary. > + * Gets original interrupt disable bit value (before update). */ > +static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled) > +{ > + int i, disabled = pci_irq_disabled(d); > + if (disabled == was_irq_disabled) > + return; > + for (i = 0; i < PCI_NUM_PINS; ++i) { > + int state = pci_irq_state(d, i); > + pci_change_irq_level(d, i, disabled ? -state : state); > + } > +} > + > +uint32_t pci_default_read_config(PCIDevice *d, > + uint32_t address, int len) > +{ > + uint32_t val = 0; > + > + memcpy(&val, d->config + address, len); > + return le32_to_cpu(val); > +} > + > +void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) > +{ > + int i, was_irq_disabled = pci_irq_disabled(d); > + > + for (i = 0; i < l; val >>= 8, ++i) { > + uint8_t wmask = d->wmask[addr + i]; > + uint8_t w1cmask = d->w1cmask[addr + i]; > + assert(!(wmask & w1cmask)); > + d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask); > + d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ > + } > + if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) || > + ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) || > + ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) || > + range_covers_byte(addr, l, PCI_COMMAND)) > + pci_update_mappings(d); > + > + if (range_covers_byte(addr, l, PCI_COMMAND)) { > + pci_update_irq_disabled(d, was_irq_disabled); > + memory_region_set_enabled(&d->bus_master_enable_region, > + pci_get_word(d->config + PCI_COMMAND) > + & PCI_COMMAND_MASTER); > + } > + > + msi_write_config(d, addr, val, l); > + msix_write_config(d, addr, val, l); > +} > + > +/***********************************************************/ > +/* generic PCI irq support */ > + > +/* 0 <= irq_num <= 3. level must be 0 or 1 */ > +static void pci_set_irq(void *opaque, int irq_num, int level) > +{ > + PCIDevice *pci_dev = opaque; > + int change; > + > + change = level - pci_irq_state(pci_dev, irq_num); > + if (!change) > + return; > + > + pci_set_irq_state(pci_dev, irq_num, level); > + pci_update_irq_status(pci_dev); > + if (pci_irq_disabled(pci_dev)) > + return; > + pci_change_irq_level(pci_dev, irq_num, change); > +} > + > +/* Special hooks used by device assignment */ > +void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq) > +{ > + assert(!bus->parent_dev); > + bus->route_intx_to_irq = route_intx_to_irq; > +} > + > +PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) > +{ > + PCIBus *bus; > + > + do { > + bus = dev->bus; > + pin = bus->map_irq(dev, pin); > + dev = bus->parent_dev; > + } while (dev); > + > + if (!bus->route_intx_to_irq) { > + error_report("PCI: Bug - unimplemented PCI INTx routing (%s)\n", > + object_get_typename(OBJECT(bus->qbus.parent))); > + return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 }; > + } > + > + return bus->route_intx_to_irq(bus->irq_opaque, pin); > +} > + > +bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new) > +{ > + return old->mode != new->mode || old->irq != new->irq; > +} > + > +void pci_bus_fire_intx_routing_notifier(PCIBus *bus) > +{ > + PCIDevice *dev; > + PCIBus *sec; > + int i; > + > + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { > + dev = bus->devices[i]; > + if (dev && dev->intx_routing_notifier) { > + dev->intx_routing_notifier(dev); > + } > + QLIST_FOREACH(sec, &bus->child, sibling) { > + pci_bus_fire_intx_routing_notifier(sec); > + } > + } > +} > + > +void pci_device_set_intx_routing_notifier(PCIDevice *dev, > + PCIINTxRoutingNotifier notifier) > +{ > + dev->intx_routing_notifier = notifier; > +} > + > +/* > + * PCI-to-PCI bridge specification > + * 9.1: Interrupt routing. Table 9-1 > + * > + * the PCI Express Base Specification, Revision 2.1 > + * 2.2.8.1: INTx interrutp signaling - Rules > + * the Implementation Note > + * Table 2-20 > + */ > +/* > + * 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD > + * 0-origin unlike PCI interrupt pin register. > + */ > +int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) > +{ > + return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; > +} > + > +/***********************************************************/ > +/* monitor info on PCI */ > + > +typedef struct { > + uint16_t class; > + const char *desc; > + const char *fw_name; > + uint16_t fw_ign_bits; > +} pci_class_desc; > + > +static const pci_class_desc pci_class_descriptions[] = > +{ > + { 0x0001, "VGA controller", "display"}, > + { 0x0100, "SCSI controller", "scsi"}, > + { 0x0101, "IDE controller", "ide"}, > + { 0x0102, "Floppy controller", "fdc"}, > + { 0x0103, "IPI controller", "ipi"}, > + { 0x0104, "RAID controller", "raid"}, > + { 0x0106, "SATA controller"}, > + { 0x0107, "SAS controller"}, > + { 0x0180, "Storage controller"}, > + { 0x0200, "Ethernet controller", "ethernet"}, > + { 0x0201, "Token Ring controller", "token-ring"}, > + { 0x0202, "FDDI controller", "fddi"}, > + { 0x0203, "ATM controller", "atm"}, > + { 0x0280, "Network controller"}, > + { 0x0300, "VGA controller", "display", 0x00ff}, > + { 0x0301, "XGA controller"}, > + { 0x0302, "3D controller"}, > + { 0x0380, "Display controller"}, > + { 0x0400, "Video controller", "video"}, > + { 0x0401, "Audio controller", "sound"}, > + { 0x0402, "Phone"}, > + { 0x0403, "Audio controller", "sound"}, > + { 0x0480, "Multimedia controller"}, > + { 0x0500, "RAM controller", "memory"}, > + { 0x0501, "Flash controller", "flash"}, > + { 0x0580, "Memory controller"}, > + { 0x0600, "Host bridge", "host"}, > + { 0x0601, "ISA bridge", "isa"}, > + { 0x0602, "EISA bridge", "eisa"}, > + { 0x0603, "MC bridge", "mca"}, > + { 0x0604, "PCI bridge", "pci"}, > + { 0x0605, "PCMCIA bridge", "pcmcia"}, > + { 0x0606, "NUBUS bridge", "nubus"}, > + { 0x0607, "CARDBUS bridge", "cardbus"}, > + { 0x0608, "RACEWAY bridge"}, > + { 0x0680, "Bridge"}, > + { 0x0700, "Serial port", "serial"}, > + { 0x0701, "Parallel port", "parallel"}, > + { 0x0800, "Interrupt controller", "interrupt-controller"}, > + { 0x0801, "DMA controller", "dma-controller"}, > + { 0x0802, "Timer", "timer"}, > + { 0x0803, "RTC", "rtc"}, > + { 0x0900, "Keyboard", "keyboard"}, > + { 0x0901, "Pen", "pen"}, > + { 0x0902, "Mouse", "mouse"}, > + { 0x0A00, "Dock station", "dock", 0x00ff}, > + { 0x0B00, "i386 cpu", "cpu", 0x00ff}, > + { 0x0c00, "Fireware contorller", "fireware"}, > + { 0x0c01, "Access bus controller", "access-bus"}, > + { 0x0c02, "SSA controller", "ssa"}, > + { 0x0c03, "USB controller", "usb"}, > + { 0x0c04, "Fibre channel controller", "fibre-channel"}, > + { 0x0c05, "SMBus"}, > + { 0, NULL} > +}; > + > +static void pci_for_each_device_under_bus(PCIBus *bus, > + void (*fn)(PCIBus *b, PCIDevice *d, > + void *opaque), > + void *opaque) > +{ > + PCIDevice *d; > + int devfn; > + > + for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > + d = bus->devices[devfn]; > + if (d) { > + fn(bus, d, opaque); > + } > + } > +} > + > +void pci_for_each_device(PCIBus *bus, int bus_num, > + void (*fn)(PCIBus *b, PCIDevice *d, void *opaque), > + void *opaque) > +{ > + bus = pci_find_bus_nr(bus, bus_num); > + > + if (bus) { > + pci_for_each_device_under_bus(bus, fn, opaque); > + } > +} > + > +static const pci_class_desc *get_class_desc(int class) > +{ > + const pci_class_desc *desc; > + > + desc = pci_class_descriptions; > + while (desc->desc && class != desc->class) { > + desc++; > + } > + > + return desc; > +} > + > +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num); > + > +static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev) > +{ > + PciMemoryRegionList *head = NULL, *cur_item = NULL; > + int i; > + > + for (i = 0; i < PCI_NUM_REGIONS; i++) { > + const PCIIORegion *r = &dev->io_regions[i]; > + PciMemoryRegionList *region; > + > + if (!r->size) { > + continue; > + } > + > + region = g_malloc0(sizeof(*region)); > + region->value = g_malloc0(sizeof(*region->value)); > + > + if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { > + region->value->type = g_strdup("io"); > + } else { > + region->value->type = g_strdup("memory"); > + region->value->has_prefetch = true; > + region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH); > + region->value->has_mem_type_64 = true; > + region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64); > + } > + > + region->value->bar = i; > + region->value->address = r->addr; > + region->value->size = r->size; > + > + /* XXX: waiting for the qapi to support GSList */ > + if (!cur_item) { > + head = cur_item = region; > + } else { > + cur_item->next = region; > + cur_item = region; > + } > + } > + > + return head; > +} > + > +static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus, > + int bus_num) > +{ > + PciBridgeInfo *info; > + > + info = g_malloc0(sizeof(*info)); > + > + info->bus.number = dev->config[PCI_PRIMARY_BUS]; > + info->bus.secondary = dev->config[PCI_SECONDARY_BUS]; > + info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS]; > + > + info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range)); > + info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); > + info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO); > + > + info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range)); > + info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > + info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > + > + info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range)); > + info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > + info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > + > + if (dev->config[PCI_SECONDARY_BUS] != 0) { > + PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]); > + if (child_bus) { > + info->has_devices = true; > + info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]); > + } > + } > + > + return info; > +} > + > +static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, > + int bus_num) > +{ > + const pci_class_desc *desc; > + PciDeviceInfo *info; > + uint8_t type; > + int class; > + > + info = g_malloc0(sizeof(*info)); > + info->bus = bus_num; > + info->slot = PCI_SLOT(dev->devfn); > + info->function = PCI_FUNC(dev->devfn); > + > + class = pci_get_word(dev->config + PCI_CLASS_DEVICE); > + info->class_info.class = class; > + desc = get_class_desc(class); > + if (desc->desc) { > + info->class_info.has_desc = true; > + info->class_info.desc = g_strdup(desc->desc); > + } > + > + info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID); > + info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID); > + info->regions = qmp_query_pci_regions(dev); > + info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : ""); > + > + if (dev->config[PCI_INTERRUPT_PIN] != 0) { > + info->has_irq = true; > + info->irq = dev->config[PCI_INTERRUPT_LINE]; > + } > + > + type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; > + if (type == PCI_HEADER_TYPE_BRIDGE) { > + info->has_pci_bridge = true; > + info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num); > + } > + > + return info; > +} > + > +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num) > +{ > + PciDeviceInfoList *info, *head = NULL, *cur_item = NULL; > + PCIDevice *dev; > + int devfn; > + > + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > + dev = bus->devices[devfn]; > + if (dev) { > + info = g_malloc0(sizeof(*info)); > + info->value = qmp_query_pci_device(dev, bus, bus_num); > + > + /* XXX: waiting for the qapi to support GSList */ > + if (!cur_item) { > + head = cur_item = info; > + } else { > + cur_item->next = info; > + cur_item = info; > + } > + } > + } > + > + return head; > +} > + > +static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) > +{ > + PciInfo *info = NULL; > + > + bus = pci_find_bus_nr(bus, bus_num); > + if (bus) { > + info = g_malloc0(sizeof(*info)); > + info->bus = bus_num; > + info->devices = qmp_query_pci_devices(bus, bus_num); > + } > + > + return info; > +} > + > +PciInfoList *qmp_query_pci(Error **errp) > +{ > + PciInfoList *info, *head = NULL, *cur_item = NULL; > + struct PCIHostBus *host; > + > + QLIST_FOREACH(host, &host_buses, next) { > + info = g_malloc0(sizeof(*info)); > + info->value = qmp_query_pci_bus(host->bus, 0); > + > + /* XXX: waiting for the qapi to support GSList */ > + if (!cur_item) { > + head = cur_item = info; > + } else { > + cur_item->next = info; > + cur_item = info; > + } > + } > + > + return head; > +} > + > +static const char * const pci_nic_models[] = { > + "ne2k_pci", > + "i82551", > + "i82557b", > + "i82559er", > + "rtl8139", > + "e1000", > + "pcnet", > + "virtio", > + NULL > +}; > + > +static const char * const pci_nic_names[] = { > + "ne2k_pci", > + "i82551", > + "i82557b", > + "i82559er", > + "rtl8139", > + "e1000", > + "pcnet", > + "virtio-net-pci", > + NULL > +}; > + > +/* Initialize a PCI NIC. */ > +/* FIXME callers should check for failure, but don't */ > +PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, > + const char *default_devaddr) > +{ > + const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr; > + PCIBus *bus; > + int devfn; > + PCIDevice *pci_dev; > + DeviceState *dev; > + int i; > + > + i = qemu_find_nic_model(nd, pci_nic_models, default_model); > + if (i < 0) > + return NULL; > + > + bus = pci_get_bus_devfn(&devfn, devaddr); > + if (!bus) { > + error_report("Invalid PCI device address %s for device %s", > + devaddr, pci_nic_names[i]); > + return NULL; > + } > + > + pci_dev = pci_create(bus, devfn, pci_nic_names[i]); > + dev = &pci_dev->qdev; > + qdev_set_nic_properties(dev, nd); > + if (qdev_init(dev) < 0) > + return NULL; > + return pci_dev; > +} > + > +PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, > + const char *default_devaddr) > +{ > + PCIDevice *res; > + > + if (qemu_show_nic_models(nd->model, pci_nic_models)) > + exit(0); > + > + res = pci_nic_init(nd, default_model, default_devaddr); > + if (!res) > + exit(1); > + return res; > +} > + > +PCIDevice *pci_vga_init(PCIBus *bus) > +{ > + switch (vga_interface_type) { > + case VGA_CIRRUS: > + return pci_create_simple(bus, -1, "cirrus-vga"); > + case VGA_QXL: > + return pci_create_simple(bus, -1, "qxl-vga"); > + case VGA_STD: > + return pci_create_simple(bus, -1, "VGA"); > + case VGA_VMWARE: > + return pci_create_simple(bus, -1, "vmware-svga"); > + case VGA_NONE: > + default: /* Other non-PCI types. Checking for unsupported types is already > + done in vl.c. */ > + return NULL; > + } > +} > + > +/* Whether a given bus number is in range of the secondary > + * bus of the given bridge device. */ > +static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) > +{ > + return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) & > + PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ && > + dev->config[PCI_SECONDARY_BUS] < bus_num && > + bus_num <= dev->config[PCI_SUBORDINATE_BUS]; > +} > + > +static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) > +{ > + PCIBus *sec; > + > + if (!bus) { > + return NULL; > + } > + > + if (pci_bus_num(bus) == bus_num) { > + return bus; > + } > + > + /* Consider all bus numbers in range for the host pci bridge. */ > + if (bus->parent_dev && > + !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) { > + return NULL; > + } > + > + /* try child bus */ > + for (; bus; bus = sec) { > + QLIST_FOREACH(sec, &bus->child, sibling) { > + assert(sec->parent_dev); > + if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) { > + return sec; > + } > + if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) { > + break; > + } > + } > + } > + > + return NULL; > +} > + > +PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn) > +{ > + bus = pci_find_bus_nr(bus, bus_num); > + > + if (!bus) > + return NULL; > + > + return bus->devices[devfn]; > +} > + > +static int pci_qdev_init(DeviceState *qdev) > +{ > + PCIDevice *pci_dev = (PCIDevice *)qdev; > + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > + PCIBus *bus; > + int rc; > + bool is_default_rom; > + > + /* initialize cap_present for pci_is_express() and pci_config_size() */ > + if (pc->is_express) { > + pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; > + } > + > + bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); > + pci_dev = do_pci_register_device(pci_dev, bus, > + object_get_typename(OBJECT(qdev)), > + pci_dev->devfn); > + if (pci_dev == NULL) > + return -1; > + if (qdev->hotplugged && pc->no_hotplug) { > + qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev))); > + do_pci_unregister_device(pci_dev); > + return -1; > + } > + if (pc->init) { > + rc = pc->init(pci_dev); > + if (rc != 0) { > + do_pci_unregister_device(pci_dev); > + return rc; > + } > + } > + > + /* rom loading */ > + is_default_rom = false; > + if (pci_dev->romfile == NULL && pc->romfile != NULL) { > + pci_dev->romfile = g_strdup(pc->romfile); > + is_default_rom = true; > + } > + pci_add_option_rom(pci_dev, is_default_rom); > + > + if (bus->hotplug) { > + /* Let buses differentiate between hotplug and when device is > + * enabled during qemu machine creation. */ > + rc = bus->hotplug(bus->hotplug_qdev, pci_dev, > + qdev->hotplugged ? PCI_HOTPLUG_ENABLED: > + PCI_COLDPLUG_ENABLED); > + if (rc != 0) { > + int r = pci_unregister_device(&pci_dev->qdev); > + assert(!r); > + return rc; > + } > + } > + return 0; > +} > + > +static int pci_unplug_device(DeviceState *qdev) > +{ > + PCIDevice *dev = PCI_DEVICE(qdev); > + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); > + > + if (pc->no_hotplug) { > + qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev))); > + return -1; > + } > + return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, > + PCI_HOTPLUG_DISABLED); > +} > + > +PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, > + const char *name) > +{ > + DeviceState *dev; > + > + dev = qdev_create(&bus->qbus, name); > + qdev_prop_set_int32(dev, "addr", devfn); > + qdev_prop_set_bit(dev, "multifunction", multifunction); > + return PCI_DEVICE(dev); > +} > + > +PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, > + bool multifunction, > + const char *name) > +{ > + PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction, name); > + qdev_init_nofail(&dev->qdev); > + return dev; > +} > + > +PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name) > +{ > + return pci_create_multifunction(bus, devfn, false, name); > +} > + > +PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) > +{ > + return pci_create_simple_multifunction(bus, devfn, false, name); > +} > + > +static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size) > +{ > + int offset = PCI_CONFIG_HEADER_SIZE; > + int i; > + for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) { > + if (pdev->used[i]) > + offset = i + 1; > + else if (i - offset + 1 == size) > + return offset; > + } > + return 0; > +} > + > +static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id, > + uint8_t *prev_p) > +{ > + uint8_t next, prev; > + > + if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST)) > + return 0; > + > + for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); > + prev = next + PCI_CAP_LIST_NEXT) > + if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id) > + break; > + > + if (prev_p) > + *prev_p = prev; > + return next; > +} > + > +static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset) > +{ > + uint8_t next, prev, found = 0; > + > + if (!(pdev->used[offset])) { > + return 0; > + } > + > + assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST); > + > + for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); > + prev = next + PCI_CAP_LIST_NEXT) { > + if (next <= offset && next > found) { > + found = next; > + } > + } > + return found; > +} > + > +/* Patch the PCI vendor and device ids in a PCI rom image if necessary. > + This is needed for an option rom which is used for more than one device. */ > +static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size) > +{ > + uint16_t vendor_id; > + uint16_t device_id; > + uint16_t rom_vendor_id; > + uint16_t rom_device_id; > + uint16_t rom_magic; > + uint16_t pcir_offset; > + uint8_t checksum; > + > + /* Words in rom data are little endian (like in PCI configuration), > + so they can be read / written with pci_get_word / pci_set_word. */ > + > + /* Only a valid rom will be patched. */ > + rom_magic = pci_get_word(ptr); > + if (rom_magic != 0xaa55) { > + PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic); > + return; > + } > + pcir_offset = pci_get_word(ptr + 0x18); > + if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) { > + PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset); > + return; > + } > + > + vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); > + device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); > + rom_vendor_id = pci_get_word(ptr + pcir_offset + 4); > + rom_device_id = pci_get_word(ptr + pcir_offset + 6); > + > + PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile, > + vendor_id, device_id, rom_vendor_id, rom_device_id); > + > + checksum = ptr[6]; > + > + if (vendor_id != rom_vendor_id) { > + /* Patch vendor id and checksum (at offset 6 for etherboot roms). */ > + checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8); > + checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8); > + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > + ptr[6] = checksum; > + pci_set_word(ptr + pcir_offset + 4, vendor_id); > + } > + > + if (device_id != rom_device_id) { > + /* Patch device id and checksum (at offset 6 for etherboot roms). */ > + checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8); > + checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8); > + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > + ptr[6] = checksum; > + pci_set_word(ptr + pcir_offset + 6, device_id); > + } > +} > + > +/* Add an option rom for the device */ > +static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) > +{ > + int size; > + char *path; > + void *ptr; > + char name[32]; > + const VMStateDescription *vmsd; > + > + if (!pdev->romfile) > + return 0; > + if (strlen(pdev->romfile) == 0) > + return 0; > + > + if (!pdev->rom_bar) { > + /* > + * Load rom via fw_cfg instead of creating a rom bar, > + * for 0.11 compatibility. > + */ > + int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE); > + if (class == 0x0300) { > + rom_add_vga(pdev->romfile); > + } else { > + rom_add_option(pdev->romfile, -1); > + } > + return 0; > + } > + > + path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); > + if (path == NULL) { > + path = g_strdup(pdev->romfile); > + } > + > + size = get_image_size(path); > + if (size < 0) { > + error_report("%s: failed to find romfile \"%s\"", > + __FUNCTION__, pdev->romfile); > + g_free(path); > + return -1; > + } > + if (size & (size - 1)) { > + size = 1 << qemu_fls(size); > + } > + > + vmsd = qdev_get_vmsd(DEVICE(pdev)); > + > + if (vmsd) { > + snprintf(name, sizeof(name), "%s.rom", vmsd->name); > + } else { > + snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev))); > + } > + pdev->has_rom = true; > + memory_region_init_ram(&pdev->rom, name, size); > + vmstate_register_ram(&pdev->rom, &pdev->qdev); > + ptr = memory_region_get_ram_ptr(&pdev->rom); > + load_image(path, ptr); > + g_free(path); > + > + if (is_default_rom) { > + /* Only the default rom images will be patched (if needed). */ > + pci_patch_ids(pdev, ptr, size); > + } > + > + qemu_put_ram_ptr(ptr); > + > + pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom); > + > + return 0; > +} > + > +static void pci_del_option_rom(PCIDevice *pdev) > +{ > + if (!pdev->has_rom) > + return; > + > + vmstate_unregister_ram(&pdev->rom, &pdev->qdev); > + memory_region_destroy(&pdev->rom); > + pdev->has_rom = false; > +} > + > +/* > + * if !offset > + * Reserve space and add capability to the linked list in pci config space > + * > + * if offset = 0, > + * Find and reserve space and add capability to the linked list > + * in pci config space */ > +int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, > + uint8_t offset, uint8_t size) > +{ > + uint8_t *config; > + int i, overlapping_cap; > + > + if (!offset) { > + offset = pci_find_space(pdev, size); > + if (!offset) { > + return -ENOSPC; > + } > + } else { > + /* Verify that capabilities don't overlap. Note: device assignment > + * depends on this check to verify that the device is not broken. > + * Should never trigger for emulated devices, but it's helpful > + * for debugging these. */ > + for (i = offset; i < offset + size; i++) { > + overlapping_cap = pci_find_capability_at_offset(pdev, i); > + if (overlapping_cap) { > + fprintf(stderr, "ERROR: %04x:%02x:%02x.%x " > + "Attempt to add PCI capability %x at offset " > + "%x overlaps existing capability %x at offset %x\n", > + pci_find_domain(pdev->bus), pci_bus_num(pdev->bus), > + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), > + cap_id, offset, overlapping_cap, i); > + return -EINVAL; > + } > + } > + } > + > + config = pdev->config + offset; > + config[PCI_CAP_LIST_ID] = cap_id; > + config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST]; > + pdev->config[PCI_CAPABILITY_LIST] = offset; > + pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST; > + memset(pdev->used + offset, 0xFF, QEMU_ALIGN_UP(size, 4)); > + /* Make capability read-only by default */ > + memset(pdev->wmask + offset, 0, size); > + /* Check capability by default */ > + memset(pdev->cmask + offset, 0xFF, size); > + return offset; > +} > + > +/* Unlink capability from the pci config space. */ > +void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) > +{ > + uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev); > + if (!offset) > + return; > + pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT]; > + /* Make capability writable again */ > + memset(pdev->wmask + offset, 0xff, size); > + memset(pdev->w1cmask + offset, 0, size); > + /* Clear cmask as device-specific registers can't be checked */ > + memset(pdev->cmask + offset, 0, size); > + memset(pdev->used + offset, 0, QEMU_ALIGN_UP(size, 4)); > + > + if (!pdev->config[PCI_CAPABILITY_LIST]) > + pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST; > +} > + > +uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id) > +{ > + return pci_find_capability_list(pdev, cap_id, NULL); > +} > + > +static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) > +{ > + PCIDevice *d = (PCIDevice *)dev; > + const pci_class_desc *desc; > + char ctxt[64]; > + PCIIORegion *r; > + int i, class; > + > + class = pci_get_word(d->config + PCI_CLASS_DEVICE); > + desc = pci_class_descriptions; > + while (desc->desc && class != desc->class) > + desc++; > + if (desc->desc) { > + snprintf(ctxt, sizeof(ctxt), "%s", desc->desc); > + } else { > + snprintf(ctxt, sizeof(ctxt), "Class %04x", class); > + } > + > + monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " > + "pci id %04x:%04x (sub %04x:%04x)\n", > + indent, "", ctxt, pci_bus_num(d->bus), > + PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), > + pci_get_word(d->config + PCI_VENDOR_ID), > + pci_get_word(d->config + PCI_DEVICE_ID), > + pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID), > + pci_get_word(d->config + PCI_SUBSYSTEM_ID)); > + for (i = 0; i < PCI_NUM_REGIONS; i++) { > + r = &d->io_regions[i]; > + if (!r->size) > + continue; > + monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS > + " [0x%"FMT_PCIBUS"]\n", > + indent, "", > + i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem", > + r->addr, r->addr + r->size - 1); > + } > +} > + > +static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len) > +{ > + PCIDevice *d = (PCIDevice *)dev; > + const char *name = NULL; > + const pci_class_desc *desc = pci_class_descriptions; > + int class = pci_get_word(d->config + PCI_CLASS_DEVICE); > + > + while (desc->desc && > + (class & ~desc->fw_ign_bits) != > + (desc->class & ~desc->fw_ign_bits)) { > + desc++; > + } > + > + if (desc->desc) { > + name = desc->fw_name; > + } > + > + if (name) { > + pstrcpy(buf, len, name); > + } else { > + snprintf(buf, len, "pci%04x,%04x", > + pci_get_word(d->config + PCI_VENDOR_ID), > + pci_get_word(d->config + PCI_DEVICE_ID)); > + } > + > + return buf; > +} > + > +static char *pcibus_get_fw_dev_path(DeviceState *dev) > +{ > + PCIDevice *d = (PCIDevice *)dev; > + char path[50], name[33]; > + int off; > + > + off = snprintf(path, sizeof(path), "%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 = container_of(dev, PCIDevice, qdev); > + PCIDevice *t; > + int slot_depth; > + /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function. > + * 00 is added here to make this format compatible with > + * domain:Bus:Slot.Func for systems without nested PCI bridges. > + * Slot.Function list specifies the slot and function numbers for all > + * devices on the path from root to the specific device. */ > + char domain[] = "DDDD:00"; > + char slot[] = ":SS.F"; > + int domain_len = sizeof domain - 1 /* For '\0' */; > + int slot_len = sizeof slot - 1 /* For '\0' */; > + int path_len; > + char *path, *p; > + int s; > + > + /* Calculate # of slots on path between device and root. */; > + slot_depth = 0; > + for (t = d; t; t = t->bus->parent_dev) { > + ++slot_depth; > + } > + > + path_len = domain_len + slot_len * slot_depth; > + > + /* Allocate memory, fill in the terminating null byte. */ > + path = g_malloc(path_len + 1 /* For '\0' */); > + path[path_len] = '\0'; > + > + /* First field is the domain. */ > + s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus)); > + assert(s == domain_len); > + memcpy(path, domain, domain_len); > + > + /* Fill in slot numbers. We walk up from device to root, so need to print > + * them in the reverse order, last to first. */ > + p = path + path_len; > + for (t = d; t; t = t->bus->parent_dev) { > + p -= slot_len; > + s = snprintf(slot, sizeof slot, ":%02x.%x", > + PCI_SLOT(t->devfn), PCI_FUNC(t->devfn)); > + assert(s == slot_len); > + memcpy(p, slot, slot_len); > + } > + > + return path; > +} > + > +static int pci_qdev_find_recursive(PCIBus *bus, > + const char *id, PCIDevice **pdev) > +{ > + DeviceState *qdev = qdev_find_recursive(&bus->qbus, id); > + if (!qdev) { > + return -ENODEV; > + } > + > + /* roughly check if given qdev is pci device */ > + if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) { > + *pdev = PCI_DEVICE(qdev); > + return 0; > + } > + return -EINVAL; > +} > + > +int pci_qdev_find_device(const char *id, PCIDevice **pdev) > +{ > + struct PCIHostBus *host; > + int rc = -ENODEV; > + > + QLIST_FOREACH(host, &host_buses, next) { > + int tmp = pci_qdev_find_recursive(host->bus, id, pdev); > + if (!tmp) { > + rc = 0; > + break; > + } > + if (tmp != -ENODEV) { > + rc = tmp; > + } > + } > + > + return rc; > +} > + > +MemoryRegion *pci_address_space(PCIDevice *dev) > +{ > + return dev->bus->address_space_mem; > +} > + > +MemoryRegion *pci_address_space_io(PCIDevice *dev) > +{ > + return dev->bus->address_space_io; > +} > + > +static void pci_device_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *k = DEVICE_CLASS(klass); > + k->init = pci_qdev_init; > + k->unplug = pci_unplug_device; > + k->exit = pci_unregister_device; > + k->bus_type = TYPE_PCI_BUS; > + k->props = pci_props; > +} > + > +void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque) > +{ > + bus->dma_context_fn = fn; > + bus->dma_context_opaque = opaque; > +} > + > +static TypeInfo pci_device_type_info = { > + .name = TYPE_PCI_DEVICE, > + .parent = TYPE_DEVICE, > + .instance_size = sizeof(PCIDevice), > + .abstract = true, > + .class_size = sizeof(PCIDeviceClass), > + .class_init = pci_device_class_init, > +}; > + > +static void pci_register_types(void) > +{ > + type_register_static(&pci_bus_info); > + type_register_static(&pci_device_type_info); > +} > + > +type_init(pci_register_types) > diff --git a/hw/pci/pci.h b/hw/pci/pci.h > new file mode 100644 > index 0000000..4da0c2a > --- /dev/null > +++ b/hw/pci/pci.h > @@ -0,0 +1,684 @@ > +#ifndef QEMU_PCI_H > +#define QEMU_PCI_H > + > +#include "qemu-common.h" > + > +#include "qdev.h" > +#include "memory.h" > +#include "dma.h" > + > +/* PCI includes legacy ISA access. */ > +#include "isa.h" > + > +#include "pcie.h" > + > +/* PCI bus */ > + > +#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) > +#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) > +#define PCI_FUNC(devfn) ((devfn) & 0x07) > +#define PCI_SLOT_MAX 32 > +#define PCI_FUNC_MAX 8 > + > +/* Class, Vendor and Device IDs from Linux's pci_ids.h */ > +#include "pci_ids.h" > + > +/* QEMU-specific Vendor and Device ID definitions */ > + > +/* IBM (0x1014) */ > +#define PCI_DEVICE_ID_IBM_440GX 0x027f > +#define PCI_DEVICE_ID_IBM_OPENPIC2 0xffff > + > +/* Hitachi (0x1054) */ > +#define PCI_VENDOR_ID_HITACHI 0x1054 > +#define PCI_DEVICE_ID_HITACHI_SH7751R 0x350e > + > +/* Apple (0x106b) */ > +#define PCI_DEVICE_ID_APPLE_343S1201 0x0010 > +#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI 0x001e > +#define PCI_DEVICE_ID_APPLE_UNI_N_PCI 0x001f > +#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL 0x0022 > +#define PCI_DEVICE_ID_APPLE_IPID_USB 0x003f > + > +/* Realtek (0x10ec) */ > +#define PCI_DEVICE_ID_REALTEK_8029 0x8029 > + > +/* Xilinx (0x10ee) */ > +#define PCI_DEVICE_ID_XILINX_XC2VP30 0x0300 > + > +/* Marvell (0x11ab) */ > +#define PCI_DEVICE_ID_MARVELL_GT6412X 0x4620 > + > +/* QEMU/Bochs VGA (0x1234) */ > +#define PCI_VENDOR_ID_QEMU 0x1234 > +#define PCI_DEVICE_ID_QEMU_VGA 0x1111 > + > +/* VMWare (0x15ad) */ > +#define PCI_VENDOR_ID_VMWARE 0x15ad > +#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 > +#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 > +#define PCI_DEVICE_ID_VMWARE_NET 0x0720 > +#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 > +#define PCI_DEVICE_ID_VMWARE_IDE 0x1729 > + > +/* Intel (0x8086) */ > +#define PCI_DEVICE_ID_INTEL_82551IT 0x1209 > +#define PCI_DEVICE_ID_INTEL_82557 0x1229 > +#define PCI_DEVICE_ID_INTEL_82801IR 0x2922 > + > +/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */ > +#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 > +#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4 > +#define PCI_SUBDEVICE_ID_QEMU 0x1100 > + > +#define PCI_DEVICE_ID_VIRTIO_NET 0x1000 > +#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 > +#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 > +#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 > +#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 > +#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 > + > +#define FMT_PCIBUS PRIx64 > + > +typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, > + uint32_t address, uint32_t data, int len); > +typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, > + uint32_t address, int len); > +typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, > + pcibus_t addr, pcibus_t size, int type); > +typedef void PCIUnregisterFunc(PCIDevice *pci_dev); > + > +typedef struct PCIIORegion { > + pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ > +#define PCI_BAR_UNMAPPED (~(pcibus_t)0) > + pcibus_t size; > + uint8_t type; > + MemoryRegion *memory; > + MemoryRegion *address_space; > +} PCIIORegion; > + > +#define PCI_ROM_SLOT 6 > +#define PCI_NUM_REGIONS 7 > + > +#include "pci_regs.h" > + > +/* PCI HEADER_TYPE */ > +#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 > + > +/* Size of the standard PCI config header */ > +#define PCI_CONFIG_HEADER_SIZE 0x40 > +/* Size of the standard PCI config space */ > +#define PCI_CONFIG_SPACE_SIZE 0x100 > +/* Size of the standart PCIe config space: 4KB */ > +#define PCIE_CONFIG_SPACE_SIZE 0x1000 > + > +#define PCI_NUM_PINS 4 /* A-D */ > + > +/* Bits in cap_present field. */ > +enum { > + QEMU_PCI_CAP_MSI = 0x1, > + QEMU_PCI_CAP_MSIX = 0x2, > + QEMU_PCI_CAP_EXPRESS = 0x4, > + > + /* multifunction capable device */ > +#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3 > + QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR), > + > + /* command register SERR bit enabled */ > +#define QEMU_PCI_CAP_SERR_BITNR 4 > + QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR), > + /* Standard hot plug controller. */ > +#define QEMU_PCI_SHPC_BITNR 5 > + QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR), > +#define QEMU_PCI_SLOTID_BITNR 6 > + QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_BITNR), > +}; > + > +#define TYPE_PCI_DEVICE "pci-device" > +#define PCI_DEVICE(obj) \ > + OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE) > +#define PCI_DEVICE_CLASS(klass) \ > + OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE) > +#define PCI_DEVICE_GET_CLASS(obj) \ > + OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE) > + > +typedef struct PCIINTxRoute { > + enum { > + PCI_INTX_ENABLED, > + PCI_INTX_INVERTED, > + PCI_INTX_DISABLED, > + } mode; > + int irq; > +} PCIINTxRoute; > + > +typedef struct PCIDeviceClass { > + DeviceClass parent_class; > + > + int (*init)(PCIDevice *dev); > + PCIUnregisterFunc *exit; > + PCIConfigReadFunc *config_read; > + PCIConfigWriteFunc *config_write; > + > + uint16_t vendor_id; > + uint16_t device_id; > + uint8_t revision; > + uint16_t class_id; > + uint16_t subsystem_vendor_id; /* only for header type = 0 */ > + uint16_t subsystem_id; /* only for header type = 0 */ > + > + /* > + * pci-to-pci bridge or normal device. > + * This doesn't mean pci host switch. > + * When card bus bridge is supported, this would be enhanced. > + */ > + int is_bridge; > + > + /* pcie stuff */ > + int is_express; /* is this device pci express? */ > + > + /* device isn't hot-pluggable */ > + int no_hotplug; > + > + /* rom bar */ > + const char *romfile; > +} PCIDeviceClass; > + > +typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev); > +typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector, > + MSIMessage msg); > +typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector); > + > +struct PCIDevice { > + DeviceState qdev; > + > + /* PCI config space */ > + uint8_t *config; > + > + /* Used to enable config checks on load. Note that writable bits are > + * never checked even if set in cmask. */ > + uint8_t *cmask; > + > + /* Used to implement R/W bytes */ > + uint8_t *wmask; > + > + /* Used to implement RW1C(Write 1 to Clear) bytes */ > + uint8_t *w1cmask; > + > + /* Used to allocate config space for capabilities. */ > + uint8_t *used; > + > + /* the following fields are read only */ > + PCIBus *bus; > + int32_t devfn; > + char name[64]; > + PCIIORegion io_regions[PCI_NUM_REGIONS]; > + AddressSpace bus_master_as; > + MemoryRegion bus_master_enable_region; > + DMAContext *dma; > + > + /* do not access the following fields */ > + PCIConfigReadFunc *config_read; > + PCIConfigWriteFunc *config_write; > + > + /* IRQ objects for the INTA-INTD pins. */ > + qemu_irq *irq; > + > + /* Current IRQ levels. Used internally by the generic PCI code. */ > + uint8_t irq_state; > + > + /* Capability bits */ > + uint32_t cap_present; > + > + /* Offset of MSI-X capability in config space */ > + uint8_t msix_cap; > + > + /* MSI-X entries */ > + int msix_entries_nr; > + > + /* Space to store MSIX table & pending bit array */ > + uint8_t *msix_table; > + uint8_t *msix_pba; > + /* MemoryRegion container for msix exclusive BAR setup */ > + MemoryRegion msix_exclusive_bar; > + /* Memory Regions for MSIX table and pending bit entries. */ > + MemoryRegion msix_table_mmio; > + MemoryRegion msix_pba_mmio; > + /* Reference-count for entries actually in use by driver. */ > + unsigned *msix_entry_used; > + /* MSIX function mask set or MSIX disabled */ > + bool msix_function_masked; > + /* Version id needed for VMState */ > + int32_t version_id; > + > + /* Offset of MSI capability in config space */ > + uint8_t msi_cap; > + > + /* PCI Express */ > + PCIExpressDevice exp; > + > + /* SHPC */ > + SHPCDevice *shpc; > + > + /* Location of option rom */ > + char *romfile; > + bool has_rom; > + MemoryRegion rom; > + uint32_t rom_bar; > + > + /* INTx routing notifier */ > + PCIINTxRoutingNotifier intx_routing_notifier; > + > + /* MSI-X notifiers */ > + MSIVectorUseNotifier msix_vector_use_notifier; > + MSIVectorReleaseNotifier msix_vector_release_notifier; > +}; > + > +void pci_register_bar(PCIDevice *pci_dev, int region_num, > + uint8_t attr, MemoryRegion *memory); > +pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num); > + > +int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, > + uint8_t offset, uint8_t size); > + > +void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); > + > +uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id); > + > + > +uint32_t pci_default_read_config(PCIDevice *d, > + uint32_t address, int len); > +void pci_default_write_config(PCIDevice *d, > + uint32_t address, uint32_t val, int len); > +void pci_device_save(PCIDevice *s, QEMUFile *f); > +int pci_device_load(PCIDevice *s, QEMUFile *f); > +MemoryRegion *pci_address_space(PCIDevice *dev); > +MemoryRegion *pci_address_space_io(PCIDevice *dev); > + > +typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); > +typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); > +typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin); > + > +typedef enum { > + PCI_HOTPLUG_DISABLED, > + PCI_HOTPLUG_ENABLED, > + PCI_COLDPLUG_ENABLED, > +} PCIHotplugState; > + > +typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, > + PCIHotplugState state); > +void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, > + const char *name, > + MemoryRegion *address_space_mem, > + MemoryRegion *address_space_io, > + uint8_t devfn_min); > +PCIBus *pci_bus_new(DeviceState *parent, const char *name, > + MemoryRegion *address_space_mem, > + MemoryRegion *address_space_io, > + uint8_t devfn_min); > +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > + void *irq_opaque, int nirq); > +int pci_bus_get_irq_level(PCIBus *bus, int irq_num); > +void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev); > +/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */ > +int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin); > +PCIBus *pci_register_bus(DeviceState *parent, const char *name, > + pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > + void *irq_opaque, > + MemoryRegion *address_space_mem, > + MemoryRegion *address_space_io, > + uint8_t devfn_min, int nirq); > +void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn); > +PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin); > +bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new); > +void pci_bus_fire_intx_routing_notifier(PCIBus *bus); > +void pci_device_set_intx_routing_notifier(PCIDevice *dev, > + PCIINTxRoutingNotifier notifier); > +void pci_device_reset(PCIDevice *dev); > +void pci_bus_reset(PCIBus *bus); > + > +PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, > + const char *default_devaddr); > +PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, > + const char *default_devaddr); > + > +PCIDevice *pci_vga_init(PCIBus *bus); > + > +int pci_bus_num(PCIBus *s); > +void pci_for_each_device(PCIBus *bus, int bus_num, > + void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque), > + void *opaque); > +PCIBus *pci_find_root_bus(int domain); > +int pci_find_domain(const PCIBus *bus); > +PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn); > +int pci_qdev_find_device(const char *id, PCIDevice **pdev); > +PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr); > + > +int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, > + unsigned *slotp); > + > +void pci_device_deassert_intx(PCIDevice *dev); > + > +typedef DMAContext *(*PCIDMAContextFunc)(PCIBus *, void *, int); > + > +void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque); > + > +static inline void > +pci_set_byte(uint8_t *config, uint8_t val) > +{ > + *config = val; > +} > + > +static inline uint8_t > +pci_get_byte(const uint8_t *config) > +{ > + return *config; > +} > + > +static inline void > +pci_set_word(uint8_t *config, uint16_t val) > +{ > + cpu_to_le16wu((uint16_t *)config, val); > +} > + > +static inline uint16_t > +pci_get_word(const uint8_t *config) > +{ > + return le16_to_cpupu((const uint16_t *)config); > +} > + > +static inline void > +pci_set_long(uint8_t *config, uint32_t val) > +{ > + cpu_to_le32wu((uint32_t *)config, val); > +} > + > +static inline uint32_t > +pci_get_long(const uint8_t *config) > +{ > + return le32_to_cpupu((const uint32_t *)config); > +} > + > +static inline void > +pci_set_quad(uint8_t *config, uint64_t val) > +{ > + cpu_to_le64w((uint64_t *)config, val); > +} > + > +static inline uint64_t > +pci_get_quad(const uint8_t *config) > +{ > + return le64_to_cpup((const uint64_t *)config); > +} > + > +static inline void > +pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val) > +{ > + pci_set_word(&pci_config[PCI_VENDOR_ID], val); > +} > + > +static inline void > +pci_config_set_device_id(uint8_t *pci_config, uint16_t val) > +{ > + pci_set_word(&pci_config[PCI_DEVICE_ID], val); > +} > + > +static inline void > +pci_config_set_revision(uint8_t *pci_config, uint8_t val) > +{ > + pci_set_byte(&pci_config[PCI_REVISION_ID], val); > +} > + > +static inline void > +pci_config_set_class(uint8_t *pci_config, uint16_t val) > +{ > + pci_set_word(&pci_config[PCI_CLASS_DEVICE], val); > +} > + > +static inline void > +pci_config_set_prog_interface(uint8_t *pci_config, uint8_t val) > +{ > + pci_set_byte(&pci_config[PCI_CLASS_PROG], val); > +} > + > +static inline void > +pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val) > +{ > + pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val); > +} > + > +/* > + * helper functions to do bit mask operation on configuration space. > + * Just to set bit, use test-and-set and discard returned value. > + * Just to clear bit, use test-and-clear and discard returned value. > + * NOTE: They aren't atomic. > + */ > +static inline uint8_t > +pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask) > +{ > + uint8_t val = pci_get_byte(config); > + pci_set_byte(config, val & ~mask); > + return val & mask; > +} > + > +static inline uint8_t > +pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask) > +{ > + uint8_t val = pci_get_byte(config); > + pci_set_byte(config, val | mask); > + return val & mask; > +} > + > +static inline uint16_t > +pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask) > +{ > + uint16_t val = pci_get_word(config); > + pci_set_word(config, val & ~mask); > + return val & mask; > +} > + > +static inline uint16_t > +pci_word_test_and_set_mask(uint8_t *config, uint16_t mask) > +{ > + uint16_t val = pci_get_word(config); > + pci_set_word(config, val | mask); > + return val & mask; > +} > + > +static inline uint32_t > +pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask) > +{ > + uint32_t val = pci_get_long(config); > + pci_set_long(config, val & ~mask); > + return val & mask; > +} > + > +static inline uint32_t > +pci_long_test_and_set_mask(uint8_t *config, uint32_t mask) > +{ > + uint32_t val = pci_get_long(config); > + pci_set_long(config, val | mask); > + return val & mask; > +} > + > +static inline uint64_t > +pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask) > +{ > + uint64_t val = pci_get_quad(config); > + pci_set_quad(config, val & ~mask); > + return val & mask; > +} > + > +static inline uint64_t > +pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask) > +{ > + uint64_t val = pci_get_quad(config); > + pci_set_quad(config, val | mask); > + return val & mask; > +} > + > +/* Access a register specified by a mask */ > +static inline void > +pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg) > +{ > + uint8_t val = pci_get_byte(config); > + uint8_t rval = reg << (ffs(mask) - 1); > + pci_set_byte(config, (~mask & val) | (mask & rval)); > +} > + > +static inline uint8_t > +pci_get_byte_by_mask(uint8_t *config, uint8_t mask) > +{ > + uint8_t val = pci_get_byte(config); > + return (val & mask) >> (ffs(mask) - 1); > +} > + > +static inline void > +pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg) > +{ > + uint16_t val = pci_get_word(config); > + uint16_t rval = reg << (ffs(mask) - 1); > + pci_set_word(config, (~mask & val) | (mask & rval)); > +} > + > +static inline uint16_t > +pci_get_word_by_mask(uint8_t *config, uint16_t mask) > +{ > + uint16_t val = pci_get_word(config); > + return (val & mask) >> (ffs(mask) - 1); > +} > + > +static inline void > +pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg) > +{ > + uint32_t val = pci_get_long(config); > + uint32_t rval = reg << (ffs(mask) - 1); > + pci_set_long(config, (~mask & val) | (mask & rval)); > +} > + > +static inline uint32_t > +pci_get_long_by_mask(uint8_t *config, uint32_t mask) > +{ > + uint32_t val = pci_get_long(config); > + return (val & mask) >> (ffs(mask) - 1); > +} > + > +static inline void > +pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg) > +{ > + uint64_t val = pci_get_quad(config); > + uint64_t rval = reg << (ffs(mask) - 1); > + pci_set_quad(config, (~mask & val) | (mask & rval)); > +} > + > +static inline uint64_t > +pci_get_quad_by_mask(uint8_t *config, uint64_t mask) > +{ > + uint64_t val = pci_get_quad(config); > + return (val & mask) >> (ffs(mask) - 1); > +} > + > +PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, > + const char *name); > +PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, > + bool multifunction, > + const char *name); > +PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); > +PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name); > + > +static inline int pci_is_express(const PCIDevice *d) > +{ > + return d->cap_present & QEMU_PCI_CAP_EXPRESS; > +} > + > +static inline uint32_t pci_config_size(const PCIDevice *d) > +{ > + return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; > +} > + > +/* DMA access functions */ > +static inline DMAContext *pci_dma_context(PCIDevice *dev) > +{ > + return dev->dma; > +} > + > +static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, > + void *buf, dma_addr_t len, DMADirection dir) > +{ > + dma_memory_rw(pci_dma_context(dev), addr, buf, len, dir); > + return 0; > +} > + > +static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr, > + void *buf, dma_addr_t len) > +{ > + return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE); > +} > + > +static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr, > + const void *buf, dma_addr_t len) > +{ > + return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE); > +} > + > +#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ > + static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \ > + dma_addr_t addr) \ > + { \ > + return ld##_l##_dma(pci_dma_context(dev), addr); \ > + } \ > + static inline void st##_s##_pci_dma(PCIDevice *dev, \ > + dma_addr_t addr, uint##_bits##_t val) \ > + { \ > + st##_s##_dma(pci_dma_context(dev), addr, val); \ > + } > + > +PCI_DMA_DEFINE_LDST(ub, b, 8); > +PCI_DMA_DEFINE_LDST(uw_le, w_le, 16) > +PCI_DMA_DEFINE_LDST(l_le, l_le, 32); > +PCI_DMA_DEFINE_LDST(q_le, q_le, 64); > +PCI_DMA_DEFINE_LDST(uw_be, w_be, 16) > +PCI_DMA_DEFINE_LDST(l_be, l_be, 32); > +PCI_DMA_DEFINE_LDST(q_be, q_be, 64); > + > +#undef PCI_DMA_DEFINE_LDST > + > +static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, > + dma_addr_t *plen, DMADirection dir) > +{ > + void *buf; > + > + buf = dma_memory_map(pci_dma_context(dev), addr, plen, dir); > + return buf; > +} > + > +static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len, > + DMADirection dir, dma_addr_t access_len) > +{ > + dma_memory_unmap(pci_dma_context(dev), buffer, len, dir, access_len); > +} > + > +static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev, > + int alloc_hint) > +{ > + qemu_sglist_init(qsg, alloc_hint, pci_dma_context(dev)); > +} > + > +extern const VMStateDescription vmstate_pci_device; > + > +#define VMSTATE_PCI_DEVICE(_field, _state) { \ > + .name = (stringify(_field)), \ > + .size = sizeof(PCIDevice), \ > + .vmsd = &vmstate_pci_device, \ > + .flags = VMS_STRUCT, \ > + .offset = vmstate_offset_value(_state, _field, PCIDevice), \ > +} > + > +#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { \ > + .name = (stringify(_field)), \ > + .size = sizeof(PCIDevice), \ > + .vmsd = &vmstate_pci_device, \ > + .flags = VMS_STRUCT|VMS_POINTER, \ > + .offset = vmstate_offset_pointer(_state, _field, PCIDevice), \ > +} > + > +#endif > diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c > new file mode 100644 > index 0000000..4680501 > --- /dev/null > +++ b/hw/pci/pci_bridge.c > @@ -0,0 +1,363 @@ > +/* > + * QEMU PCI bus manager > + * > + * Copyright (c) 2004 Fabrice Bellard > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to dea > + > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM > + > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > +/* > + * split out from pci.c > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + */ > + > +#include "pci_bridge.h" > +#include "pci_internals.h" > +#include "range.h" > + > +/* PCI bridge subsystem vendor ID helper functions */ > +#define PCI_SSVID_SIZEOF 8 > +#define PCI_SSVID_SVID 4 > +#define PCI_SSVID_SSID 6 > + > +int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, > + uint16_t svid, uint16_t ssid) > +{ > + int pos; > + pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF); > + if (pos < 0) { > + return pos; > + } > + > + pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid); > + pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid); > + return pos; > +} > + > +/* Accessor function to get parent bridge device from pci bus. */ > +PCIDevice *pci_bridge_get_device(PCIBus *bus) > +{ > + return bus->parent_dev; > +} > + > +/* Accessor function to get secondary bus from pci-to-pci bridge device */ > +PCIBus *pci_bridge_get_sec_bus(PCIBridge *br) > +{ > + return &br->sec_bus; > +} > + > +static uint32_t pci_config_get_io_base(const PCIDevice *d, > + uint32_t base, uint32_t base_upper16) > +{ > + uint32_t val; > + > + val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8; > + if (d->config[base] & PCI_IO_RANGE_TYPE_32) { > + val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16; > + } > + return val; > +} > + > +static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base) > +{ > + return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) > + << 16; > +} > + > +static pcibus_t pci_config_get_pref_base(const PCIDevice *d, > + uint32_t base, uint32_t upper) > +{ > + pcibus_t tmp; > + pcibus_t val; > + > + tmp = (pcibus_t)pci_get_word(d->config + base); > + val = (tmp & PCI_PREF_RANGE_MASK) << 16; > + if (tmp & PCI_PREF_RANGE_TYPE_64) { > + val |= (pcibus_t)pci_get_long(d->config + upper) << 32; > + } > + return val; > +} > + > +/* accessor function to get bridge filtering base address */ > +pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type) > +{ > + pcibus_t base; > + if (type & PCI_BASE_ADDRESS_SPACE_IO) { > + base = pci_config_get_io_base(bridge, > + PCI_IO_BASE, PCI_IO_BASE_UPPER16); > + } else { > + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > + base = pci_config_get_pref_base( > + bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32); > + } else { > + base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE); > + } > + } > + > + return base; > +} > + > +/* accessor funciton to get bridge filtering limit */ > +pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type) > +{ > + pcibus_t limit; > + if (type & PCI_BASE_ADDRESS_SPACE_IO) { > + limit = pci_config_get_io_base(bridge, > + PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16); > + limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */ > + } else { > + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > + limit = pci_config_get_pref_base( > + bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32); > + } else { > + limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT); > + } > + limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */ > + } > + return limit; > +} > + > +static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, > + uint8_t type, const char *name, > + MemoryRegion *space, > + MemoryRegion *parent_space, > + bool enabled) > +{ > + pcibus_t base = pci_bridge_get_base(&bridge->dev, type); > + pcibus_t limit = pci_bridge_get_limit(&bridge->dev, type); > + /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly. > + * Apparently no way to do this with existing memory APIs. */ > + pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0; > + > + memory_region_init_alias(alias, name, space, base, size); > + memory_region_add_subregion_overlap(parent_space, base, alias, 1); > +} > + > +static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) > +{ > + PCIBus *parent = br->dev.bus; > + PCIBridgeWindows *w = g_new(PCIBridgeWindows, 1); > + uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND); > + > + pci_bridge_init_alias(br, &w->alias_pref_mem, > + PCI_BASE_ADDRESS_MEM_PREFETCH, > + "pci_bridge_pref_mem", > + &br->address_space_mem, > + parent->address_space_mem, > + cmd & PCI_COMMAND_MEMORY); > + pci_bridge_init_alias(br, &w->alias_mem, > + PCI_BASE_ADDRESS_SPACE_MEMORY, > + "pci_bridge_mem", > + &br->address_space_mem, > + parent->address_space_mem, > + cmd & PCI_COMMAND_MEMORY); > + pci_bridge_init_alias(br, &w->alias_io, > + PCI_BASE_ADDRESS_SPACE_IO, > + "pci_bridge_io", > + &br->address_space_io, > + parent->address_space_io, > + cmd & PCI_COMMAND_IO); > + /* TODO: optinal VGA and VGA palette snooping support. */ > + > + return w; > +} > + > +static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w) > +{ > + PCIBus *parent = br->dev.bus; > + > + memory_region_del_subregion(parent->address_space_io, &w->alias_io); > + memory_region_del_subregion(parent->address_space_mem, &w->alias_mem); > + memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem); > +} > + > +static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w) > +{ > + memory_region_destroy(&w->alias_io); > + memory_region_destroy(&w->alias_mem); > + memory_region_destroy(&w->alias_pref_mem); > + g_free(w); > +} > + > +static void pci_bridge_update_mappings(PCIBridge *br) > +{ > + PCIBridgeWindows *w = br->windows; > + > + /* Make updates atomic to: handle the case of one VCPU updating the bridge > + * while another accesses an unaffected region. */ > + memory_region_transaction_begin(); > + pci_bridge_region_del(br, br->windows); > + br->windows = pci_bridge_region_init(br); > + memory_region_transaction_commit(); > + pci_bridge_region_cleanup(br, w); > +} > + > +/* default write_config function for PCI-to-PCI bridge */ > +void pci_bridge_write_config(PCIDevice *d, > + uint32_t address, uint32_t val, int len) > +{ > + PCIBridge *s = container_of(d, PCIBridge, dev); > + uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); > + uint16_t newctl; > + > + pci_default_write_config(d, address, val, len); > + > + if (ranges_overlap(address, len, PCI_COMMAND, 2) || > + > + /* io base/limit */ > + ranges_overlap(address, len, PCI_IO_BASE, 2) || > + > + /* memory base/limit, prefetchable base/limit and > + io base/limit upper 16 */ > + ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { > + pci_bridge_update_mappings(s); > + } > + > + newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); > + if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) { > + /* Trigger hot reset on 0->1 transition. */ > + pci_bus_reset(&s->sec_bus); > + } > +} > + > +void pci_bridge_disable_base_limit(PCIDevice *dev) > +{ > + uint8_t *conf = dev->config; > + > + pci_byte_test_and_set_mask(conf + PCI_IO_BASE, > + PCI_IO_RANGE_MASK & 0xff); > + pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, > + PCI_IO_RANGE_MASK & 0xff); > + pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE, > + PCI_MEMORY_RANGE_MASK & 0xffff); > + pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, > + PCI_MEMORY_RANGE_MASK & 0xffff); > + pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE, > + PCI_PREF_RANGE_MASK & 0xffff); > + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, > + PCI_PREF_RANGE_MASK & 0xffff); > + pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); > + pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); > +} > + > +/* reset bridge specific configuration registers */ > +void pci_bridge_reset(DeviceState *qdev) > +{ > + PCIDevice *dev = PCI_DEVICE(qdev); > + uint8_t *conf = dev->config; > + > + conf[PCI_PRIMARY_BUS] = 0; > + conf[PCI_SECONDARY_BUS] = 0; > + conf[PCI_SUBORDINATE_BUS] = 0; > + conf[PCI_SEC_LATENCY_TIMER] = 0; > + > + /* > + * the default values for base/limit registers aren't specified > + * in the PCI-to-PCI-bridge spec. So we don't thouch them here. > + * Each implementation can override it. > + * typical implementation does > + * zero base/limit registers or > + * disable forwarding: pci_bridge_disable_base_limit() > + * If disable forwarding is wanted, call pci_bridge_disable_base_limit() > + * after this function. > + */ > + pci_byte_test_and_clear_mask(conf + PCI_IO_BASE, > + PCI_IO_RANGE_MASK & 0xff); > + pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, > + PCI_IO_RANGE_MASK & 0xff); > + pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE, > + PCI_MEMORY_RANGE_MASK & 0xffff); > + pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, > + PCI_MEMORY_RANGE_MASK & 0xffff); > + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE, > + PCI_PREF_RANGE_MASK & 0xffff); > + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, > + PCI_PREF_RANGE_MASK & 0xffff); > + pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); > + pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); > + > + pci_set_word(conf + PCI_BRIDGE_CONTROL, 0); > +} > + > +/* default qdev initialization function for PCI-to-PCI bridge */ > +int pci_bridge_initfn(PCIDevice *dev) > +{ > + PCIBus *parent = dev->bus; > + PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); > + PCIBus *sec_bus = &br->sec_bus; > + > + pci_word_test_and_set_mask(dev->config + PCI_STATUS, > + PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); > + pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI); > + dev->config[PCI_HEADER_TYPE] = > + (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) | > + PCI_HEADER_TYPE_BRIDGE; > + pci_set_word(dev->config + PCI_SEC_STATUS, > + PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); > + > + /* > + * If we don't specify the name, the bus will be addressed as <id>.0, where > + * id is the device id. > + * Since PCI Bridge devices have a single bus each, we don't need the index: > + * let users address the bus using the device name. > + */ > + if (!br->bus_name && dev->qdev.id && *dev->qdev.id) { > + br->bus_name = dev->qdev.id; > + } > + > + qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev, > + br->bus_name); > + sec_bus->parent_dev = dev; > + sec_bus->map_irq = br->map_irq; > + sec_bus->address_space_mem = &br->address_space_mem; > + memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX); > + sec_bus->address_space_io = &br->address_space_io; > + memory_region_init(&br->address_space_io, "pci_bridge_io", 65536); > + br->windows = pci_bridge_region_init(br); > + QLIST_INIT(&sec_bus->child); > + QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); > + return 0; > +} > + > +/* default qdev clean up function for PCI-to-PCI bridge */ > +void pci_bridge_exitfn(PCIDevice *pci_dev) > +{ > + PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); > + assert(QLIST_EMPTY(&s->sec_bus.child)); > + QLIST_REMOVE(&s->sec_bus, sibling); > + pci_bridge_region_del(s, s->windows); > + pci_bridge_region_cleanup(s, s->windows); > + memory_region_destroy(&s->address_space_mem); > + memory_region_destroy(&s->address_space_io); > + /* qbus_free() is called automatically by qdev_free() */ > +} > + > +/* > + * before qdev initialization(qdev_init()), this function sets bus_name and > + * map_irq callback which are necessry for pci_bridge_initfn() to > + * initialize bus. > + */ > +void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, > + pci_map_irq_fn map_irq) > +{ > + br->map_irq = map_irq; > + br->bus_name = bus_name; > +} > diff --git a/hw/pci/pci_bridge.h b/hw/pci/pci_bridge.h > new file mode 100644 > index 0000000..a00accc > --- /dev/null > +++ b/hw/pci/pci_bridge.h > @@ -0,0 +1,66 @@ > +/* > + * QEMU PCI bridge > + * > + * Copyright (c) 2004 Fabrice Bellard > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + * > + * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc] > + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + */ > + > +#ifndef QEMU_PCI_BRIDGE_H > +#define QEMU_PCI_BRIDGE_H > + > +#include "pci.h" > + > +int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, > + uint16_t svid, uint16_t ssid); > + > +PCIDevice *pci_bridge_get_device(PCIBus *bus); > +PCIBus *pci_bridge_get_sec_bus(PCIBridge *br); > + > +pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type); > +pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type); > + > +void pci_bridge_write_config(PCIDevice *d, > + uint32_t address, uint32_t val, int len); > +void pci_bridge_disable_base_limit(PCIDevice *dev); > +void pci_bridge_reset_reg(PCIDevice *dev); > +void pci_bridge_reset(DeviceState *qdev); > + > +int pci_bridge_initfn(PCIDevice *pci_dev); > +void pci_bridge_exitfn(PCIDevice *pci_dev); > + > + > +/* > + * before qdev initialization(qdev_init()), this function sets bus_name and > + * map_irq callback which are necessry for pci_bridge_initfn() to > + * initialize bus. > + */ > +void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, > + pci_map_irq_fn map_irq); > + > +#endif /* QEMU_PCI_BRIDGE_H */ > +/* > + * Local variables: > + * c-indent-level: 4 > + * c-basic-offset: 4 > + * tab-width: 8 > + * indent-tab-mode: nil > + * End: > + */ > diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c > new file mode 100644 > index 0000000..68e328c > --- /dev/null > +++ b/hw/pci/pci_host.c > @@ -0,0 +1,180 @@ > +/* > + * pci_host.c > + * > + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "pci.h" > +#include "pci_host.h" > + > +/* debug PCI */ > +//#define DEBUG_PCI > + > +#ifdef DEBUG_PCI > +#define PCI_DPRINTF(fmt, ...) \ > +do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0) > +#else > +#define PCI_DPRINTF(fmt, ...) > +#endif > + > +/* > + * PCI address > + * bit 16 - 24: bus number > + * bit 8 - 15: devfun number > + * bit 0 - 7: offset in configuration space of a given pci device > + */ > + > +/* the helper functio to get a PCIDeice* for a given pci address */ > +static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr) > +{ > + uint8_t bus_num = addr >> 16; > + uint8_t devfn = addr >> 8; > + > + return pci_find_device(bus, bus_num, devfn); > +} > + > +void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, > + uint32_t limit, uint32_t val, uint32_t len) > +{ > + assert(len <= 4); > + pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr)); > +} > + > +uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, > + uint32_t limit, uint32_t len) > +{ > + assert(len <= 4); > + return pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr)); > +} > + > +void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len) > +{ > + PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); > + uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); > + > + if (!pci_dev) { > + return; > + } > + > + PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n", > + __func__, pci_dev->name, config_addr, val, len); > + pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE, > + val, len); > +} > + > +uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) > +{ > + PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); > + uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); > + uint32_t val; > + > + if (!pci_dev) { > + return ~0x0; > + } > + > + val = pci_host_config_read_common(pci_dev, config_addr, > + PCI_CONFIG_SPACE_SIZE, len); > + PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n", > + __func__, pci_dev->name, config_addr, val, len); > + > + return val; > +} > + > +static void pci_host_config_write(void *opaque, hwaddr addr, > + uint64_t val, unsigned len) > +{ > + PCIHostState *s = opaque; > + > + PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", > + __func__, addr, len, val); > + if (addr != 0 || len != 4) { > + return; > + } > + s->config_reg = val; > +} > + > +static uint64_t pci_host_config_read(void *opaque, hwaddr addr, > + unsigned len) > +{ > + PCIHostState *s = opaque; > + uint32_t val = s->config_reg; > + > + PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n", > + __func__, addr, len, val); > + return val; > +} > + > +static void pci_host_data_write(void *opaque, hwaddr addr, > + uint64_t val, unsigned len) > +{ > + PCIHostState *s = opaque; > + PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n", > + addr, len, (unsigned)val); > + if (s->config_reg & (1u << 31)) > + pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); > +} > + > +static uint64_t pci_host_data_read(void *opaque, > + hwaddr addr, unsigned len) > +{ > + PCIHostState *s = opaque; > + uint32_t val; > + if (!(s->config_reg & (1 << 31))) > + return 0xffffffff; > + val = pci_data_read(s->bus, s->config_reg | (addr & 3), len); > + PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n", > + addr, len, val); > + return val; > +} > + > +const MemoryRegionOps pci_host_conf_le_ops = { > + .read = pci_host_config_read, > + .write = pci_host_config_write, > + .endianness = DEVICE_LITTLE_ENDIAN, > +}; > + > +const MemoryRegionOps pci_host_conf_be_ops = { > + .read = pci_host_config_read, > + .write = pci_host_config_write, > + .endianness = DEVICE_BIG_ENDIAN, > +}; > + > +const MemoryRegionOps pci_host_data_le_ops = { > + .read = pci_host_data_read, > + .write = pci_host_data_write, > + .endianness = DEVICE_LITTLE_ENDIAN, > +}; > + > +const MemoryRegionOps pci_host_data_be_ops = { > + .read = pci_host_data_read, > + .write = pci_host_data_write, > + .endianness = DEVICE_BIG_ENDIAN, > +}; > + > +static const TypeInfo pci_host_type_info = { > + .name = TYPE_PCI_HOST_BRIDGE, > + .parent = TYPE_SYS_BUS_DEVICE, > + .abstract = true, > + .instance_size = sizeof(PCIHostState), > +}; > + > +static void pci_host_register_types(void) > +{ > + type_register_static(&pci_host_type_info); > +} > + > +type_init(pci_host_register_types) > diff --git a/hw/pci/pci_host.h b/hw/pci/pci_host.h > new file mode 100644 > index 0000000..4b9c300 > --- /dev/null > +++ b/hw/pci/pci_host.h > @@ -0,0 +1,62 @@ > +/* > + * QEMU Common PCI Host bridge configuration data space access routines. > + * > + * Copyright (c) 2006 Fabrice Bellard > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > + > +/* Worker routines for a PCI host controller that uses an {address,data} > + register pair to access PCI configuration space. */ > + > +#ifndef PCI_HOST_H > +#define PCI_HOST_H > + > +#include "sysbus.h" > + > +#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge" > +#define PCI_HOST_BRIDGE(obj) \ > + OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE) > + > +struct PCIHostState { > + SysBusDevice busdev; > + > + MemoryRegion conf_mem; > + MemoryRegion data_mem; > + MemoryRegion mmcfg; > + MemoryRegion *address_space; > + uint32_t config_reg; > + PCIBus *bus; > +}; > + > +/* common internal helpers for PCI/PCIe hosts, cut off overflows */ > +void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, > + uint32_t limit, uint32_t val, uint32_t len); > +uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, > + uint32_t limit, uint32_t len); > + > +void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len); > +uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len); > + > +extern const MemoryRegionOps pci_host_conf_le_ops; > +extern const MemoryRegionOps pci_host_conf_be_ops; > +extern const MemoryRegionOps pci_host_data_le_ops; > +extern const MemoryRegionOps pci_host_data_be_ops; > + > +#endif /* PCI_HOST_H */ > diff --git a/hw/pci/pci_ids.h b/hw/pci/pci_ids.h > new file mode 100644 > index 0000000..5df7245 > --- /dev/null > +++ b/hw/pci/pci_ids.h > @@ -0,0 +1,147 @@ > +/* > + * PCI Class, Vendor and Device IDs > + * > + * Please keep sorted. > + * > + * Abbreviated version of linux/pci_ids.h > + * > + * QEMU-specific definitions belong in pci.h > + */ > + > +/* Device classes and subclasses */ > + > +#define PCI_BASE_CLASS_STORAGE 0x01 > +#define PCI_BASE_CLASS_NETWORK 0x02 > + > +#define PCI_CLASS_STORAGE_SCSI 0x0100 > +#define PCI_CLASS_STORAGE_IDE 0x0101 > +#define PCI_CLASS_STORAGE_RAID 0x0104 > +#define PCI_CLASS_STORAGE_SATA 0x0106 > +#define PCI_CLASS_STORAGE_OTHER 0x0180 > + > +#define PCI_CLASS_NETWORK_ETHERNET 0x0200 > + > +#define PCI_CLASS_DISPLAY_VGA 0x0300 > +#define PCI_CLASS_DISPLAY_OTHER 0x0380 > + > +#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 > + > +#define PCI_CLASS_MEMORY_RAM 0x0500 > + > +#define PCI_CLASS_SYSTEM_OTHER 0x0880 > + > +#define PCI_CLASS_SERIAL_USB 0x0c03 > +#define PCI_CLASS_SERIAL_SMBUS 0x0c05 > + > +#define PCI_CLASS_BRIDGE_HOST 0x0600 > +#define PCI_CLASS_BRIDGE_ISA 0x0601 > +#define PCI_CLASS_BRIDGE_PCI 0x0604 > +#define PCI_CLASS_BRDIGE_PCI_INF_SUB 0x01 > +#define PCI_CLASS_BRIDGE_OTHER 0x0680 > + > +#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 > +#define PCI_CLASS_COMMUNICATION_OTHER 0x0780 > + > +#define PCI_CLASS_PROCESSOR_CO 0x0b40 > +#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20 > + > +#define PCI_CLASS_OTHERS 0xff > + > +/* Vendors and devices. Sort key: vendor first, device next. */ > + > +#define PCI_VENDOR_ID_LSI_LOGIC 0x1000 > +#define PCI_DEVICE_ID_LSI_53C895A 0x0012 > +#define PCI_DEVICE_ID_LSI_SAS1078 0x0060 > + > +#define PCI_VENDOR_ID_DEC 0x1011 > +#define PCI_DEVICE_ID_DEC_21154 0x0026 > + > +#define PCI_VENDOR_ID_CIRRUS 0x1013 > + > +#define PCI_VENDOR_ID_IBM 0x1014 > + > +#define PCI_VENDOR_ID_AMD 0x1022 > +#define PCI_DEVICE_ID_AMD_LANCE 0x2000 > +#define PCI_DEVICE_ID_AMD_SCSI 0x2020 > + > +#define PCI_VENDOR_ID_TI 0x104c > + > +#define PCI_VENDOR_ID_MOTOROLA 0x1057 > +#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 > +#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 > + > +#define PCI_VENDOR_ID_APPLE 0x106b > +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 > +#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b > + > +#define PCI_VENDOR_ID_SUN 0x108e > +#define PCI_DEVICE_ID_SUN_EBUS 0x1000 > +#define PCI_DEVICE_ID_SUN_SIMBA 0x5000 > +#define PCI_DEVICE_ID_SUN_SABRE 0xa000 > + > +#define PCI_VENDOR_ID_CMD 0x1095 > +#define PCI_DEVICE_ID_CMD_646 0x0646 > + > +#define PCI_VENDOR_ID_REALTEK 0x10ec > +#define PCI_DEVICE_ID_REALTEK_8139 0x8139 > + > +#define PCI_VENDOR_ID_XILINX 0x10ee > + > +#define PCI_VENDOR_ID_VIA 0x1106 > +#define PCI_DEVICE_ID_VIA_ISA_BRIDGE 0x0686 > +#define PCI_DEVICE_ID_VIA_IDE 0x0571 > +#define PCI_DEVICE_ID_VIA_UHCI 0x3038 > +#define PCI_DEVICE_ID_VIA_ACPI 0x3057 > +#define PCI_DEVICE_ID_VIA_AC97 0x3058 > +#define PCI_DEVICE_ID_VIA_MC97 0x3068 > + > +#define PCI_VENDOR_ID_MARVELL 0x11ab > + > +#define PCI_VENDOR_ID_ENSONIQ 0x1274 > +#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 > + > +#define PCI_VENDOR_ID_FREESCALE 0x1957 > +#define PCI_DEVICE_ID_MPC8533E 0x0030 > + > +#define PCI_VENDOR_ID_INTEL 0x8086 > +#define PCI_DEVICE_ID_INTEL_82378 0x0484 > +#define PCI_DEVICE_ID_INTEL_82441 0x1237 > +#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 > +#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e > +#define PCI_DEVICE_ID_INTEL_82801D 0x24CD > +#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab > +#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 > +#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 > +#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 > +#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 > +#define PCI_DEVICE_ID_INTEL_82371AB 0x7111 > +#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 > +#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 > + > +#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 > +#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 > +#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 > +#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 > +#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 > +#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 > +#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 > +#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 > +#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 > + > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934 > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935 > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936 > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937 > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938 > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939 > +#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a > +#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c > +#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed > + > +#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 > + > +#define PCI_VENDOR_ID_XEN 0x5853 > +#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 > + > +#define PCI_VENDOR_ID_NEC 0x1033 > +#define PCI_DEVICE_ID_NEC_UPD720200 0x0194 > diff --git a/hw/pci/pci_internals.h b/hw/pci/pci_internals.h > new file mode 100644 > index 0000000..21d0ce6 > --- /dev/null > +++ b/hw/pci/pci_internals.h > @@ -0,0 +1,78 @@ > +#ifndef QEMU_PCI_INTERNALS_H > +#define QEMU_PCI_INTERNALS_H > + > +/* > + * This header files is private to pci.c and pci_bridge.c > + * So following structures are opaque to others and shouldn't be > + * accessed. > + * > + * For pci-to-pci bridge needs to include this header file to embed > + * PCIBridge in its structure or to get sizeof(PCIBridge), > + * However, they shouldn't access those following members directly. > + * Use accessor function in pci.h, pci_bridge.h > + */ > + > +#define TYPE_PCI_BUS "PCI" > +#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) > + > +struct PCIBus { > + BusState qbus; > + PCIDMAContextFunc dma_context_fn; > + void *dma_context_opaque; > + uint8_t devfn_min; > + pci_set_irq_fn set_irq; > + pci_map_irq_fn map_irq; > + pci_route_irq_fn route_intx_to_irq; > + pci_hotplug_fn hotplug; > + DeviceState *hotplug_qdev; > + void *irq_opaque; > + PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; > + PCIDevice *parent_dev; > + MemoryRegion *address_space_mem; > + MemoryRegion *address_space_io; > + > + QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ > + QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ > + > + /* The bus IRQ state is the logical OR of the connected devices. > + Keep a count of the number of devices with raised IRQs. */ > + int nirq; > + int *irq_count; > +}; > + > +typedef struct PCIBridgeWindows PCIBridgeWindows; > + > +/* > + * Aliases for each of the address space windows that the bridge > + * can forward. Mapped into the bridge's parent's address space, > + * as subregions. > + */ > +struct PCIBridgeWindows { > + MemoryRegion alias_pref_mem; > + MemoryRegion alias_mem; > + MemoryRegion alias_io; > +}; > + > +struct PCIBridge { > + PCIDevice dev; > + > + /* private member */ > + PCIBus sec_bus; > + /* > + * Memory regions for the bridge's address spaces. These regions are not > + * directly added to system_memory/system_io or its descendants. > + * Bridge's secondary bus points to these, so that devices > + * under the bridge see these regions as its address spaces. > + * The regions are as large as the entire address space - > + * they don't take into account any windows. > + */ > + MemoryRegion address_space_mem; > + MemoryRegion address_space_io; > + > + PCIBridgeWindows *windows; > + > + pci_map_irq_fn map_irq; > + const char *bus_name; > +}; > + > +#endif /* QEMU_PCI_INTERNALS_H */ > diff --git a/hw/pci/pci_regs.h b/hw/pci/pci_regs.h > new file mode 100644 > index 0000000..56a404b > --- /dev/null > +++ b/hw/pci/pci_regs.h > @@ -0,0 +1,717 @@ > +/* > + * pci_regs.h > + * > + * PCI standard defines > + * Copyright 1994, Drew Eckhardt > + * Copyright 1997--1999 Martin Mares <mj@ucw.cz> > + * > + * For more information, please consult the following manuals (look at > + * http://www.pcisig.com/ for how to get them): > + * > + * PCI BIOS Specification > + * PCI Local Bus Specification > + * PCI to PCI Bridge Specification > + * PCI System Design Guide > + * > + * For hypertransport information, please consult the following manuals > + * from http://www.hypertransport.org > + * > + * The Hypertransport I/O Link Specification > + */ > + > +#ifndef LINUX_PCI_REGS_H > +#define LINUX_PCI_REGS_H > + > +/* > + * Under PCI, each device has 256 bytes of configuration address space, > + * of which the first 64 bytes are standardized as follows: > + */ > +#define PCI_VENDOR_ID 0x00 /* 16 bits */ > +#define PCI_DEVICE_ID 0x02 /* 16 bits */ > +#define PCI_COMMAND 0x04 /* 16 bits */ > +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ > +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ > +#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ > +#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ > +#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ > +#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ > +#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ > +#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ > +#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ > +#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ > +#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ > + > +#define PCI_STATUS 0x06 /* 16 bits */ > +#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */ > +#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ > +#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ > +#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ > +#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ > +#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ > +#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ > +#define PCI_STATUS_DEVSEL_FAST 0x000 > +#define PCI_STATUS_DEVSEL_MEDIUM 0x200 > +#define PCI_STATUS_DEVSEL_SLOW 0x400 > +#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ > +#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ > +#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ > +#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ > +#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ > + > +#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ > +#define PCI_REVISION_ID 0x08 /* Revision ID */ > +#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ > +#define PCI_CLASS_DEVICE 0x0a /* Device class */ > + > +#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ > +#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ > +#define PCI_HEADER_TYPE 0x0e /* 8 bits */ > +#define PCI_HEADER_TYPE_NORMAL 0 > +#define PCI_HEADER_TYPE_BRIDGE 1 > +#define PCI_HEADER_TYPE_CARDBUS 2 > + > +#define PCI_BIST 0x0f /* 8 bits */ > +#define PCI_BIST_CODE_MASK 0x0f /* Return result */ > +#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ > +#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ > + > +/* > + * Base addresses specify locations in memory or I/O space. > + * Decoded size can be determined by writing a value of > + * 0xffffffff to the register, and reading it back. Only > + * 1 bits are decoded. > + */ > +#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ > +#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ > +#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ > +#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ > +#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ > +#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ > +#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ > +#define PCI_BASE_ADDRESS_SPACE_IO 0x01 > +#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 > +#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 > +#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ > +#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ > +#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ > +#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ > +#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) > +#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) > +/* bit 1 is reserved if address_space = 1 */ > + > +/* Header type 0 (normal devices) */ > +#define PCI_CARDBUS_CIS 0x28 > +#define PCI_SUBSYSTEM_VENDOR_ID 0x2c > +#define PCI_SUBSYSTEM_ID 0x2e > +#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ > +#define PCI_ROM_ADDRESS_ENABLE 0x01 > +#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) > + > +#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ > + > +/* 0x35-0x3b are reserved */ > +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ > +#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ > +#define PCI_MIN_GNT 0x3e /* 8 bits */ > +#define PCI_MAX_LAT 0x3f /* 8 bits */ > + > +/* Header type 1 (PCI-to-PCI bridges) */ > +#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ > +#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ > +#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ > +#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ > +#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ > +#define PCI_IO_LIMIT 0x1d > +#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ > +#define PCI_IO_RANGE_TYPE_16 0x00 > +#define PCI_IO_RANGE_TYPE_32 0x01 > +#define PCI_IO_RANGE_MASK (~0x0fUL) > +#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ > +#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ > +#define PCI_MEMORY_LIMIT 0x22 > +#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL > +#define PCI_MEMORY_RANGE_MASK (~0x0fUL) > +#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ > +#define PCI_PREF_MEMORY_LIMIT 0x26 > +#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL > +#define PCI_PREF_RANGE_TYPE_32 0x00 > +#define PCI_PREF_RANGE_TYPE_64 0x01 > +#define PCI_PREF_RANGE_MASK (~0x0fUL) > +#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ > +#define PCI_PREF_LIMIT_UPPER32 0x2c > +#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ > +#define PCI_IO_LIMIT_UPPER16 0x32 > +/* 0x34 same as for htype 0 */ > +/* 0x35-0x3b is reserved */ > +#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ > +/* 0x3c-0x3d are same as for htype 0 */ > +#define PCI_BRIDGE_CONTROL 0x3e > +#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ > +#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ > +#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */ > +#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ > +#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ > +#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ > +#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ > + > +/* Header type 2 (CardBus bridges) */ > +#define PCI_CB_CAPABILITY_LIST 0x14 > +/* 0x15 reserved */ > +#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */ > +#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */ > +#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */ > +#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */ > +#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ > +#define PCI_CB_MEMORY_BASE_0 0x1c > +#define PCI_CB_MEMORY_LIMIT_0 0x20 > +#define PCI_CB_MEMORY_BASE_1 0x24 > +#define PCI_CB_MEMORY_LIMIT_1 0x28 > +#define PCI_CB_IO_BASE_0 0x2c > +#define PCI_CB_IO_BASE_0_HI 0x2e > +#define PCI_CB_IO_LIMIT_0 0x30 > +#define PCI_CB_IO_LIMIT_0_HI 0x32 > +#define PCI_CB_IO_BASE_1 0x34 > +#define PCI_CB_IO_BASE_1_HI 0x36 > +#define PCI_CB_IO_LIMIT_1 0x38 > +#define PCI_CB_IO_LIMIT_1_HI 0x3a > +#define PCI_CB_IO_RANGE_MASK (~0x03UL) > +/* 0x3c-0x3d are same as for htype 0 */ > +#define PCI_CB_BRIDGE_CONTROL 0x3e > +#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */ > +#define PCI_CB_BRIDGE_CTL_SERR 0x02 > +#define PCI_CB_BRIDGE_CTL_ISA 0x04 > +#define PCI_CB_BRIDGE_CTL_VGA 0x08 > +#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20 > +#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */ > +#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */ > +#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */ > +#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200 > +#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400 > +#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 > +#define PCI_CB_SUBSYSTEM_ID 0x42 > +#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */ > +/* 0x48-0x7f reserved */ > + > +/* Capability lists */ > + > +#define PCI_CAP_LIST_ID 0 /* Capability ID */ > +#define PCI_CAP_ID_PM 0x01 /* Power Management */ > +#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ > +#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ > +#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ > +#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ > +#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ > +#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ > +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ > +#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */ > +#define PCI_CAP_ID_DBG 0x0A /* Debug port */ > +#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ > +#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ > +#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ > +#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ > +#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ > +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ > +#define PCI_CAP_ID_SATA 0x12 /* Serial ATA */ > +#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ > +#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ > +#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ > +#define PCI_CAP_SIZEOF 4 > + > +/* Power Management Registers */ > + > +#define PCI_PM_PMC 2 /* PM Capabilities Register */ > +#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ > +#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ > +#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ > +#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ > +#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */ > +#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ > +#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ > +#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ > +#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ > +#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ > +#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ > +#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ > +#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ > +#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ > +#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */ > +#define PCI_PM_CTRL 4 /* PM control and status register */ > +#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ > +#define PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */ > +#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ > +#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ > +#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ > +#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ > +#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ > +#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ > +#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ > +#define PCI_PM_DATA_REGISTER 7 /* (??) */ > +#define PCI_PM_SIZEOF 8 > + > +/* AGP registers */ > + > +#define PCI_AGP_VERSION 2 /* BCD version number */ > +#define PCI_AGP_RFU 3 /* Rest of capability flags */ > +#define PCI_AGP_STATUS 4 /* Status register */ > +#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ > +#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ > +#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ > +#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ > +#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ > +#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ > +#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ > +#define PCI_AGP_COMMAND 8 /* Control register */ > +#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ > +#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ > +#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ > +#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ > +#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ > +#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ > +#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ > +#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ > +#define PCI_AGP_SIZEOF 12 > + > +/* Vital Product Data */ > + > +#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */ > +#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */ > +#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */ > +#define PCI_VPD_DATA 4 /* 32-bits of data returned here */ > + > +/* Slot Identification */ > + > +#define PCI_SID_ESR 2 /* Expansion Slot Register */ > +#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ > +#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ > +#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ > + > +/* Message Signalled Interrupts registers */ > + > +#define PCI_MSI_FLAGS 2 /* Various flags */ > +#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */ > +#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */ > +#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */ > +#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */ > +#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */ > +#define PCI_MSI_RFU 3 /* Rest of capability flags */ > +#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ > +#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ > +#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ > +#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */ > +#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ > +#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ > + > +/* MSI-X registers */ > +#define PCI_MSIX_FLAGS 2 > +#define PCI_MSIX_FLAGS_QSIZE 0x7FF > +#define PCI_MSIX_FLAGS_ENABLE (1 << 15) > +#define PCI_MSIX_FLAGS_MASKALL (1 << 14) > +#define PCI_MSIX_TABLE 4 > +#define PCI_MSIX_PBA 8 > +#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) > + > +/* MSI-X entry's format */ > +#define PCI_MSIX_ENTRY_SIZE 16 > +#define PCI_MSIX_ENTRY_LOWER_ADDR 0 > +#define PCI_MSIX_ENTRY_UPPER_ADDR 4 > +#define PCI_MSIX_ENTRY_DATA 8 > +#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 > +#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 > + > +/* CompactPCI Hotswap Register */ > + > +#define PCI_CHSWP_CSR 2 /* Control and Status Register */ > +#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */ > +#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */ > +#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */ > +#define PCI_CHSWP_LOO 0x08 /* LED On / Off */ > +#define PCI_CHSWP_PI 0x30 /* Programming Interface */ > +#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ > +#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ > + > +/* PCI Advanced Feature registers */ > + > +#define PCI_AF_LENGTH 2 > +#define PCI_AF_CAP 3 > +#define PCI_AF_CAP_TP 0x01 > +#define PCI_AF_CAP_FLR 0x02 > +#define PCI_AF_CTRL 4 > +#define PCI_AF_CTRL_FLR 0x01 > +#define PCI_AF_STATUS 5 > +#define PCI_AF_STATUS_TP 0x01 > + > +/* PCI-X registers */ > + > +#define PCI_X_CMD 2 /* Modes & Features */ > +#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ > +#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ > +#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ > +#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ > +#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ > +#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ > +#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ > + /* Max # of outstanding split transactions */ > +#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */ > +#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */ > +#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */ > +#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */ > +#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */ > +#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */ > +#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */ > +#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */ > +#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ > +#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */ > +#define PCI_X_STATUS 4 /* PCI-X capabilities */ > +#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */ > +#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */ > +#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */ > +#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */ > +#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */ > +#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */ > +#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */ > +#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count */ > +#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */ > +#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */ > +#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ > +#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ > +#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ > + > +/* PCI Bridge Subsystem ID registers */ > + > +#define PCI_SSVID_VENDOR_ID 4 /* PCI-Bridge subsystem vendor id register */ > +#define PCI_SSVID_DEVICE_ID 6 /* PCI-Bridge subsystem device id register */ > + > +/* PCI Express capability registers */ > + > +#define PCI_EXP_FLAGS 2 /* Capabilities register */ > +#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ > +#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ > +#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ > +#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ > +#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ > +#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ > +#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ > +#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ > +#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */ > +#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ > +#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ > +#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ > +#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ > +#define PCI_EXP_DEVCAP 4 /* Device capabilities */ > +#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */ > +#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */ > +#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */ > +#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */ > +#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */ > +#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ > +#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ > +#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ > +#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ > +#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ > +#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ > +#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ > +#define PCI_EXP_DEVCTL 8 /* Device Control */ > +#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ > +#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ > +#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ > +#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ > +#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */ > +#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ > +#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ > +#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ > +#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ > +#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ > +#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ > +#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ > +#define PCI_EXP_DEVSTA 10 /* Device Status */ > +#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ > +#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ > +#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */ > +#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */ > +#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ > +#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ > +#define PCI_EXP_LNKCAP 12 /* Link Capabilities */ > +#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */ > +#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */ > +#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */ > +#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */ > +#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */ > +#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* L1 Clock Power Management */ > +#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Reporting Capable */ > +#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link Active Reporting Capable */ > +#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notification Capability */ > +#define PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */ > +#define PCI_EXP_LNKCTL 16 /* Link Control */ > +#define PCI_EXP_LNKCTL_ASPMC 0x0003 /* ASPM Control */ > +#define PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */ > +#define PCI_EXP_LNKCTL_LD 0x0010 /* Link Disable */ > +#define PCI_EXP_LNKCTL_RL 0x0020 /* Retrain Link */ > +#define PCI_EXP_LNKCTL_CCC 0x0040 /* Common Clock Configuration */ > +#define PCI_EXP_LNKCTL_ES 0x0080 /* Extended Synch */ > +#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ > +#define PCI_EXP_LNKCTL_HAWD 0x0200 /* Hardware Autonomous Width Disable */ > +#define PCI_EXP_LNKCTL_LBMIE 0x0400 /* Link Bandwidth Management Interrupt Enable */ > +#define PCI_EXP_LNKCTL_LABIE 0x0800 /* Lnk Autonomous Bandwidth Interrupt Enable */ > +#define PCI_EXP_LNKSTA 18 /* Link Status */ > +#define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */ > +#define PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */ > +#define PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */ > +#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Nogotiated Link Width */ > +#define PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */ > +#define PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */ > +#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ > +#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ > +#define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ > +#define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */ > +#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ > +#define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */ > +#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */ > +#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */ > +#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Present */ > +#define PCI_EXP_SLTCAP_PIP 0x00000010 /* Power Indicator Present */ > +#define PCI_EXP_SLTCAP_HPS 0x00000020 /* Hot-Plug Surprise */ > +#define PCI_EXP_SLTCAP_HPC 0x00000040 /* Hot-Plug Capable */ > +#define PCI_EXP_SLTCAP_SPLV 0x00007f80 /* Slot Power Limit Value */ > +#define PCI_EXP_SLTCAP_SPLS 0x00018000 /* Slot Power Limit Scale */ > +#define PCI_EXP_SLTCAP_EIP 0x00020000 /* Electromechanical Interlock Present */ > +#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Support */ > +#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ > +#define PCI_EXP_SLTCTL 24 /* Slot Control */ > +#define PCI_EXP_SLTCTL_ABPE 0x0001 /* Attention Button Pressed Enable */ > +#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enable */ > +#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable */ > +#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed Enable */ > +#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable */ > +#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */ > +#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */ > +#define PCI_EXP_SLTCTL_PIC 0x0300 /* Power Indicator Control */ > +#define PCI_EXP_SLTCTL_PCC 0x0400 /* Power Controller Control */ > +#define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */ > +#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */ > +#define PCI_EXP_SLTSTA 26 /* Slot Status */ > +#define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */ > +#define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */ > +#define PCI_EXP_SLTSTA_MRLSC 0x0004 /* MRL Sensor Changed */ > +#define PCI_EXP_SLTSTA_PDC 0x0008 /* Presence Detect Changed */ > +#define PCI_EXP_SLTSTA_CC 0x0010 /* Command Completed */ > +#define PCI_EXP_SLTSTA_MRLSS 0x0020 /* MRL Sensor State */ > +#define PCI_EXP_SLTSTA_PDS 0x0040 /* Presence Detect State */ > +#define PCI_EXP_SLTSTA_EIS 0x0080 /* Electromechanical Interlock Status */ > +#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Changed */ > +#define PCI_EXP_RTCTL 28 /* Root Control */ > +#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctable Error */ > +#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal Error */ > +#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Error */ > +#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */ > +#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */ > +#define PCI_EXP_RTCAP 30 /* Root Capabilities */ > +#define PCI_EXP_RTSTA 32 /* Root Status */ > +#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ > +#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ > +#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ > +#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ > +#define PCI_EXP_DEVCAP2_LTR 0x800 /* Latency tolerance reporting */ > +#define PCI_EXP_OBFF_MASK 0xc0000 /* OBFF support mechanism */ > +#define PCI_EXP_OBFF_MSG 0x40000 /* New message signaling */ > +#define PCI_EXP_OBFF_WAKE 0x80000 /* Re-use WAKE# for OBFF */ > +#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ > +#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */ > +#define PCI_EXP_IDO_REQ_EN 0x100 /* ID-based ordering request enable */ > +#define PCI_EXP_IDO_CMP_EN 0x200 /* ID-based ordering completion enable */ > +#define PCI_EXP_LTR_EN 0x400 /* Latency tolerance reporting */ > +#define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message type A */ > +#define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message type B */ > +#define PCI_EXP_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ > +#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ > +#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ > + > +/* Extended Capabilities (PCI-X 2.0 and Express) */ > +#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff) > +#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf) > +#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc) > + > +#define PCI_EXT_CAP_ID_ERR 1 > +#define PCI_EXT_CAP_ID_VC 2 > +#define PCI_EXT_CAP_ID_DSN 3 > +#define PCI_EXT_CAP_ID_PWR 4 > +#define PCI_EXT_CAP_ID_VNDR 11 > +#define PCI_EXT_CAP_ID_ACS 13 > +#define PCI_EXT_CAP_ID_ARI 14 > +#define PCI_EXT_CAP_ID_ATS 15 > +#define PCI_EXT_CAP_ID_SRIOV 16 > +#define PCI_EXT_CAP_ID_LTR 24 > + > +/* Advanced Error Reporting */ > +#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ > +#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */ > +#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ > +#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */ > +#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */ > +#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */ > +#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */ > +#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */ > +#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */ > +#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */ > +#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */ > +#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */ > +#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */ > + /* Same bits as above */ > +#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */ > + /* Same bits as above */ > +#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */ > +#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */ > +#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */ > +#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */ > +#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */ > +#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */ > +#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ > + /* Same bits as above */ > +#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ > +#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */ > +#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */ > +#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */ > +#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */ > +#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ > +#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */ > +#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */ > +/* Correctable Err Reporting Enable */ > +#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 > +/* Non-fatal Err Reporting Enable */ > +#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 > +/* Fatal Err Reporting Enable */ > +#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 > +#define PCI_ERR_ROOT_STATUS 48 > +#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ > +/* Multi ERR_COR Received */ > +#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 > +/* ERR_FATAL/NONFATAL Recevied */ > +#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 > +/* Multi ERR_FATAL/NONFATAL Recevied */ > +#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 > +#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */ > +#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ > +#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ > +#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */ > + > +/* Virtual Channel */ > +#define PCI_VC_PORT_REG1 4 > +#define PCI_VC_PORT_REG2 8 > +#define PCI_VC_PORT_CTRL 12 > +#define PCI_VC_PORT_STATUS 14 > +#define PCI_VC_RES_CAP 16 > +#define PCI_VC_RES_CTRL 20 > +#define PCI_VC_RES_STATUS 26 > + > +/* Power Budgeting */ > +#define PCI_PWR_DSR 4 /* Data Select Register */ > +#define PCI_PWR_DATA 8 /* Data Register */ > +#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */ > +#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */ > +#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */ > +#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */ > +#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */ > +#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */ > +#define PCI_PWR_CAP 12 /* Capability */ > +#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ > + > +/* > + * Hypertransport sub capability types > + * > + * Unfortunately there are both 3 bit and 5 bit capability types defined > + * in the HT spec, catering for that is a little messy. You probably don't > + * want to use these directly, just use pci_find_ht_capability() and it > + * will do the right thing for you. > + */ > +#define HT_3BIT_CAP_MASK 0xE0 > +#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ > +#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ > + > +#define HT_5BIT_CAP_MASK 0xF8 > +#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ > +#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ > +#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ > +#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */ > +#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */ > +#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */ > +#define HT_MSI_FLAGS 0x02 /* Offset to flags */ > +#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */ > +#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */ > +#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */ > +#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */ > +#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */ > +#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */ > +#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */ > +#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */ > +#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */ > +#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */ > +#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */ > + > +/* Alternative Routing-ID Interpretation */ > +#define PCI_ARI_CAP 0x04 /* ARI Capability Register */ > +#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */ > +#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */ > +#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */ > +#define PCI_ARI_CTRL 0x06 /* ARI Control Register */ > +#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */ > +#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ > +#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ > + > +/* Address Translation Service */ > +#define PCI_ATS_CAP 0x04 /* ATS Capability Register */ > +#define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f) /* Invalidate Queue Depth */ > +#define PCI_ATS_MAX_QDEP 32 /* Max Invalidate Queue Depth */ > +#define PCI_ATS_CTRL 0x06 /* ATS Control Register */ > +#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */ > +#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */ > +#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */ > + > +/* Single Root I/O Virtualization */ > +#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ > +#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ > +#define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */ > +#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */ > +#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */ > +#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */ > +#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */ > +#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */ > +#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */ > +#define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */ > +#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */ > +#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */ > +#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */ > +#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */ > +#define PCI_SRIOV_FUNC_LINK 0x12 /* Function Dependency Link */ > +#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */ > +#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */ > +#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */ > +#define PCI_SRIOV_SUP_PGSIZE 0x1c /* Supported Page Sizes */ > +#define PCI_SRIOV_SYS_PGSIZE 0x20 /* System Page Size */ > +#define PCI_SRIOV_BAR 0x24 /* VF BAR0 */ > +#define PCI_SRIOV_NUM_BARS 6 /* Number of VF BARs */ > +#define PCI_SRIOV_VFM 0x3c /* VF Migration State Array Offset*/ > +#define PCI_SRIOV_VFM_BIR(x) ((x) & 7) /* State BIR */ > +#define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7) /* State Offset */ > +#define PCI_SRIOV_VFM_UA 0x0 /* Inactive.Unavailable */ > +#define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */ > +#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ > +#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ > + > +#define PCI_LTR_MAX_SNOOP_LAT 0x4 > +#define PCI_LTR_MAX_NOSNOOP_LAT 0x6 > +#define PCI_LTR_VALUE_MASK 0x000003ff > +#define PCI_LTR_SCALE_MASK 0x00001c00 > +#define PCI_LTR_SCALE_SHIFT 10 > + > +/* Access Control Service */ > +#define PCI_ACS_CAP 0x04 /* ACS Capability Register */ > +#define PCI_ACS_SV 0x01 /* Source Validation */ > +#define PCI_ACS_TB 0x02 /* Translation Blocking */ > +#define PCI_ACS_RR 0x04 /* P2P Request Redirect */ > +#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */ > +#define PCI_ACS_UF 0x10 /* Upstream Forwarding */ > +#define PCI_ACS_EC 0x20 /* P2P Egress Control */ > +#define PCI_ACS_DT 0x40 /* Direct Translated P2P */ > +#define PCI_ACS_CTRL 0x06 /* ACS Control Register */ > +#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ > + > +#endif /* LINUX_PCI_REGS_H */ > diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c > new file mode 100644 > index 0000000..7c92f19 > --- /dev/null > +++ b/hw/pci/pcie.c > @@ -0,0 +1,555 @@ > +/* > + * pcie.c > + * > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "qemu-common.h" > +#include "pci_bridge.h" > +#include "pcie.h" > +#include "msix.h" > +#include "msi.h" > +#include "pci_internals.h" > +#include "pcie_regs.h" > +#include "range.h" > + > +//#define DEBUG_PCIE > +#ifdef DEBUG_PCIE > +# define PCIE_DPRINTF(fmt, ...) \ > + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > +#else > +# define PCIE_DPRINTF(fmt, ...) do {} while (0) > +#endif > +#define PCIE_DEV_PRINTF(dev, fmt, ...) \ > + PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > + > + > +/*************************************************************************** > + * pci express capability helper functions > + */ > +int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) > +{ > + int pos; > + uint8_t *exp_cap; > + > + assert(pci_is_express(dev)); > + > + pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, > + PCI_EXP_VER2_SIZEOF); > + if (pos < 0) { > + return pos; > + } > + dev->exp.exp_cap = pos; > + exp_cap = dev->config + pos; > + > + /* capability register > + interrupt message number defaults to 0 */ > + pci_set_word(exp_cap + PCI_EXP_FLAGS, > + ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) | > + PCI_EXP_FLAGS_VER2); > + > + /* device capability register > + * table 7-12: > + * roll based error reporting bit must be set by all > + * Functions conforming to the ECN, PCI Express Base > + * Specification, Revision 1.1., or subsequent PCI Express Base > + * Specification revisions. > + */ > + pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER); > + > + pci_set_long(exp_cap + PCI_EXP_LNKCAP, > + (port << PCI_EXP_LNKCAP_PN_SHIFT) | > + PCI_EXP_LNKCAP_ASPMS_0S | > + PCI_EXP_LNK_MLW_1 | > + PCI_EXP_LNK_LS_25); > + > + pci_set_word(exp_cap + PCI_EXP_LNKSTA, > + PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25); > + > + pci_set_long(exp_cap + PCI_EXP_DEVCAP2, > + PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP); > + > + pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB); > + return pos; > +} > + > +void pcie_cap_exit(PCIDevice *dev) > +{ > + pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF); > +} > + > +uint8_t pcie_cap_get_type(const PCIDevice *dev) > +{ > + uint32_t pos = dev->exp.exp_cap; > + assert(pos > 0); > + return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) & > + PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT; > +} > + > +/* MSI/MSI-X */ > +/* pci express interrupt message number */ > +/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */ > +void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector) > +{ > + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > + assert(vector < 32); > + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ); > + pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS, > + vector << PCI_EXP_FLAGS_IRQ_SHIFT); > +} > + > +uint8_t pcie_cap_flags_get_vector(PCIDevice *dev) > +{ > + return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) & > + PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT; > +} > + > +void pcie_cap_deverr_init(PCIDevice *dev) > +{ > + uint32_t pos = dev->exp.exp_cap; > + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP, > + PCI_EXP_DEVCAP_RBER); > + pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL, > + PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | > + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); > + pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA, > + PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED | > + PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD); > +} > + > +void pcie_cap_deverr_reset(PCIDevice *dev) > +{ > + uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; > + pci_long_test_and_clear_mask(devctl, > + PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | > + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); > +} > + > +static void hotplug_event_update_event_status(PCIDevice *dev) > +{ > + uint32_t pos = dev->exp.exp_cap; > + uint8_t *exp_cap = dev->config + pos; > + uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL); > + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > + > + dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) && > + (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED); > +} > + > +static void hotplug_event_notify(PCIDevice *dev) > +{ > + bool prev = dev->exp.hpev_notified; > + > + hotplug_event_update_event_status(dev); > + > + if (prev == dev->exp.hpev_notified) { > + return; > + } > + > + /* Note: the logic above does not take into account whether interrupts > + * are masked. The result is that interrupt will be sent when it is > + * subsequently unmasked. This appears to be legal: Section 6.7.3.4: > + * The Port may optionally send an MSI when there are hot-plug events that > + * occur while interrupt generation is disabled, and interrupt generation is > + * subsequently enabled. */ > + if (msix_enabled(dev)) { > + msix_notify(dev, pcie_cap_flags_get_vector(dev)); > + } else if (msi_enabled(dev)) { > + msi_notify(dev, pcie_cap_flags_get_vector(dev)); > + } else { > + qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified); > + } > +} > + > +static void hotplug_event_clear(PCIDevice *dev) > +{ > + hotplug_event_update_event_status(dev); > + if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) { > + qemu_set_irq(dev->irq[dev->exp.hpev_intx], 0); > + } > +} > + > +/* > + * A PCI Express Hot-Plug Event has occurred, so update slot status register > + * and notify OS of the event if necessary. > + * > + * 6.7.3 PCI Express Hot-Plug Events > + * 6.7.3.4 Software Notification of Hot-Plug Events > + */ > +static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) > +{ > + /* Minor optimization: if nothing changed - no event is needed. */ > + if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap + > + PCI_EXP_SLTSTA, event)) { > + return; > + } > + hotplug_event_notify(dev); > +} > + > +static int pcie_cap_slot_hotplug(DeviceState *qdev, > + PCIDevice *pci_dev, PCIHotplugState state) > +{ > + PCIDevice *d = PCI_DEVICE(qdev); > + uint8_t *exp_cap = d->config + d->exp.exp_cap; > + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > + > + /* Don't send event when device is enabled during qemu machine creation: > + * it is present on boot, no hotplug event is necessary. We do send an > + * event when the device is disabled later. */ > + if (state == PCI_COLDPLUG_ENABLED) { > + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, > + PCI_EXP_SLTSTA_PDS); > + return 0; > + } > + > + PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state); > + if (sltsta & PCI_EXP_SLTSTA_EIS) { > + /* the slot is electromechanically locked. > + * This error is propagated up to qdev and then to HMP/QMP. > + */ > + return -EBUSY; > + } > + > + /* TODO: multifunction hot-plug. > + * Right now, only a device of function = 0 is allowed to be > + * hot plugged/unplugged. > + */ > + assert(PCI_FUNC(pci_dev->devfn) == 0); > + > + if (state == PCI_HOTPLUG_ENABLED) { > + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, > + PCI_EXP_SLTSTA_PDS); > + pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); > + } else { > + qdev_free(&pci_dev->qdev); > + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, > + PCI_EXP_SLTSTA_PDS); > + pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); > + } > + return 0; > +} > + > +/* pci express slot for pci express root/downstream port > + PCI express capability slot registers */ > +void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot) > +{ > + uint32_t pos = dev->exp.exp_cap; > + > + pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS, > + PCI_EXP_FLAGS_SLOT); > + > + pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP, > + ~PCI_EXP_SLTCAP_PSN); > + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP, > + (slot << PCI_EXP_SLTCAP_PSN_SHIFT) | > + PCI_EXP_SLTCAP_EIP | > + PCI_EXP_SLTCAP_HPS | > + PCI_EXP_SLTCAP_HPC | > + PCI_EXP_SLTCAP_PIP | > + PCI_EXP_SLTCAP_AIP | > + PCI_EXP_SLTCAP_ABP); > + > + pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL, > + PCI_EXP_SLTCTL_PIC | > + PCI_EXP_SLTCTL_AIC); > + pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL, > + PCI_EXP_SLTCTL_PIC_OFF | > + PCI_EXP_SLTCTL_AIC_OFF); > + pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, > + PCI_EXP_SLTCTL_PIC | > + PCI_EXP_SLTCTL_AIC | > + PCI_EXP_SLTCTL_HPIE | > + PCI_EXP_SLTCTL_CCIE | > + PCI_EXP_SLTCTL_PDCE | > + PCI_EXP_SLTCTL_ABPE); > + /* Although reading PCI_EXP_SLTCTL_EIC returns always 0, > + * make the bit writable here in order to detect 1b is written. > + * pcie_cap_slot_write_config() test-and-clear the bit, so > + * this bit always returns 0 to the guest. > + */ > + pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, > + PCI_EXP_SLTCTL_EIC); > + > + pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA, > + PCI_EXP_HP_EV_SUPPORTED); > + > + dev->exp.hpev_notified = false; > + > + pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)), > + pcie_cap_slot_hotplug, &dev->qdev); > +} > + > +void pcie_cap_slot_reset(PCIDevice *dev) > +{ > + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > + > + PCIE_DEV_PRINTF(dev, "reset\n"); > + > + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, > + PCI_EXP_SLTCTL_EIC | > + PCI_EXP_SLTCTL_PIC | > + PCI_EXP_SLTCTL_AIC | > + PCI_EXP_SLTCTL_HPIE | > + PCI_EXP_SLTCTL_CCIE | > + PCI_EXP_SLTCTL_PDCE | > + PCI_EXP_SLTCTL_ABPE); > + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL, > + PCI_EXP_SLTCTL_PIC_OFF | > + PCI_EXP_SLTCTL_AIC_OFF); > + > + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, > + PCI_EXP_SLTSTA_EIS |/* on reset, > + the lock is released */ > + PCI_EXP_SLTSTA_CC | > + PCI_EXP_SLTSTA_PDC | > + PCI_EXP_SLTSTA_ABP); > + > + hotplug_event_update_event_status(dev); > +} > + > +void pcie_cap_slot_write_config(PCIDevice *dev, > + uint32_t addr, uint32_t val, int len) > +{ > + uint32_t pos = dev->exp.exp_cap; > + uint8_t *exp_cap = dev->config + pos; > + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > + > + if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) { > + hotplug_event_clear(dev); > + } > + > + if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) { > + return; > + } > + > + if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, > + PCI_EXP_SLTCTL_EIC)) { > + sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */ > + pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta); > + PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: " > + "sltsta -> 0x%02"PRIx16"\n", > + sltsta); > + } > + > + hotplug_event_notify(dev); > + > + /* > + * 6.7.3.2 Command Completed Events > + * > + * Software issues a command to a hot-plug capable Downstream Port by > + * issuing a write transaction that targets any portion of the Port’s Slot > + * Control register. A single write to the Slot Control register is > + * considered to be a single command, even if the write affects more than > + * one field in the Slot Control register. In response to this transaction, > + * the Port must carry out the requested actions and then set the > + * associated status field for the command completed event. */ > + > + /* Real hardware might take a while to complete requested command because > + * physical movement would be involved like locking the electromechanical > + * lock. However in our case, command is completed instantaneously above, > + * so send a command completion event right now. > + */ > + pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI); > +} > + > +int pcie_cap_slot_post_load(void *opaque, int version_id) > +{ > + PCIDevice *dev = opaque; > + hotplug_event_update_event_status(dev); > + return 0; > +} > + > +void pcie_cap_slot_push_attention_button(PCIDevice *dev) > +{ > + pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP); > +} > + > +/* root control/capabilities/status. PME isn't emulated for now */ > +void pcie_cap_root_init(PCIDevice *dev) > +{ > + pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL, > + PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | > + PCI_EXP_RTCTL_SEFEE); > +} > + > +void pcie_cap_root_reset(PCIDevice *dev) > +{ > + pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0); > +} > + > +/* function level reset(FLR) */ > +void pcie_cap_flr_init(PCIDevice *dev) > +{ > + pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP, > + PCI_EXP_DEVCAP_FLR); > + > + /* Although reading BCR_FLR returns always 0, > + * the bit is made writable here in order to detect the 1b is written > + * pcie_cap_flr_write_config() test-and-clear the bit, so > + * this bit always returns 0 to the guest. > + */ > + pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL, > + PCI_EXP_DEVCTL_BCR_FLR); > +} > + > +void pcie_cap_flr_write_config(PCIDevice *dev, > + uint32_t addr, uint32_t val, int len) > +{ > + uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; > + if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) { > + /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler > + so the handler can detect FLR by looking at this bit. */ > + pci_device_reset(dev); > + pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR); > + } > +} > + > +/* Alternative Routing-ID Interpretation (ARI) */ > +/* ari forwarding support for down stream port */ > +void pcie_cap_ari_init(PCIDevice *dev) > +{ > + uint32_t pos = dev->exp.exp_cap; > + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2, > + PCI_EXP_DEVCAP2_ARI); > + pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2, > + PCI_EXP_DEVCTL2_ARI); > +} > + > +void pcie_cap_ari_reset(PCIDevice *dev) > +{ > + uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2; > + pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI); > +} > + > +bool pcie_cap_is_ari_enabled(const PCIDevice *dev) > +{ > + if (!pci_is_express(dev)) { > + return false; > + } > + if (!dev->exp.exp_cap) { > + return false; > + } > + > + return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & > + PCI_EXP_DEVCTL2_ARI; > +} > + > +/************************************************************************** > + * pci express extended capability allocation functions > + * uint16_t ext_cap_id (16 bit) > + * uint8_t cap_ver (4 bit) > + * uint16_t cap_offset (12 bit) > + * uint16_t ext_cap_size > + */ > + > +static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id, > + uint16_t *prev_p) > +{ > + uint16_t prev = 0; > + uint16_t next; > + uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE); > + > + if (!header) { > + /* no extended capability */ > + next = 0; > + goto out; > + } > + for (next = PCI_CONFIG_SPACE_SIZE; next; > + prev = next, next = PCI_EXT_CAP_NEXT(header)) { > + > + assert(next >= PCI_CONFIG_SPACE_SIZE); > + assert(next <= PCIE_CONFIG_SPACE_SIZE - 8); > + > + header = pci_get_long(dev->config + next); > + if (PCI_EXT_CAP_ID(header) == cap_id) { > + break; > + } > + } > + > +out: > + if (prev_p) { > + *prev_p = prev; > + } > + return next; > +} > + > +uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id) > +{ > + return pcie_find_capability_list(dev, cap_id, NULL); > +} > + > +static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next) > +{ > + uint16_t header = pci_get_long(dev->config + pos); > + assert(!(next & (PCI_EXT_CAP_ALIGN - 1))); > + header = (header & ~PCI_EXT_CAP_NEXT_MASK) | > + ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK); > + pci_set_long(dev->config + pos, header); > +} > + > +/* > + * caller must supply valid (offset, size) * such that the range shouldn't > + * overlap with other capability or other registers. > + * This function doesn't check it. > + */ > +void pcie_add_capability(PCIDevice *dev, > + uint16_t cap_id, uint8_t cap_ver, > + uint16_t offset, uint16_t size) > +{ > + uint32_t header; > + uint16_t next; > + > + assert(offset >= PCI_CONFIG_SPACE_SIZE); > + assert(offset < offset + size); > + assert(offset + size < PCIE_CONFIG_SPACE_SIZE); > + assert(size >= 8); > + assert(pci_is_express(dev)); > + > + if (offset == PCI_CONFIG_SPACE_SIZE) { > + header = pci_get_long(dev->config + offset); > + next = PCI_EXT_CAP_NEXT(header); > + } else { > + uint16_t prev; > + > + /* 0 is reserved cap id. use internally to find the last capability > + in the linked list */ > + next = pcie_find_capability_list(dev, 0, &prev); > + > + assert(prev >= PCI_CONFIG_SPACE_SIZE); > + assert(next == 0); > + pcie_ext_cap_set_next(dev, prev, offset); > + } > + pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next)); > + > + /* Make capability read-only by default */ > + memset(dev->wmask + offset, 0, size); > + memset(dev->w1cmask + offset, 0, size); > + /* Check capability by default */ > + memset(dev->cmask + offset, 0xFF, size); > +} > + > +/************************************************************************** > + * pci express extended capability helper functions > + */ > + > +/* ARI */ > +void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn) > +{ > + pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER, > + offset, PCI_ARI_SIZEOF); > + pci_set_long(dev->config + offset + PCI_ARI_CAP, PCI_ARI_CAP_NFN(nextfn)); > +} > diff --git a/hw/pci/pcie.h b/hw/pci/pcie.h > new file mode 100644 > index 0000000..4889194 > --- /dev/null > +++ b/hw/pci/pcie.h > @@ -0,0 +1,142 @@ > +/* > + * pcie.h > + * > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef QEMU_PCIE_H > +#define QEMU_PCIE_H > + > +#include "hw.h" > +#include "pci_regs.h" > +#include "pcie_regs.h" > +#include "pcie_aer.h" > + > +typedef enum { > + /* for attention and power indicator */ > + PCI_EXP_HP_IND_RESERVED = PCI_EXP_SLTCTL_IND_RESERVED, > + PCI_EXP_HP_IND_ON = PCI_EXP_SLTCTL_IND_ON, > + PCI_EXP_HP_IND_BLINK = PCI_EXP_SLTCTL_IND_BLINK, > + PCI_EXP_HP_IND_OFF = PCI_EXP_SLTCTL_IND_OFF, > +} PCIExpressIndicator; > + > +typedef enum { > + /* these bits must match the bits in Slot Control/Status registers. > + * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx > + * > + * Not all the bits of slot control register match with the ones of > + * slot status. Not some bits of slot status register is used to > + * show status, not to report event occurrence. > + * So such bits must be masked out when checking the software > + * notification condition. > + */ > + PCI_EXP_HP_EV_ABP = PCI_EXP_SLTCTL_ABPE, > + /* attention button pressed */ > + PCI_EXP_HP_EV_PDC = PCI_EXP_SLTCTL_PDCE, > + /* presence detect changed */ > + PCI_EXP_HP_EV_CCI = PCI_EXP_SLTCTL_CCIE, > + /* command completed */ > + > + PCI_EXP_HP_EV_SUPPORTED = PCI_EXP_HP_EV_ABP | > + PCI_EXP_HP_EV_PDC | > + PCI_EXP_HP_EV_CCI, > + /* supported event mask */ > + > + /* events not listed aren't supported */ > +} PCIExpressHotPlugEvent; > + > +struct PCIExpressDevice { > + /* Offset of express capability in config space */ > + uint8_t exp_cap; > + > + /* SLOT */ > + unsigned int hpev_intx; /* INTx for hot plug event (0-3:INT[A-D]#) > + * default is 0 = INTA# > + * If the chip wants to use other interrupt > + * line, initialize this member with the > + * desired number. > + * If the chip dynamically changes this member, > + * also initialize it when loaded as > + * appropreately. > + */ > + bool hpev_notified; /* Logical AND of conditions for hot plug event. > + Following 6.7.3.4: > + Software Notification of Hot-Plug Events, an interrupt > + is sent whenever the logical and of these conditions > + transitions from false to true. */ > + > + /* AER */ > + uint16_t aer_cap; > + PCIEAERLog aer_log; > + unsigned int aer_intx; /* INTx for error reporting > + * default is 0 = INTA# > + * If the chip wants to use other interrupt > + * line, initialize this member with the > + * desired number. > + * If the chip dynamically changes this member, > + * also initialize it when loaded as > + * appropreately. > + */ > +}; > + > +/* PCI express capability helper functions */ > +int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port); > +void pcie_cap_exit(PCIDevice *dev); > +uint8_t pcie_cap_get_type(const PCIDevice *dev); > +void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector); > +uint8_t pcie_cap_flags_get_vector(PCIDevice *dev); > + > +void pcie_cap_deverr_init(PCIDevice *dev); > +void pcie_cap_deverr_reset(PCIDevice *dev); > + > +void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot); > +void pcie_cap_slot_reset(PCIDevice *dev); > +void pcie_cap_slot_write_config(PCIDevice *dev, > + uint32_t addr, uint32_t val, int len); > +int pcie_cap_slot_post_load(void *opaque, int version_id); > +void pcie_cap_slot_push_attention_button(PCIDevice *dev); > + > +void pcie_cap_root_init(PCIDevice *dev); > +void pcie_cap_root_reset(PCIDevice *dev); > + > +void pcie_cap_flr_init(PCIDevice *dev); > +void pcie_cap_flr_write_config(PCIDevice *dev, > + uint32_t addr, uint32_t val, int len); > + > +void pcie_cap_ari_init(PCIDevice *dev); > +void pcie_cap_ari_reset(PCIDevice *dev); > +bool pcie_cap_is_ari_enabled(const PCIDevice *dev); > + > +/* PCI express extended capability helper functions */ > +uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id); > +void pcie_add_capability(PCIDevice *dev, > + uint16_t cap_id, uint8_t cap_ver, > + uint16_t offset, uint16_t size); > + > +void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn); > + > +extern const VMStateDescription vmstate_pcie_device; > + > +#define VMSTATE_PCIE_DEVICE(_field, _state) { \ > + .name = (stringify(_field)), \ > + .size = sizeof(PCIDevice), \ > + .vmsd = &vmstate_pcie_device, \ > + .flags = VMS_STRUCT, \ > + .offset = vmstate_offset_value(_state, _field, PCIDevice), \ > +} > + > +#endif /* QEMU_PCIE_H */ > diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c > new file mode 100644 > index 0000000..b04c164 > --- /dev/null > +++ b/hw/pci/pcie_aer.c > @@ -0,0 +1,1032 @@ > +/* > + * pcie_aer.c > + * > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "sysemu.h" > +#include "qemu-objects.h" > +#include "monitor.h" > +#include "pci_bridge.h" > +#include "pcie.h" > +#include "msix.h" > +#include "msi.h" > +#include "pci_internals.h" > +#include "pcie_regs.h" > + > +//#define DEBUG_PCIE > +#ifdef DEBUG_PCIE > +# define PCIE_DPRINTF(fmt, ...) \ > + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > +#else > +# define PCIE_DPRINTF(fmt, ...) do {} while (0) > +#endif > +#define PCIE_DEV_PRINTF(dev, fmt, ...) \ > + PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > + > +#define PCI_ERR_SRC_COR_OFFS 0 > +#define PCI_ERR_SRC_UNCOR_OFFS 2 > + > +/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */ > +static uint32_t pcie_aer_uncor_default_severity(uint32_t status) > +{ > + switch (status) { > + case PCI_ERR_UNC_INTN: > + case PCI_ERR_UNC_DLP: > + case PCI_ERR_UNC_SDN: > + case PCI_ERR_UNC_RX_OVER: > + case PCI_ERR_UNC_FCP: > + case PCI_ERR_UNC_MALF_TLP: > + return PCI_ERR_ROOT_CMD_FATAL_EN; > + case PCI_ERR_UNC_POISON_TLP: > + case PCI_ERR_UNC_ECRC: > + case PCI_ERR_UNC_UNSUP: > + case PCI_ERR_UNC_COMP_TIME: > + case PCI_ERR_UNC_COMP_ABORT: > + case PCI_ERR_UNC_UNX_COMP: > + case PCI_ERR_UNC_ACSV: > + case PCI_ERR_UNC_MCBTLP: > + case PCI_ERR_UNC_ATOP_EBLOCKED: > + case PCI_ERR_UNC_TLP_PRF_BLOCKED: > + return PCI_ERR_ROOT_CMD_NONFATAL_EN; > + default: > + abort(); > + break; > + } > + return PCI_ERR_ROOT_CMD_FATAL_EN; > +} > + > +static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err) > +{ > + if (aer_log->log_num == aer_log->log_max) { > + return -1; > + } > + memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err); > + aer_log->log_num++; > + return 0; > +} > + > +static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err) > +{ > + assert(aer_log->log_num); > + *err = aer_log->log[0]; > + aer_log->log_num--; > + memmove(&aer_log->log[0], &aer_log->log[1], > + aer_log->log_num * sizeof *err); > +} > + > +static void aer_log_clear_all_err(PCIEAERLog *aer_log) > +{ > + aer_log->log_num = 0; > +} > + > +int pcie_aer_init(PCIDevice *dev, uint16_t offset) > +{ > + PCIExpressDevice *exp; > + > + pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER, > + offset, PCI_ERR_SIZEOF); > + exp = &dev->exp; > + exp->aer_cap = offset; > + > + /* log_max is property */ > + if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) { > + dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT; > + } > + /* clip down the value to avoid unreasobale memory usage */ > + if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) { > + return -EINVAL; > + } > + dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] * > + dev->exp.aer_log.log_max); > + > + pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS, > + PCI_ERR_UNC_SUPPORTED); > + > + pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER, > + PCI_ERR_UNC_SEVERITY_DEFAULT); > + pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER, > + PCI_ERR_UNC_SUPPORTED); > + > + pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS, > + PCI_ERR_COR_STATUS); > + > + pci_set_long(dev->config + offset + PCI_ERR_COR_MASK, > + PCI_ERR_COR_MASK_DEFAULT); > + pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK, > + PCI_ERR_COR_SUPPORTED); > + > + /* capabilities and control. multiple header logging is supported */ > + if (dev->exp.aer_log.log_max > 0) { > + pci_set_long(dev->config + offset + PCI_ERR_CAP, > + PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC | > + PCI_ERR_CAP_MHRC); > + pci_set_long(dev->wmask + offset + PCI_ERR_CAP, > + PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE | > + PCI_ERR_CAP_MHRE); > + } else { > + pci_set_long(dev->config + offset + PCI_ERR_CAP, > + PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC); > + pci_set_long(dev->wmask + offset + PCI_ERR_CAP, > + PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); > + } > + > + switch (pcie_cap_get_type(dev)) { > + case PCI_EXP_TYPE_ROOT_PORT: > + /* this case will be set by pcie_aer_root_init() */ > + /* fallthrough */ > + case PCI_EXP_TYPE_DOWNSTREAM: > + case PCI_EXP_TYPE_UPSTREAM: > + pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL, > + PCI_BRIDGE_CTL_SERR); > + pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS, > + PCI_SEC_STATUS_RCV_SYSTEM_ERROR); > + break; > + default: > + /* nothing */ > + break; > + } > + return 0; > +} > + > +void pcie_aer_exit(PCIDevice *dev) > +{ > + g_free(dev->exp.aer_log.log); > +} > + > +static void pcie_aer_update_uncor_status(PCIDevice *dev) > +{ > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > + PCIEAERLog *aer_log = &dev->exp.aer_log; > + > + uint16_t i; > + for (i = 0; i < aer_log->log_num; i++) { > + pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS, > + dev->exp.aer_log.log[i].status); > + } > +} > + > +/* > + * return value: > + * true: error message needs to be sent up > + * false: error message is masked > + * > + * 6.2.6 Error Message Control > + * Figure 6-3 > + * all pci express devices part > + */ > +static bool > +pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg) > +{ > + if (!(pcie_aer_msg_is_uncor(msg) && > + (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) { > + return false; > + } > + > + /* Signaled System Error > + * > + * 7.5.1.1 Command register > + * Bit 8 SERR# Enable > + * > + * When Set, this bit enables reporting of Non-fatal and Fatal > + * errors detected by the Function to the Root Complex. Note that > + * errors are reported if enabled either through this bit or through > + * the PCI Express specific bits in the Device Control register (see > + * Section 7.8.4). > + */ > + pci_word_test_and_set_mask(dev->config + PCI_STATUS, > + PCI_STATUS_SIG_SYSTEM_ERROR); > + > + if (!(msg->severity & > + pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) { > + return false; > + } > + > + /* send up error message */ > + return true; > +} > + > +/* > + * return value: > + * true: error message is sent up > + * false: error message is masked > + * > + * 6.2.6 Error Message Control > + * Figure 6-3 > + * virtual pci bridge part > + */ > +static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg) > +{ > + uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL); > + > + if (pcie_aer_msg_is_uncor(msg)) { > + /* Received System Error */ > + pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS, > + PCI_SEC_STATUS_RCV_SYSTEM_ERROR); > + } > + > + if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) { > + return false; > + } > + return true; > +} > + > +void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector) > +{ > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > + assert(vector < PCI_ERR_ROOT_IRQ_MAX); > + pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS, > + PCI_ERR_ROOT_IRQ); > + pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS, > + vector << PCI_ERR_ROOT_IRQ_SHIFT); > +} > + > +static unsigned int pcie_aer_root_get_vector(PCIDevice *dev) > +{ > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > + uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > + return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT; > +} > + > +/* Given a status register, get corresponding bits in the command register */ > +static uint32_t pcie_aer_status_to_cmd(uint32_t status) > +{ > + uint32_t cmd = 0; > + if (status & PCI_ERR_ROOT_COR_RCV) { > + cmd |= PCI_ERR_ROOT_CMD_COR_EN; > + } > + if (status & PCI_ERR_ROOT_NONFATAL_RCV) { > + cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN; > + } > + if (status & PCI_ERR_ROOT_FATAL_RCV) { > + cmd |= PCI_ERR_ROOT_CMD_FATAL_EN; > + } > + return cmd; > +} > + > +static void pcie_aer_root_notify(PCIDevice *dev) > +{ > + if (msix_enabled(dev)) { > + msix_notify(dev, pcie_aer_root_get_vector(dev)); > + } else if (msi_enabled(dev)) { > + msi_notify(dev, pcie_aer_root_get_vector(dev)); > + } else { > + qemu_set_irq(dev->irq[dev->exp.aer_intx], 1); > + } > +} > + > +/* > + * 6.2.6 Error Message Control > + * Figure 6-3 > + * root port part > + */ > +static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg) > +{ > + uint16_t cmd; > + uint8_t *aer_cap; > + uint32_t root_cmd; > + uint32_t root_status, prev_status; > + > + cmd = pci_get_word(dev->config + PCI_COMMAND); > + aer_cap = dev->config + dev->exp.aer_cap; > + root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); > + prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > + > + if (cmd & PCI_COMMAND_SERR) { > + /* System Error. > + * > + * The way to report System Error is platform specific and > + * it isn't implemented in qemu right now. > + * So just discard the error for now. > + * OS which cares of aer would receive errors via > + * native aer mechanims, so this wouldn't matter. > + */ > + } > + > + /* Errro Message Received: Root Error Status register */ > + switch (msg->severity) { > + case PCI_ERR_ROOT_CMD_COR_EN: > + if (root_status & PCI_ERR_ROOT_COR_RCV) { > + root_status |= PCI_ERR_ROOT_MULTI_COR_RCV; > + } else { > + pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SRC_COR_OFFS, > + msg->source_id); > + } > + root_status |= PCI_ERR_ROOT_COR_RCV; > + break; > + case PCI_ERR_ROOT_CMD_NONFATAL_EN: > + root_status |= PCI_ERR_ROOT_NONFATAL_RCV; > + break; > + case PCI_ERR_ROOT_CMD_FATAL_EN: > + if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) { > + root_status |= PCI_ERR_ROOT_FIRST_FATAL; > + } > + root_status |= PCI_ERR_ROOT_FATAL_RCV; > + break; > + default: > + abort(); > + break; > + } > + if (pcie_aer_msg_is_uncor(msg)) { > + if (root_status & PCI_ERR_ROOT_UNCOR_RCV) { > + root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV; > + } else { > + pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + > + PCI_ERR_SRC_UNCOR_OFFS, msg->source_id); > + } > + root_status |= PCI_ERR_ROOT_UNCOR_RCV; > + } > + pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status); > + > + /* 6.2.4.1.2 Interrupt Generation */ > + /* All the above did was set some bits in the status register. > + * Specifically these that match message severity. > + * The below code relies on this fact. */ > + if (!(root_cmd & msg->severity) || > + (pcie_aer_status_to_cmd(prev_status) & root_cmd)) { > + /* Condition is not being set or was already true so nothing to do. */ > + return; > + } > + > + pcie_aer_root_notify(dev); > +} > + > +/* > + * 6.2.6 Error Message Control Figure 6-3 > + * > + * Walk up the bus tree from the device, propagate the error message. > + */ > +static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) > +{ > + uint8_t type; > + > + while (dev) { > + if (!pci_is_express(dev)) { > + /* just ignore it */ > + /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR? > + * Consider e.g. a PCI bridge above a PCI Express device. */ > + return; > + } > + > + type = pcie_cap_get_type(dev); > + if ((type == PCI_EXP_TYPE_ROOT_PORT || > + type == PCI_EXP_TYPE_UPSTREAM || > + type == PCI_EXP_TYPE_DOWNSTREAM) && > + !pcie_aer_msg_vbridge(dev, msg)) { > + return; > + } > + if (!pcie_aer_msg_alldev(dev, msg)) { > + return; > + } > + if (type == PCI_EXP_TYPE_ROOT_PORT) { > + pcie_aer_msg_root_port(dev, msg); > + /* Root port can notify system itself, > + or send the error message to root complex event collector. */ > + /* > + * if root port is associated with an event collector, > + * return the root complex event collector here. > + * For now root complex event collector isn't supported. > + */ > + return; > + } > + dev = pci_bridge_get_device(dev->bus); > + } > +} > + > +static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err) > +{ > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > + uint8_t first_bit = ffs(err->status) - 1; > + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > + int i; > + > + assert(err->status); > + assert(!(err->status & (err->status - 1))); > + > + errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); > + errcap |= PCI_ERR_CAP_FEP(first_bit); > + > + if (err->flags & PCIE_AER_ERR_HEADER_VALID) { > + for (i = 0; i < ARRAY_SIZE(err->header); ++i) { > + /* 7.10.8 Header Log Register */ > + uint8_t *header_log = > + aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0]; > + cpu_to_be32wu((uint32_t*)header_log, err->header[i]); > + } > + } else { > + assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT)); > + memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); > + } > + > + if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) && > + (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & > + PCI_EXP_DEVCAP2_EETLPP)) { > + for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) { > + /* 7.10.12 tlp prefix log register */ > + uint8_t *prefix_log = > + aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0]; > + cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]); > + } > + errcap |= PCI_ERR_CAP_TLP; > + } else { > + memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, > + PCI_ERR_TLP_PREFIX_LOG_SIZE); > + } > + pci_set_long(aer_cap + PCI_ERR_CAP, errcap); > +} > + > +static void pcie_aer_clear_log(PCIDevice *dev) > +{ > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > + > + pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP, > + PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); > + > + memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); > + memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE); > +} > + > +static void pcie_aer_clear_error(PCIDevice *dev) > +{ > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > + PCIEAERLog *aer_log = &dev->exp.aer_log; > + PCIEAERErr err; > + > + if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) { > + pcie_aer_clear_log(dev); > + return; > + } > + > + /* > + * If more errors are queued, set corresponding bits in uncorrectable > + * error status. > + * We emulate uncorrectable error status register as W1CS. > + * So set bit in uncorrectable error status here again for multiple > + * error recording support. > + * > + * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability) > + */ > + pcie_aer_update_uncor_status(dev); > + > + aer_log_del_err(aer_log, &err); > + pcie_aer_update_log(dev, &err); > +} > + > +static int pcie_aer_record_error(PCIDevice *dev, > + const PCIEAERErr *err) > +{ > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > + int fep = PCI_ERR_CAP_FEP(errcap); > + > + assert(err->status); > + assert(!(err->status & (err->status - 1))); > + > + if (errcap & PCI_ERR_CAP_MHRE && > + (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) { > + /* Not first error. queue error */ > + if (aer_log_add_err(&dev->exp.aer_log, err) < 0) { > + /* overflow */ > + return -1; > + } > + return 0; > + } > + > + pcie_aer_update_log(dev, err); > + return 0; > +} > + > +typedef struct PCIEAERInject { > + PCIDevice *dev; > + uint8_t *aer_cap; > + const PCIEAERErr *err; > + uint16_t devctl; > + uint16_t devsta; > + uint32_t error_status; > + bool unsupported_request; > + bool log_overflow; > + PCIEAERMsg msg; > +} PCIEAERInject; > + > +static bool pcie_aer_inject_cor_error(PCIEAERInject *inj, > + uint32_t uncor_status, > + bool is_advisory_nonfatal) > +{ > + PCIDevice *dev = inj->dev; > + > + inj->devsta |= PCI_EXP_DEVSTA_CED; > + if (inj->unsupported_request) { > + inj->devsta |= PCI_EXP_DEVSTA_URD; > + } > + pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); > + > + if (inj->aer_cap) { > + uint32_t mask; > + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS, > + inj->error_status); > + mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK); > + if (mask & inj->error_status) { > + return false; > + } > + if (is_advisory_nonfatal) { > + uint32_t uncor_mask = > + pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); > + if (!(uncor_mask & uncor_status)) { > + inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); > + } > + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > + uncor_status); > + } > + } > + > + if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) { > + return false; > + } > + if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) { > + return false; > + } > + > + inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN; > + return true; > +} > + > +static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal) > +{ > + PCIDevice *dev = inj->dev; > + uint16_t cmd; > + > + if (is_fatal) { > + inj->devsta |= PCI_EXP_DEVSTA_FED; > + } else { > + inj->devsta |= PCI_EXP_DEVSTA_NFED; > + } > + if (inj->unsupported_request) { > + inj->devsta |= PCI_EXP_DEVSTA_URD; > + } > + pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); > + > + if (inj->aer_cap) { > + uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); > + if (mask & inj->error_status) { > + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > + inj->error_status); > + return false; > + } > + > + inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); > + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > + inj->error_status); > + } > + > + cmd = pci_get_word(dev->config + PCI_COMMAND); > + if (inj->unsupported_request && > + !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) { > + return false; > + } > + if (is_fatal) { > + if (!((cmd & PCI_COMMAND_SERR) || > + (inj->devctl & PCI_EXP_DEVCTL_FERE))) { > + return false; > + } > + inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN; > + } else { > + if (!((cmd & PCI_COMMAND_SERR) || > + (inj->devctl & PCI_EXP_DEVCTL_NFERE))) { > + return false; > + } > + inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN; > + } > + return true; > +} > + > +/* > + * non-Function specific error must be recorded in all functions. > + * It is the responsibility of the caller of this function. > + * It is also caller's responsibility to determine which function should > + * report the rerror. > + * > + * 6.2.4 Error Logging > + * 6.2.5 Sqeunce of Device Error Signaling and Logging Operations > + * table 6-2: Flowchard Showing Sequence of Device Error Signaling and Logging > + * Operations > + */ > +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err) > +{ > + uint8_t *aer_cap = NULL; > + uint16_t devctl = 0; > + uint16_t devsta = 0; > + uint32_t error_status = err->status; > + PCIEAERInject inj; > + > + if (!pci_is_express(dev)) { > + return -ENOSYS; > + } > + > + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > + error_status &= PCI_ERR_COR_SUPPORTED; > + } else { > + error_status &= PCI_ERR_UNC_SUPPORTED; > + } > + > + /* invalid status bit. one and only one bit must be set */ > + if (!error_status || (error_status & (error_status - 1))) { > + return -EINVAL; > + } > + > + if (dev->exp.aer_cap) { > + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > + aer_cap = dev->config + dev->exp.aer_cap; > + devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL); > + devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA); > + } > + > + inj.dev = dev; > + inj.aer_cap = aer_cap; > + inj.err = err; > + inj.devctl = devctl; > + inj.devsta = devsta; > + inj.error_status = error_status; > + inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) && > + err->status == PCI_ERR_UNC_UNSUP; > + inj.log_overflow = false; > + > + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > + if (!pcie_aer_inject_cor_error(&inj, 0, false)) { > + return 0; > + } > + } else { > + bool is_fatal = > + pcie_aer_uncor_default_severity(error_status) == > + PCI_ERR_ROOT_CMD_FATAL_EN; > + if (aer_cap) { > + is_fatal = > + error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER); > + } > + if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) { > + inj.error_status = PCI_ERR_COR_ADV_NONFATAL; > + if (!pcie_aer_inject_cor_error(&inj, error_status, true)) { > + return 0; > + } > + } else { > + if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) { > + return 0; > + } > + } > + } > + > + /* send up error message */ > + inj.msg.source_id = err->source_id; > + pcie_aer_msg(dev, &inj.msg); > + > + if (inj.log_overflow) { > + PCIEAERErr header_log_overflow = { > + .status = PCI_ERR_COR_HL_OVERFLOW, > + .flags = PCIE_AER_ERR_IS_CORRECTABLE, > + }; > + int ret = pcie_aer_inject_error(dev, &header_log_overflow); > + assert(!ret); > + } > + return 0; > +} > + > +void pcie_aer_write_config(PCIDevice *dev, > + uint32_t addr, uint32_t val, int len) > +{ > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > + uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap); > + uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS); > + > + /* uncorrectable error */ > + if (!(uncorsta & first_error)) { > + /* the bit that corresponds to the first error is cleared */ > + pcie_aer_clear_error(dev); > + } else if (errcap & PCI_ERR_CAP_MHRE) { > + /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared > + * nothing should happen. So we have to revert the modification to > + * the register. > + */ > + pcie_aer_update_uncor_status(dev); > + } else { > + /* capability & control > + * PCI_ERR_CAP_MHRE might be cleared, so clear of header log. > + */ > + aer_log_clear_all_err(&dev->exp.aer_log); > + } > +} > + > +void pcie_aer_root_init(PCIDevice *dev) > +{ > + uint16_t pos = dev->exp.aer_cap; > + > + pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND, > + PCI_ERR_ROOT_CMD_EN_MASK); > + pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS, > + PCI_ERR_ROOT_STATUS_REPORT_MASK); > + /* PCI_ERR_ROOT_IRQ is RO but devices change it using a > + * device-specific method. > + */ > + pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS, > + ~PCI_ERR_ROOT_IRQ); > +} > + > +void pcie_aer_root_reset(PCIDevice *dev) > +{ > + uint8_t* aer_cap = dev->config + dev->exp.aer_cap; > + > + pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0); > + > + /* > + * Advanced Error Interrupt Message Number in Root Error Status Register > + * must be updated by chip dependent code because it's chip dependent > + * which number is used. > + */ > +} > + > +void pcie_aer_root_write_config(PCIDevice *dev, > + uint32_t addr, uint32_t val, int len, > + uint32_t root_cmd_prev) > +{ > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > + uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > + uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status); > + uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); > + /* 6.2.4.1.2 Interrupt Generation */ > + if (!msix_enabled(dev) && !msi_enabled(dev)) { > + qemu_set_irq(dev->irq[dev->exp.aer_intx], !!(root_cmd & enabled_cmd)); > + return; > + } > + > + if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) { > + /* Send MSI on transition from false to true. */ > + return; > + } > + > + pcie_aer_root_notify(dev); > +} > + > +static const VMStateDescription vmstate_pcie_aer_err = { > + .name = "PCIE_AER_ERROR", > + .version_id = 1, > + .minimum_version_id = 1, > + .minimum_version_id_old = 1, > + .fields = (VMStateField[]) { > + VMSTATE_UINT32(status, PCIEAERErr), > + VMSTATE_UINT16(source_id, PCIEAERErr), > + VMSTATE_UINT16(flags, PCIEAERErr), > + VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4), > + VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +const VMStateDescription vmstate_pcie_aer_log = { > + .name = "PCIE_AER_ERROR_LOG", > + .version_id = 1, > + .minimum_version_id = 1, > + .minimum_version_id_old = 1, > + .fields = (VMStateField[]) { > + VMSTATE_UINT16(log_num, PCIEAERLog), > + VMSTATE_UINT16(log_max, PCIEAERLog), > + VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num, > + vmstate_pcie_aer_err, PCIEAERErr), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) > +{ > + QDict *qdict; > + int devfn; > + assert(qobject_type(data) == QTYPE_QDICT); > + qdict = qobject_to_qdict(data); > + > + devfn = (int)qdict_get_int(qdict, "devfn"); > + monitor_printf(mon, "OK id: %s domain: %x, bus: %x devfn: %x.%x\n", > + qdict_get_str(qdict, "id"), > + (int) qdict_get_int(qdict, "domain"), > + (int) qdict_get_int(qdict, "bus"), > + PCI_SLOT(devfn), PCI_FUNC(devfn)); > +} > + > +typedef struct PCIEAERErrorName { > + const char *name; > + uint32_t val; > + bool correctable; > +} PCIEAERErrorName; > + > +/* > + * AER error name -> value conversion table > + * This naming scheme is same to linux aer-injection tool. > + */ > +static const struct PCIEAERErrorName pcie_aer_error_list[] = { > + { > + .name = "TRAIN", > + .val = PCI_ERR_UNC_TRAIN, > + .correctable = false, > + }, { > + .name = "DLP", > + .val = PCI_ERR_UNC_DLP, > + .correctable = false, > + }, { > + .name = "SDN", > + .val = PCI_ERR_UNC_SDN, > + .correctable = false, > + }, { > + .name = "POISON_TLP", > + .val = PCI_ERR_UNC_POISON_TLP, > + .correctable = false, > + }, { > + .name = "FCP", > + .val = PCI_ERR_UNC_FCP, > + .correctable = false, > + }, { > + .name = "COMP_TIME", > + .val = PCI_ERR_UNC_COMP_TIME, > + .correctable = false, > + }, { > + .name = "COMP_ABORT", > + .val = PCI_ERR_UNC_COMP_ABORT, > + .correctable = false, > + }, { > + .name = "UNX_COMP", > + .val = PCI_ERR_UNC_UNX_COMP, > + .correctable = false, > + }, { > + .name = "RX_OVER", > + .val = PCI_ERR_UNC_RX_OVER, > + .correctable = false, > + }, { > + .name = "MALF_TLP", > + .val = PCI_ERR_UNC_MALF_TLP, > + .correctable = false, > + }, { > + .name = "ECRC", > + .val = PCI_ERR_UNC_ECRC, > + .correctable = false, > + }, { > + .name = "UNSUP", > + .val = PCI_ERR_UNC_UNSUP, > + .correctable = false, > + }, { > + .name = "ACSV", > + .val = PCI_ERR_UNC_ACSV, > + .correctable = false, > + }, { > + .name = "INTN", > + .val = PCI_ERR_UNC_INTN, > + .correctable = false, > + }, { > + .name = "MCBTLP", > + .val = PCI_ERR_UNC_MCBTLP, > + .correctable = false, > + }, { > + .name = "ATOP_EBLOCKED", > + .val = PCI_ERR_UNC_ATOP_EBLOCKED, > + .correctable = false, > + }, { > + .name = "TLP_PRF_BLOCKED", > + .val = PCI_ERR_UNC_TLP_PRF_BLOCKED, > + .correctable = false, > + }, { > + .name = "RCVR", > + .val = PCI_ERR_COR_RCVR, > + .correctable = true, > + }, { > + .name = "BAD_TLP", > + .val = PCI_ERR_COR_BAD_TLP, > + .correctable = true, > + }, { > + .name = "BAD_DLLP", > + .val = PCI_ERR_COR_BAD_DLLP, > + .correctable = true, > + }, { > + .name = "REP_ROLL", > + .val = PCI_ERR_COR_REP_ROLL, > + .correctable = true, > + }, { > + .name = "REP_TIMER", > + .val = PCI_ERR_COR_REP_TIMER, > + .correctable = true, > + }, { > + .name = "ADV_NONFATAL", > + .val = PCI_ERR_COR_ADV_NONFATAL, > + .correctable = true, > + }, { > + .name = "INTERNAL", > + .val = PCI_ERR_COR_INTERNAL, > + .correctable = true, > + }, { > + .name = "HL_OVERFLOW", > + .val = PCI_ERR_COR_HL_OVERFLOW, > + .correctable = true, > + }, > +}; > + > +static int pcie_aer_parse_error_string(const char *error_name, > + uint32_t *status, bool *correctable) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) { > + const PCIEAERErrorName *e = &pcie_aer_error_list[i]; > + if (strcmp(error_name, e->name)) { > + continue; > + } > + > + *status = e->val; > + *correctable = e->correctable; > + return 0; > + } > + return -EINVAL; > +} > + > +int do_pcie_aer_inject_error(Monitor *mon, > + const QDict *qdict, QObject **ret_data) > +{ > + const char *id = qdict_get_str(qdict, "id"); > + const char *error_name; > + uint32_t error_status; > + bool correctable; > + PCIDevice *dev; > + PCIEAERErr err; > + int ret; > + > + ret = pci_qdev_find_device(id, &dev); > + if (ret < 0) { > + monitor_printf(mon, > + "id or pci device path is invalid or device not " > + "found. %s\n", id); > + return ret; > + } > + if (!pci_is_express(dev)) { > + monitor_printf(mon, "the device doesn't support pci express. %s\n", > + id); > + return -ENOSYS; > + } > + > + error_name = qdict_get_str(qdict, "error_status"); > + if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) { > + char *e = NULL; > + error_status = strtoul(error_name, &e, 0); > + correctable = qdict_get_try_bool(qdict, "correctable", 0); > + if (!e || *e != '\0') { > + monitor_printf(mon, "invalid error status value. \"%s\"", > + error_name); > + return -EINVAL; > + } > + } > + err.status = error_status; > + err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn; > + > + err.flags = 0; > + if (correctable) { > + err.flags |= PCIE_AER_ERR_IS_CORRECTABLE; > + } > + if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) { > + err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY; > + } > + if (qdict_haskey(qdict, "header0")) { > + err.flags |= PCIE_AER_ERR_HEADER_VALID; > + } > + if (qdict_haskey(qdict, "prefix0")) { > + err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT; > + } > + > + err.header[0] = qdict_get_try_int(qdict, "header0", 0); > + err.header[1] = qdict_get_try_int(qdict, "header1", 0); > + err.header[2] = qdict_get_try_int(qdict, "header2", 0); > + err.header[3] = qdict_get_try_int(qdict, "header3", 0); > + > + err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0); > + err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0); > + err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0); > + err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0); > + > + ret = pcie_aer_inject_error(dev, &err); > + *ret_data = qobject_from_jsonf("{'id': %s, " > + "'domain': %d, 'bus': %d, 'devfn': %d, " > + "'ret': %d}", > + id, > + pci_find_domain(dev->bus), > + pci_bus_num(dev->bus), dev->devfn, > + ret); > + assert(*ret_data); > + > + return 0; > +} > diff --git a/hw/pci/pcie_aer.h b/hw/pci/pcie_aer.h > new file mode 100644 > index 0000000..7539500 > --- /dev/null > +++ b/hw/pci/pcie_aer.h > @@ -0,0 +1,106 @@ > +/* > + * pcie_aer.h > + * > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef QEMU_PCIE_AER_H > +#define QEMU_PCIE_AER_H > + > +#include "hw.h" > + > +/* definitions which PCIExpressDevice uses */ > + > +/* AER log */ > +struct PCIEAERLog { > + /* This structure is saved/loaded. > + So explicitly size them instead of unsigned int */ > + > + /* the number of currently recorded log in log member */ > + uint16_t log_num; > + > + /* > + * The maximum number of the log. Errors can be logged up to this. > + * > + * This is configurable property. > + * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT > + * to avoid unreasonable memory usage. > + * I bet that 128 log size would be big enough, otherwise too many errors > + * for system to function normaly. But could consecutive errors occur? > + */ > +#define PCIE_AER_LOG_MAX_DEFAULT 8 > +#define PCIE_AER_LOG_MAX_LIMIT 128 > +#define PCIE_AER_LOG_MAX_UNSET 0xffff > + uint16_t log_max; > + > + /* Error log. log_max-sized array */ > + PCIEAERErr *log; > +}; > + > +/* aer error message: error signaling message has only error sevirity and > + source id. See 2.2.8.3 error signaling messages */ > +struct PCIEAERMsg { > + /* > + * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN > + * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE} > + */ > + uint32_t severity; > + > + uint16_t source_id; /* bdf */ > +}; > + > +static inline bool > +pcie_aer_msg_is_uncor(const PCIEAERMsg *msg) > +{ > + return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN || > + msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN; > +} > + > +/* error */ > +struct PCIEAERErr { > + uint32_t status; /* error status bits */ > + uint16_t source_id; /* bdf */ > + > +#define PCIE_AER_ERR_IS_CORRECTABLE 0x1 /* correctable/uncorrectable */ > +#define PCIE_AER_ERR_MAYBE_ADVISORY 0x2 /* maybe advisory non-fatal */ > +#define PCIE_AER_ERR_HEADER_VALID 0x4 /* TLP header is logged */ > +#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8 /* TLP Prefix is logged */ > + uint16_t flags; > + > + uint32_t header[4]; /* TLP header */ > + uint32_t prefix[4]; /* TLP header prefix */ > +}; > + > +extern const VMStateDescription vmstate_pcie_aer_log; > + > +int pcie_aer_init(PCIDevice *dev, uint16_t offset); > +void pcie_aer_exit(PCIDevice *dev); > +void pcie_aer_write_config(PCIDevice *dev, > + uint32_t addr, uint32_t val, int len); > + > +/* aer root port */ > +void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector); > +void pcie_aer_root_init(PCIDevice *dev); > +void pcie_aer_root_reset(PCIDevice *dev); > +void pcie_aer_root_write_config(PCIDevice *dev, > + uint32_t addr, uint32_t val, int len, > + uint32_t root_cmd_prev); > + > +/* error injection */ > +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err); > + > +#endif /* QEMU_PCIE_AER_H */ > diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c > new file mode 100644 > index 0000000..c257fb4 > --- /dev/null > +++ b/hw/pci/pcie_host.c > @@ -0,0 +1,161 @@ > +/* > + * pcie_host.c > + * utility functions for pci express host bridge. > + * > + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "hw.h" > +#include "pci.h" > +#include "pcie_host.h" > +#include "exec-memory.h" > + > +/* > + * PCI express mmcfig address > + * bit 20 - 28: bus number > + * bit 15 - 19: device number > + * bit 12 - 14: function number > + * bit 0 - 11: offset in configuration space of a given device > + */ > +#define PCIE_MMCFG_SIZE_MAX (1ULL << 28) > +#define PCIE_MMCFG_SIZE_MIN (1ULL << 20) > +#define PCIE_MMCFG_BUS_BIT 20 > +#define PCIE_MMCFG_BUS_MASK 0x1ff > +#define PCIE_MMCFG_DEVFN_BIT 12 > +#define PCIE_MMCFG_DEVFN_MASK 0xff > +#define PCIE_MMCFG_CONFOFFSET_MASK 0xfff > +#define PCIE_MMCFG_BUS(addr) (((addr) >> PCIE_MMCFG_BUS_BIT) & \ > + PCIE_MMCFG_BUS_MASK) > +#define PCIE_MMCFG_DEVFN(addr) (((addr) >> PCIE_MMCFG_DEVFN_BIT) & \ > + PCIE_MMCFG_DEVFN_MASK) > +#define PCIE_MMCFG_CONFOFFSET(addr) ((addr) & PCIE_MMCFG_CONFOFFSET_MASK) > + > + > +/* a helper function to get a PCIDevice for a given mmconfig address */ > +static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, > + uint32_t mmcfg_addr) > +{ > + return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), > + PCIE_MMCFG_DEVFN(mmcfg_addr)); > +} > + > +static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr, > + uint64_t val, unsigned len) > +{ > + PCIExpressHost *e = opaque; > + PCIBus *s = e->pci.bus; > + PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); > + uint32_t addr; > + uint32_t limit; > + > + if (!pci_dev) { > + return; > + } > + addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > + limit = pci_config_size(pci_dev); > + if (limit <= addr) { > + /* conventional pci device can be behind pcie-to-pci bridge. > + 256 <= addr < 4K has no effects. */ > + return; > + } > + pci_host_config_write_common(pci_dev, addr, limit, val, len); > +} > + > +static uint64_t pcie_mmcfg_data_read(void *opaque, > + hwaddr mmcfg_addr, > + unsigned len) > +{ > + PCIExpressHost *e = opaque; > + PCIBus *s = e->pci.bus; > + PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); > + uint32_t addr; > + uint32_t limit; > + > + if (!pci_dev) { > + return ~0x0; > + } > + addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > + limit = pci_config_size(pci_dev); > + if (limit <= addr) { > + /* conventional pci device can be behind pcie-to-pci bridge. > + 256 <= addr < 4K has no effects. */ > + return ~0x0; > + } > + return pci_host_config_read_common(pci_dev, addr, limit, len); > +} > + > +static const MemoryRegionOps pcie_mmcfg_ops = { > + .read = pcie_mmcfg_data_read, > + .write = pcie_mmcfg_data_write, > + .endianness = DEVICE_NATIVE_ENDIAN, > +}; > + > +/* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */ > +#define PCIE_BASE_ADDR_UNMAPPED ((hwaddr)-1ULL) > + > +int pcie_host_init(PCIExpressHost *e) > +{ > + e->base_addr = PCIE_BASE_ADDR_UNMAPPED; > + > + return 0; > +} > + > +void pcie_host_mmcfg_unmap(PCIExpressHost *e) > +{ > + if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { > + memory_region_del_subregion(get_system_memory(), &e->mmio); > + memory_region_destroy(&e->mmio); > + e->base_addr = PCIE_BASE_ADDR_UNMAPPED; > + } > +} > + > +void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, > + uint32_t size) > +{ > + assert(!(size & (size - 1))); /* power of 2 */ > + assert(size >= PCIE_MMCFG_SIZE_MIN); > + assert(size <= PCIE_MMCFG_SIZE_MAX); > + e->size = size; > + memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size); > + e->base_addr = addr; > + memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio); > +} > + > +void pcie_host_mmcfg_update(PCIExpressHost *e, > + int enable, > + hwaddr addr, > + uint32_t size) > +{ > + pcie_host_mmcfg_unmap(e); > + if (enable) { > + pcie_host_mmcfg_map(e, addr, size); > + } > +} > + > +static const TypeInfo pcie_host_type_info = { > + .name = TYPE_PCIE_HOST_BRIDGE, > + .parent = TYPE_PCI_HOST_BRIDGE, > + .abstract = true, > + .instance_size = sizeof(PCIExpressHost), > +}; > + > +static void pcie_host_register_types(void) > +{ > + type_register_static(&pcie_host_type_info); > +} > + > +type_init(pcie_host_register_types) > diff --git a/hw/pci/pcie_host.h b/hw/pci/pcie_host.h > new file mode 100644 > index 0000000..3921935 > --- /dev/null > +++ b/hw/pci/pcie_host.h > @@ -0,0 +1,54 @@ > +/* > + * pcie_host.h > + * > + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef PCIE_HOST_H > +#define PCIE_HOST_H > + > +#include "pci_host.h" > +#include "memory.h" > + > +#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge" > +#define PCIE_HOST_BRIDGE(obj) \ > + OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE) > + > +struct PCIExpressHost { > + PCIHostState pci; > + > + /* express part */ > + > + /* base address where MMCONFIG area is mapped. */ > + hwaddr base_addr; > + > + /* the size of MMCONFIG area. It's host bridge dependent */ > + hwaddr size; > + > + /* MMCONFIG mmio area */ > + MemoryRegion mmio; > +}; > + > +int pcie_host_init(PCIExpressHost *e); > +void pcie_host_mmcfg_unmap(PCIExpressHost *e); > +void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size); > +void pcie_host_mmcfg_update(PCIExpressHost *e, > + int enable, > + hwaddr addr, > + uint32_t size); > + > +#endif /* PCIE_HOST_H */ > diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c > new file mode 100644 > index 0000000..d6350e5 > --- /dev/null > +++ b/hw/pci/pcie_port.c > @@ -0,0 +1,114 @@ > +/* > + * pcie_port.c > + * > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "pcie_port.h" > + > +void pcie_port_init_reg(PCIDevice *d) > +{ > + /* Unlike pci bridge, > + 66MHz and fast back to back don't apply to pci express port. */ > + pci_set_word(d->config + PCI_STATUS, 0); > + pci_set_word(d->config + PCI_SEC_STATUS, 0); > + > + /* Unlike conventional pci bridge, some bits are hardwired to 0. */ > + pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, > + PCI_BRIDGE_CTL_PARITY | > + PCI_BRIDGE_CTL_ISA | > + PCI_BRIDGE_CTL_VGA | > + PCI_BRIDGE_CTL_SERR | > + PCI_BRIDGE_CTL_BUS_RESET); > +} > + > +/************************************************************************** > + * (chassis number, pcie physical slot number) -> pcie slot conversion > + */ > +struct PCIEChassis { > + uint8_t number; > + > + QLIST_HEAD(, PCIESlot) slots; > + QLIST_ENTRY(PCIEChassis) next; > +}; > + > +static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis); > + > +static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number) > +{ > + struct PCIEChassis *c; > + QLIST_FOREACH(c, &chassis, next) { > + if (c->number == chassis_number) { > + break; > + } > + } > + return c; > +} > + > +void pcie_chassis_create(uint8_t chassis_number) > +{ > + struct PCIEChassis *c; > + c = pcie_chassis_find(chassis_number); > + if (c) { > + return; > + } > + c = g_malloc0(sizeof(*c)); > + c->number = chassis_number; > + QLIST_INIT(&c->slots); > + QLIST_INSERT_HEAD(&chassis, c, next); > +} > + > +static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c, > + uint8_t slot) > +{ > + PCIESlot *s; > + QLIST_FOREACH(s, &c->slots, next) { > + if (s->slot == slot) { > + break; > + } > + } > + return s; > +} > + > +PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot) > +{ > + struct PCIEChassis *c; > + c = pcie_chassis_find(chassis_number); > + if (!c) { > + return NULL; > + } > + return pcie_chassis_find_slot_with_chassis(c, slot); > +} > + > +int pcie_chassis_add_slot(struct PCIESlot *slot) > +{ > + struct PCIEChassis *c; > + c = pcie_chassis_find(slot->chassis); > + if (!c) { > + return -ENODEV; > + } > + if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) { > + return -EBUSY; > + } > + QLIST_INSERT_HEAD(&c->slots, slot, next); > + return 0; > +} > + > +void pcie_chassis_del_slot(PCIESlot *s) > +{ > + QLIST_REMOVE(s, next); > +} > diff --git a/hw/pci/pcie_port.h b/hw/pci/pcie_port.h > new file mode 100644 > index 0000000..3709583 > --- /dev/null > +++ b/hw/pci/pcie_port.h > @@ -0,0 +1,51 @@ > +/* > + * pcie_port.h > + * > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > + * VA Linux Systems Japan K.K. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef QEMU_PCIE_PORT_H > +#define QEMU_PCIE_PORT_H > + > +#include "pci_bridge.h" > +#include "pci_internals.h" > + > +struct PCIEPort { > + PCIBridge br; > + > + /* pci express switch port */ > + uint8_t port; > +}; > + > +void pcie_port_init_reg(PCIDevice *d); > + > +struct PCIESlot { > + PCIEPort port; > + > + /* pci express switch port with slot */ > + uint8_t chassis; > + uint16_t slot; > + QLIST_ENTRY(PCIESlot) next; > +}; > + > +void pcie_chassis_create(uint8_t chassis_number); > +void pcie_main_chassis_create(void); > +PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot); > +int pcie_chassis_add_slot(struct PCIESlot *slot); > +void pcie_chassis_del_slot(PCIESlot *s); > + > +#endif /* QEMU_PCIE_PORT_H */ > diff --git a/hw/pci/pcie_regs.h b/hw/pci/pcie_regs.h > new file mode 100644 > index 0000000..4d123d9 > --- /dev/null > +++ b/hw/pci/pcie_regs.h > @@ -0,0 +1,156 @@ > +/* > + * constants for pcie configurations space from pci express spec. > + * > + * TODO: > + * Those constants and macros should go to Linux pci_regs.h > + * Once they're merged, they will go away. > + */ > +#ifndef QEMU_PCIE_REGS_H > +#define QEMU_PCIE_REGS_H > + > + > +/* express capability */ > + > +#define PCI_EXP_VER2_SIZEOF 0x3c /* express capability of ver. 2 */ > +#define PCI_EXT_CAP_VER_SHIFT 16 > +#define PCI_EXT_CAP_NEXT_SHIFT 20 > +#define PCI_EXT_CAP_NEXT_MASK (0xffc << PCI_EXT_CAP_NEXT_SHIFT) > + > +#define PCI_EXT_CAP(id, ver, next) \ > + ((id) | \ > + ((ver) << PCI_EXT_CAP_VER_SHIFT) | \ > + ((next) << PCI_EXT_CAP_NEXT_SHIFT)) > + > +#define PCI_EXT_CAP_ALIGN 4 > +#define PCI_EXT_CAP_ALIGNUP(x) \ > + (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1)) > + > +/* PCI_EXP_FLAGS */ > +#define PCI_EXP_FLAGS_VER2 2 /* for now, supports only ver. 2 */ > +#define PCI_EXP_FLAGS_IRQ_SHIFT (ffs(PCI_EXP_FLAGS_IRQ) - 1) > +#define PCI_EXP_FLAGS_TYPE_SHIFT (ffs(PCI_EXP_FLAGS_TYPE) - 1) > + > + > +/* PCI_EXP_LINK{CAP, STA} */ > +/* link speed */ > +#define PCI_EXP_LNK_LS_25 1 > + > +#define PCI_EXP_LNK_MLW_SHIFT (ffs(PCI_EXP_LNKCAP_MLW) - 1) > +#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT) > + > +/* PCI_EXP_LINKCAP */ > +#define PCI_EXP_LNKCAP_ASPMS_SHIFT (ffs(PCI_EXP_LNKCAP_ASPMS) - 1) > +#define PCI_EXP_LNKCAP_ASPMS_0S (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT) > + > +#define PCI_EXP_LNKCAP_PN_SHIFT (ffs(PCI_EXP_LNKCAP_PN) - 1) > + > +#define PCI_EXP_SLTCAP_PSN_SHIFT (ffs(PCI_EXP_SLTCAP_PSN) - 1) > + > +#define PCI_EXP_SLTCTL_IND_RESERVED 0x0 > +#define PCI_EXP_SLTCTL_IND_ON 0x1 > +#define PCI_EXP_SLTCTL_IND_BLINK 0x2 > +#define PCI_EXP_SLTCTL_IND_OFF 0x3 > +#define PCI_EXP_SLTCTL_AIC_SHIFT (ffs(PCI_EXP_SLTCTL_AIC) - 1) > +#define PCI_EXP_SLTCTL_AIC_OFF \ > + (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT) > + > +#define PCI_EXP_SLTCTL_PIC_SHIFT (ffs(PCI_EXP_SLTCTL_PIC) - 1) > +#define PCI_EXP_SLTCTL_PIC_OFF \ > + (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT) > + > +#define PCI_EXP_SLTCTL_SUPPORTED \ > + (PCI_EXP_SLTCTL_ABPE | \ > + PCI_EXP_SLTCTL_PDCE | \ > + PCI_EXP_SLTCTL_CCIE | \ > + PCI_EXP_SLTCTL_HPIE | \ > + PCI_EXP_SLTCTL_AIC | \ > + PCI_EXP_SLTCTL_PCC | \ > + PCI_EXP_SLTCTL_EIC) > + > +#define PCI_EXP_DEVCAP2_EFF 0x100000 > +#define PCI_EXP_DEVCAP2_EETLPP 0x200000 > + > +#define PCI_EXP_DEVCTL2_EETLPPB 0x80 > + > +/* ARI */ > +#define PCI_ARI_VER 1 > +#define PCI_ARI_SIZEOF 8 > + > +/* AER */ > +#define PCI_ERR_VER 2 > +#define PCI_ERR_SIZEOF 0x48 > + > +#define PCI_ERR_UNC_SDN 0x00000020 /* surprise down */ > +#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */ > +#define PCI_ERR_UNC_INTN 0x00400000 /* Internal Error */ > +#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC Blcoked TLP */ > +#define PCI_ERR_UNC_ATOP_EBLOCKED 0x01000000 /* atomic op egress blocked */ > +#define PCI_ERR_UNC_TLP_PRF_BLOCKED 0x02000000 /* TLP Prefix Blocked */ > +#define PCI_ERR_COR_ADV_NONFATAL 0x00002000 /* Advisory Non-Fatal */ > +#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected Internal */ > +#define PCI_ERR_COR_HL_OVERFLOW 0x00008000 /* Header Long Overflow */ > +#define PCI_ERR_CAP_FEP_MASK 0x0000001f > +#define PCI_ERR_CAP_MHRC 0x00000200 > +#define PCI_ERR_CAP_MHRE 0x00000400 > +#define PCI_ERR_CAP_TLP 0x00000800 > + > +#define PCI_ERR_HEADER_LOG_SIZE 16 > +#define PCI_ERR_TLP_PREFIX_LOG 0x38 > +#define PCI_ERR_TLP_PREFIX_LOG_SIZE 16 > + > +#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR 0x4000 > + > +/* aer root error command/status */ > +#define PCI_ERR_ROOT_CMD_EN_MASK (PCI_ERR_ROOT_CMD_COR_EN | \ > + PCI_ERR_ROOT_CMD_NONFATAL_EN | \ > + PCI_ERR_ROOT_CMD_FATAL_EN) > + > +#define PCI_ERR_ROOT_IRQ_MAX 32 > +#define PCI_ERR_ROOT_IRQ 0xf8000000 > +#define PCI_ERR_ROOT_IRQ_SHIFT (ffs(PCI_ERR_ROOT_IRQ) - 1) > +#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV | \ > + PCI_ERR_ROOT_MULTI_COR_RCV | \ > + PCI_ERR_ROOT_UNCOR_RCV | \ > + PCI_ERR_ROOT_MULTI_UNCOR_RCV | \ > + PCI_ERR_ROOT_FIRST_FATAL | \ > + PCI_ERR_ROOT_NONFATAL_RCV | \ > + PCI_ERR_ROOT_FATAL_RCV) > + > +#define PCI_ERR_UNC_SUPPORTED (PCI_ERR_UNC_DLP | \ > + PCI_ERR_UNC_SDN | \ > + PCI_ERR_UNC_POISON_TLP | \ > + PCI_ERR_UNC_FCP | \ > + PCI_ERR_UNC_COMP_TIME | \ > + PCI_ERR_UNC_COMP_ABORT | \ > + PCI_ERR_UNC_UNX_COMP | \ > + PCI_ERR_UNC_RX_OVER | \ > + PCI_ERR_UNC_MALF_TLP | \ > + PCI_ERR_UNC_ECRC | \ > + PCI_ERR_UNC_UNSUP | \ > + PCI_ERR_UNC_ACSV | \ > + PCI_ERR_UNC_INTN | \ > + PCI_ERR_UNC_MCBTLP | \ > + PCI_ERR_UNC_ATOP_EBLOCKED | \ > + PCI_ERR_UNC_TLP_PRF_BLOCKED) > + > +#define PCI_ERR_UNC_SEVERITY_DEFAULT (PCI_ERR_UNC_DLP | \ > + PCI_ERR_UNC_SDN | \ > + PCI_ERR_UNC_FCP | \ > + PCI_ERR_UNC_RX_OVER | \ > + PCI_ERR_UNC_MALF_TLP | \ > + PCI_ERR_UNC_INTN) > + > +#define PCI_ERR_COR_SUPPORTED (PCI_ERR_COR_RCVR | \ > + PCI_ERR_COR_BAD_TLP | \ > + PCI_ERR_COR_BAD_DLLP | \ > + PCI_ERR_COR_REP_ROLL | \ > + PCI_ERR_COR_REP_TIMER | \ > + PCI_ERR_COR_ADV_NONFATAL | \ > + PCI_ERR_COR_INTERNAL | \ > + PCI_ERR_COR_HL_OVERFLOW) > + > +#define PCI_ERR_COR_MASK_DEFAULT (PCI_ERR_COR_ADV_NONFATAL | \ > + PCI_ERR_COR_INTERNAL | \ > + PCI_ERR_COR_HL_OVERFLOW) > + > +#endif /* QEMU_PCIE_REGS_H */ > diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c > new file mode 100644 > index 0000000..4597bbd > --- /dev/null > +++ b/hw/pci/shpc.c > @@ -0,0 +1,681 @@ > +#include <strings.h> > +#include <stdint.h> > +#include "range.h" > +#include "range.h" > +#include "shpc.h" > +#include "pci.h" > +#include "pci_internals.h" > +#include "msi.h" > + > +/* TODO: model power only and disabled slot states. */ > +/* TODO: handle SERR and wakeups */ > +/* TODO: consider enabling 66MHz support */ > + > +/* TODO: remove fully only on state DISABLED and LED off. > + * track state to properly record this. */ > + > +/* SHPC Working Register Set */ > +#define SHPC_BASE_OFFSET 0x00 /* 4 bytes */ > +#define SHPC_SLOTS_33 0x04 /* 4 bytes. Also encodes PCI-X slots. */ > +#define SHPC_SLOTS_66 0x08 /* 4 bytes. */ > +#define SHPC_NSLOTS 0x0C /* 1 byte */ > +#define SHPC_FIRST_DEV 0x0D /* 1 byte */ > +#define SHPC_PHYS_SLOT 0x0E /* 2 byte */ > +#define SHPC_PHYS_NUM_MAX 0x7ff > +#define SHPC_PHYS_NUM_UP 0x2000 > +#define SHPC_PHYS_MRL 0x4000 > +#define SHPC_PHYS_BUTTON 0x8000 > +#define SHPC_SEC_BUS 0x10 /* 2 bytes */ > +#define SHPC_SEC_BUS_33 0x0 > +#define SHPC_SEC_BUS_66 0x1 /* Unused */ > +#define SHPC_SEC_BUS_MASK 0x7 > +#define SHPC_MSI_CTL 0x12 /* 1 byte */ > +#define SHPC_PROG_IFC 0x13 /* 1 byte */ > +#define SHPC_PROG_IFC_1_0 0x1 > +#define SHPC_CMD_CODE 0x14 /* 1 byte */ > +#define SHPC_CMD_TRGT 0x15 /* 1 byte */ > +#define SHPC_CMD_TRGT_MIN 0x1 > +#define SHPC_CMD_TRGT_MAX 0x1f > +#define SHPC_CMD_STATUS 0x16 /* 2 bytes */ > +#define SHPC_CMD_STATUS_BUSY 0x1 > +#define SHPC_CMD_STATUS_MRL_OPEN 0x2 > +#define SHPC_CMD_STATUS_INVALID_CMD 0x4 > +#define SHPC_CMD_STATUS_INVALID_MODE 0x8 > +#define SHPC_INT_LOCATOR 0x18 /* 4 bytes */ > +#define SHPC_INT_COMMAND 0x1 > +#define SHPC_SERR_LOCATOR 0x1C /* 4 bytes */ > +#define SHPC_SERR_INT 0x20 /* 4 bytes */ > +#define SHPC_INT_DIS 0x1 > +#define SHPC_SERR_DIS 0x2 > +#define SHPC_CMD_INT_DIS 0x4 > +#define SHPC_ARB_SERR_DIS 0x8 > +#define SHPC_CMD_DETECTED 0x10000 > +#define SHPC_ARB_DETECTED 0x20000 > + /* 4 bytes * slot # (start from 0) */ > +#define SHPC_SLOT_REG(s) (0x24 + (s) * 4) > + /* 2 bytes */ > +#define SHPC_SLOT_STATUS(s) (0x0 + SHPC_SLOT_REG(s)) > + > +/* Same slot state masks are used for command and status registers */ > +#define SHPC_SLOT_STATE_MASK 0x03 > +#define SHPC_SLOT_STATE_SHIFT \ > + (ffs(SHPC_SLOT_STATE_MASK) - 1) > + > +#define SHPC_STATE_NO 0x0 > +#define SHPC_STATE_PWRONLY 0x1 > +#define SHPC_STATE_ENABLED 0x2 > +#define SHPC_STATE_DISABLED 0x3 > + > +#define SHPC_SLOT_PWR_LED_MASK 0xC > +#define SHPC_SLOT_PWR_LED_SHIFT \ > + (ffs(SHPC_SLOT_PWR_LED_MASK) - 1) > +#define SHPC_SLOT_ATTN_LED_MASK 0x30 > +#define SHPC_SLOT_ATTN_LED_SHIFT \ > + (ffs(SHPC_SLOT_ATTN_LED_MASK) - 1) > + > +#define SHPC_LED_NO 0x0 > +#define SHPC_LED_ON 0x1 > +#define SHPC_LED_BLINK 0x2 > +#define SHPC_LED_OFF 0x3 > + > +#define SHPC_SLOT_STATUS_PWR_FAULT 0x40 > +#define SHPC_SLOT_STATUS_BUTTON 0x80 > +#define SHPC_SLOT_STATUS_MRL_OPEN 0x100 > +#define SHPC_SLOT_STATUS_66 0x200 > +#define SHPC_SLOT_STATUS_PRSNT_MASK 0xC00 > +#define SHPC_SLOT_STATUS_PRSNT_EMPTY 0x3 > +#define SHPC_SLOT_STATUS_PRSNT_25W 0x1 > +#define SHPC_SLOT_STATUS_PRSNT_15W 0x2 > +#define SHPC_SLOT_STATUS_PRSNT_7_5W 0x0 > + > +#define SHPC_SLOT_STATUS_PRSNT_PCIX 0x3000 > + > + > + /* 1 byte */ > +#define SHPC_SLOT_EVENT_LATCH(s) (0x2 + SHPC_SLOT_REG(s)) > + /* 1 byte */ > +#define SHPC_SLOT_EVENT_SERR_INT_DIS(d, s) (0x3 + SHPC_SLOT_REG(s)) > +#define SHPC_SLOT_EVENT_PRESENCE 0x01 > +#define SHPC_SLOT_EVENT_ISOLATED_FAULT 0x02 > +#define SHPC_SLOT_EVENT_BUTTON 0x04 > +#define SHPC_SLOT_EVENT_MRL 0x08 > +#define SHPC_SLOT_EVENT_CONNECTED_FAULT 0x10 > +/* Bits below are used for Serr/Int disable only */ > +#define SHPC_SLOT_EVENT_MRL_SERR_DIS 0x20 > +#define SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS 0x40 > + > +#define SHPC_MIN_SLOTS 1 > +#define SHPC_MAX_SLOTS 31 > +#define SHPC_SIZEOF(d) SHPC_SLOT_REG((d)->shpc->nslots) > + > +/* SHPC Slot identifiers */ > + > +/* Hotplug supported at 31 slots out of the total 32. We reserve slot 0, > + and give the rest of them physical *and* pci numbers starting from 1, so > + they match logical numbers. Note: this means that multiple slots must have > + different chassis number values, to make chassis+physical slot unique. > + TODO: make this configurable? */ > +#define SHPC_IDX_TO_LOGICAL(slot) ((slot) + 1) > +#define SHPC_LOGICAL_TO_IDX(target) ((target) - 1) > +#define SHPC_IDX_TO_PCI(slot) ((slot) + 1) > +#define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1) > +#define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1) > + > +static int roundup_pow_of_two(int x) > +{ > + x |= (x >> 1); > + x |= (x >> 2); > + x |= (x >> 4); > + x |= (x >> 8); > + x |= (x >> 16); > + return x + 1; > +} > + > +static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk) > +{ > + uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); > + return (pci_get_word(status) & msk) >> (ffs(msk) - 1); > +} > + > +static void shpc_set_status(SHPCDevice *shpc, > + int slot, uint8_t value, uint16_t msk) > +{ > + uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); > + pci_word_test_and_clear_mask(status, msk); > + pci_word_test_and_set_mask(status, value << (ffs(msk) - 1)); > +} > + > +static void shpc_interrupt_update(PCIDevice *d) > +{ > + SHPCDevice *shpc = d->shpc; > + int slot; > + int level = 0; > + uint32_t serr_int; > + uint32_t int_locator = 0; > + > + /* Update interrupt locator register */ > + for (slot = 0; slot < shpc->nslots; ++slot) { > + uint8_t event = shpc->config[SHPC_SLOT_EVENT_LATCH(slot)]; > + uint8_t disable = shpc->config[SHPC_SLOT_EVENT_SERR_INT_DIS(d, slot)]; > + uint32_t mask = 1 << SHPC_IDX_TO_LOGICAL(slot); > + if (event & ~disable) { > + int_locator |= mask; > + } > + } > + serr_int = pci_get_long(shpc->config + SHPC_SERR_INT); > + if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_DIS)) { > + int_locator |= SHPC_INT_COMMAND; > + } > + pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator); > + level = (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0; > + if (msi_enabled(d) && shpc->msi_requested != level) > + msi_notify(d, 0); > + else > + qemu_set_irq(d->irq[0], level); > + shpc->msi_requested = level; > +} > + > +static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed) > +{ > + switch (speed) { > + case SHPC_SEC_BUS_33: > + shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK; > + shpc->config[SHPC_SEC_BUS] |= speed; > + break; > + default: > + pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, > + SHPC_CMD_STATUS_INVALID_MODE); > + } > +} > + > +void shpc_reset(PCIDevice *d) > +{ > + SHPCDevice *shpc = d->shpc; > + int nslots = shpc->nslots; > + int i; > + memset(shpc->config, 0, SHPC_SIZEOF(d)); > + pci_set_byte(shpc->config + SHPC_NSLOTS, nslots); > + pci_set_long(shpc->config + SHPC_SLOTS_33, nslots); > + pci_set_long(shpc->config + SHPC_SLOTS_66, 0); > + pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0)); > + pci_set_word(shpc->config + SHPC_PHYS_SLOT, > + SHPC_IDX_TO_PHYSICAL(0) | > + SHPC_PHYS_NUM_UP | > + SHPC_PHYS_MRL | > + SHPC_PHYS_BUTTON); > + pci_set_long(shpc->config + SHPC_SERR_INT, SHPC_INT_DIS | > + SHPC_SERR_DIS | > + SHPC_CMD_INT_DIS | > + SHPC_ARB_SERR_DIS); > + pci_set_byte(shpc->config + SHPC_PROG_IFC, SHPC_PROG_IFC_1_0); > + pci_set_word(shpc->config + SHPC_SEC_BUS, SHPC_SEC_BUS_33); > + for (i = 0; i < shpc->nslots; ++i) { > + pci_set_byte(shpc->config + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), > + SHPC_SLOT_EVENT_PRESENCE | > + SHPC_SLOT_EVENT_ISOLATED_FAULT | > + SHPC_SLOT_EVENT_BUTTON | > + SHPC_SLOT_EVENT_MRL | > + SHPC_SLOT_EVENT_CONNECTED_FAULT | > + SHPC_SLOT_EVENT_MRL_SERR_DIS | > + SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); > + if (shpc->sec_bus->devices[PCI_DEVFN(SHPC_IDX_TO_PCI(i), 0)]) { > + shpc_set_status(shpc, i, SHPC_STATE_ENABLED, SHPC_SLOT_STATE_MASK); > + shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_MRL_OPEN); > + shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_7_5W, > + SHPC_SLOT_STATUS_PRSNT_MASK); > + shpc_set_status(shpc, i, SHPC_LED_ON, SHPC_SLOT_PWR_LED_MASK); > + } else { > + shpc_set_status(shpc, i, SHPC_STATE_DISABLED, SHPC_SLOT_STATE_MASK); > + shpc_set_status(shpc, i, 1, SHPC_SLOT_STATUS_MRL_OPEN); > + shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_EMPTY, > + SHPC_SLOT_STATUS_PRSNT_MASK); > + shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK); > + } > + shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66); > + } > + shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33); > + shpc->msi_requested = 0; > + shpc_interrupt_update(d); > +} > + > +static void shpc_invalid_command(SHPCDevice *shpc) > +{ > + pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, > + SHPC_CMD_STATUS_INVALID_CMD); > +} > + > +static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot) > +{ > + int devfn; > + int pci_slot = SHPC_IDX_TO_PCI(slot); > + for (devfn = PCI_DEVFN(pci_slot, 0); > + devfn <= PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1); > + ++devfn) { > + PCIDevice *affected_dev = shpc->sec_bus->devices[devfn]; > + if (affected_dev) { > + qdev_free(&affected_dev->qdev); > + } > + } > +} > + > +static void shpc_slot_command(SHPCDevice *shpc, uint8_t target, > + uint8_t state, uint8_t power, uint8_t attn) > +{ > + uint8_t current_state; > + int slot = SHPC_LOGICAL_TO_IDX(target); > + if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) { > + shpc_invalid_command(shpc); > + return; > + } > + current_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); > + if (current_state == SHPC_STATE_ENABLED && state == SHPC_STATE_PWRONLY) { > + shpc_invalid_command(shpc); > + return; > + } > + > + switch (power) { > + case SHPC_LED_NO: > + break; > + default: > + /* TODO: send event to monitor */ > + shpc_set_status(shpc, slot, power, SHPC_SLOT_PWR_LED_MASK); > + } > + switch (attn) { > + case SHPC_LED_NO: > + break; > + default: > + /* TODO: send event to monitor */ > + shpc_set_status(shpc, slot, attn, SHPC_SLOT_ATTN_LED_MASK); > + } > + > + if ((current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_PWRONLY) || > + (current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_ENABLED)) { > + shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > + } else if ((current_state == SHPC_STATE_ENABLED || > + current_state == SHPC_STATE_PWRONLY) && > + state == SHPC_STATE_DISABLED) { > + shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > + power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); > + /* TODO: track what monitor requested. */ > + /* Look at LED to figure out whether it's ok to remove the device. */ > + if (power == SHPC_LED_OFF) { > + shpc_free_devices_in_slot(shpc, slot); > + shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); > + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, > + SHPC_SLOT_STATUS_PRSNT_MASK); > + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > + SHPC_SLOT_EVENT_BUTTON | > + SHPC_SLOT_EVENT_MRL | > + SHPC_SLOT_EVENT_PRESENCE; > + } > + } > +} > + > +static void shpc_command(SHPCDevice *shpc) > +{ > + uint8_t code = pci_get_byte(shpc->config + SHPC_CMD_CODE); > + uint8_t speed; > + uint8_t target; > + uint8_t attn; > + uint8_t power; > + uint8_t state; > + int i; > + > + /* Clear status from the previous command. */ > + pci_word_test_and_clear_mask(shpc->config + SHPC_CMD_STATUS, > + SHPC_CMD_STATUS_BUSY | > + SHPC_CMD_STATUS_MRL_OPEN | > + SHPC_CMD_STATUS_INVALID_CMD | > + SHPC_CMD_STATUS_INVALID_MODE); > + switch (code) { > + case 0x00 ... 0x3f: > + target = shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX; > + state = (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_SHIFT; > + power = (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_LED_SHIFT; > + attn = (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_LED_SHIFT; > + shpc_slot_command(shpc, target, state, power, attn); > + break; > + case 0x40 ... 0x47: > + speed = code & SHPC_SEC_BUS_MASK; > + shpc_set_sec_bus_speed(shpc, speed); > + break; > + case 0x48: > + /* Power only all slots */ > + /* first verify no slots are enabled */ > + for (i = 0; i < shpc->nslots; ++i) { > + state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); > + if (state == SHPC_STATE_ENABLED) { > + shpc_invalid_command(shpc); > + goto done; > + } > + } > + for (i = 0; i < shpc->nslots; ++i) { > + if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { > + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > + SHPC_STATE_PWRONLY, SHPC_LED_ON, SHPC_LED_NO); > + } else { > + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > + SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); > + } > + } > + break; > + case 0x49: > + /* Enable all slots */ > + /* TODO: Spec says this shall fail if some are already enabled. > + * This doesn't make sense - why not? a spec bug? */ > + for (i = 0; i < shpc->nslots; ++i) { > + state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); > + if (state == SHPC_STATE_ENABLED) { > + shpc_invalid_command(shpc); > + goto done; > + } > + } > + for (i = 0; i < shpc->nslots; ++i) { > + if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { > + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > + SHPC_STATE_ENABLED, SHPC_LED_ON, SHPC_LED_NO); > + } else { > + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > + SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); > + } > + } > + break; > + default: > + shpc_invalid_command(shpc); > + break; > + } > +done: > + pci_long_test_and_set_mask(shpc->config + SHPC_SERR_INT, SHPC_CMD_DETECTED); > +} > + > +static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, int l) > +{ > + SHPCDevice *shpc = d->shpc; > + int i; > + if (addr >= SHPC_SIZEOF(d)) { > + return; > + } > + l = MIN(l, SHPC_SIZEOF(d) - addr); > + > + /* TODO: code duplicated from pci.c */ > + for (i = 0; i < l; val >>= 8, ++i) { > + unsigned a = addr + i; > + uint8_t wmask = shpc->wmask[a]; > + uint8_t w1cmask = shpc->w1cmask[a]; > + assert(!(wmask & w1cmask)); > + shpc->config[a] = (shpc->config[a] & ~wmask) | (val & wmask); > + shpc->config[a] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ > + } > + if (ranges_overlap(addr, l, SHPC_CMD_CODE, 2)) { > + shpc_command(shpc); > + } > + shpc_interrupt_update(d); > +} > + > +static uint64_t shpc_read(PCIDevice *d, unsigned addr, int l) > +{ > + uint64_t val = 0x0; > + if (addr >= SHPC_SIZEOF(d)) { > + return val; > + } > + l = MIN(l, SHPC_SIZEOF(d) - addr); > + memcpy(&val, d->shpc->config + addr, l); > + return val; > +} > + > +/* SHPC Bridge Capability */ > +#define SHPC_CAP_LENGTH 0x08 > +#define SHPC_CAP_DWORD_SELECT 0x2 /* 1 byte */ > +#define SHPC_CAP_CxP 0x3 /* 1 byte: CSP, CIP */ > +#define SHPC_CAP_DWORD_DATA 0x4 /* 4 bytes */ > +#define SHPC_CAP_CSP_MASK 0x4 > +#define SHPC_CAP_CIP_MASK 0x8 > + > +static uint8_t shpc_cap_dword(PCIDevice *d) > +{ > + return pci_get_byte(d->config + d->shpc->cap + SHPC_CAP_DWORD_SELECT); > +} > + > +/* Update dword data capability register */ > +static void shpc_cap_update_dword(PCIDevice *d) > +{ > + unsigned data; > + data = shpc_read(d, shpc_cap_dword(d) * 4, 4); > + pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, data); > +} > + > +/* Add SHPC capability to the config space for the device. */ > +static int shpc_cap_add_config(PCIDevice *d) > +{ > + uint8_t *config; > + int config_offset; > + config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC, > + 0, SHPC_CAP_LENGTH); > + if (config_offset < 0) { > + return config_offset; > + } > + config = d->config + config_offset; > + > + pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0); > + pci_set_byte(config + SHPC_CAP_CxP, 0); > + pci_set_long(config + SHPC_CAP_DWORD_DATA, 0); > + d->shpc->cap = config_offset; > + /* Make dword select and data writeable. */ > + pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff); > + pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff); > + return 0; > +} > + > +static uint64_t shpc_mmio_read(void *opaque, hwaddr addr, > + unsigned size) > +{ > + return shpc_read(opaque, addr, size); > +} > + > +static void shpc_mmio_write(void *opaque, hwaddr addr, > + uint64_t val, unsigned size) > +{ > + shpc_write(opaque, addr, val, size); > +} > + > +static const MemoryRegionOps shpc_mmio_ops = { > + .read = shpc_mmio_read, > + .write = shpc_mmio_write, > + .endianness = DEVICE_LITTLE_ENDIAN, > + .valid = { > + /* SHPC ECN requires dword accesses, but the original 1.0 spec doesn't. > + * It's easier to suppport all sizes than worry about it. */ > + .min_access_size = 1, > + .max_access_size = 4, > + }, > +}; > + > +static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev, > + PCIHotplugState hotplug_state) > +{ > + int pci_slot = PCI_SLOT(affected_dev->devfn); > + uint8_t state; > + uint8_t led; > + PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); > + SHPCDevice *shpc = d->shpc; > + int slot = SHPC_PCI_TO_IDX(pci_slot); > + if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) { > + error_report("Unsupported PCI slot %d for standard hotplug " > + "controller. Valid slots are between %d and %d.", > + pci_slot, SHPC_IDX_TO_PCI(0), > + SHPC_IDX_TO_PCI(shpc->nslots) - 1); > + return -1; > + } > + /* Don't send event when device is enabled during qemu machine creation: > + * it is present on boot, no hotplug event is necessary. We do send an > + * event when the device is disabled later. */ > + if (hotplug_state == PCI_COLDPLUG_ENABLED) { > + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); > + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, > + SHPC_SLOT_STATUS_PRSNT_MASK); > + return 0; > + } > + if (hotplug_state == PCI_HOTPLUG_DISABLED) { > + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON; > + state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); > + led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); > + if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) { > + shpc_free_devices_in_slot(shpc, slot); > + shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); > + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, > + SHPC_SLOT_STATUS_PRSNT_MASK); > + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > + SHPC_SLOT_EVENT_MRL | > + SHPC_SLOT_EVENT_PRESENCE; > + } > + } else { > + /* This could be a cancellation of the previous removal. > + * We check MRL state to figure out. */ > + if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) { > + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); > + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, > + SHPC_SLOT_STATUS_PRSNT_MASK); > + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > + SHPC_SLOT_EVENT_BUTTON | > + SHPC_SLOT_EVENT_MRL | > + SHPC_SLOT_EVENT_PRESENCE; > + } else { > + /* Press attention button to cancel removal */ > + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > + SHPC_SLOT_EVENT_BUTTON; > + } > + } > + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66); > + shpc_interrupt_update(d); > + return 0; > +} > + > +/* Initialize the SHPC structure in bridge's BAR. */ > +int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset) > +{ > + int i, ret; > + int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */ > + SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc)); > + shpc->sec_bus = sec_bus; > + ret = shpc_cap_add_config(d); > + if (ret) { > + g_free(d->shpc); > + return ret; > + } > + if (nslots < SHPC_MIN_SLOTS) { > + return 0; > + } > + if (nslots > SHPC_MAX_SLOTS || > + SHPC_IDX_TO_PCI(nslots) > PCI_SLOT_MAX) { > + /* TODO: report an error mesage that makes sense. */ > + return -EINVAL; > + } > + shpc->nslots = nslots; > + shpc->config = g_malloc0(SHPC_SIZEOF(d)); > + shpc->cmask = g_malloc0(SHPC_SIZEOF(d)); > + shpc->wmask = g_malloc0(SHPC_SIZEOF(d)); > + shpc->w1cmask = g_malloc0(SHPC_SIZEOF(d)); > + > + shpc_reset(d); > + > + pci_set_long(shpc->config + SHPC_BASE_OFFSET, offset); > + > + pci_set_byte(shpc->wmask + SHPC_CMD_CODE, 0xff); > + pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); > + pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); > + pci_set_long(shpc->wmask + SHPC_SERR_INT, > + SHPC_INT_DIS | > + SHPC_SERR_DIS | > + SHPC_CMD_INT_DIS | > + SHPC_ARB_SERR_DIS); > + pci_set_long(shpc->w1cmask + SHPC_SERR_INT, > + SHPC_CMD_DETECTED | > + SHPC_ARB_DETECTED); > + for (i = 0; i < nslots; ++i) { > + pci_set_byte(shpc->wmask + > + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), > + SHPC_SLOT_EVENT_PRESENCE | > + SHPC_SLOT_EVENT_ISOLATED_FAULT | > + SHPC_SLOT_EVENT_BUTTON | > + SHPC_SLOT_EVENT_MRL | > + SHPC_SLOT_EVENT_CONNECTED_FAULT | > + SHPC_SLOT_EVENT_MRL_SERR_DIS | > + SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); > + pci_set_byte(shpc->w1cmask + > + SHPC_SLOT_EVENT_LATCH(i), > + SHPC_SLOT_EVENT_PRESENCE | > + SHPC_SLOT_EVENT_ISOLATED_FAULT | > + SHPC_SLOT_EVENT_BUTTON | > + SHPC_SLOT_EVENT_MRL | > + SHPC_SLOT_EVENT_CONNECTED_FAULT); > + } > + > + /* TODO: init cmask */ > + memory_region_init_io(&shpc->mmio, &shpc_mmio_ops, d, "shpc-mmio", > + SHPC_SIZEOF(d)); > + shpc_cap_update_dword(d); > + memory_region_add_subregion(bar, offset, &shpc->mmio); > + pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev); > + > + d->cap_present |= QEMU_PCI_CAP_SHPC; > + return 0; > +} > + > +int shpc_bar_size(PCIDevice *d) > +{ > + return roundup_pow_of_two(SHPC_SLOT_REG(SHPC_MAX_SLOTS)); > +} > + > +void shpc_cleanup(PCIDevice *d, MemoryRegion *bar) > +{ > + SHPCDevice *shpc = d->shpc; > + d->cap_present &= ~QEMU_PCI_CAP_SHPC; > + memory_region_del_subregion(bar, &shpc->mmio); > + /* TODO: cleanup config space changes? */ > + g_free(shpc->config); > + g_free(shpc->cmask); > + g_free(shpc->wmask); > + g_free(shpc->w1cmask); > + memory_region_destroy(&shpc->mmio); > + g_free(shpc); > +} > + > +void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) > +{ > + if (!ranges_overlap(addr, l, d->shpc->cap, SHPC_CAP_LENGTH)) { > + return; > + } > + if (ranges_overlap(addr, l, d->shpc->cap + SHPC_CAP_DWORD_DATA, 4)) { > + unsigned dword_data; > + dword_data = pci_get_long(d->shpc->config + d->shpc->cap > + + SHPC_CAP_DWORD_DATA); > + shpc_write(d, shpc_cap_dword(d) * 4, dword_data, 4); > + } > + /* Update cap dword data in case guest is going to read it. */ > + shpc_cap_update_dword(d); > +} > + > +static void shpc_save(QEMUFile *f, void *pv, size_t size) > +{ > + PCIDevice *d = container_of(pv, PCIDevice, shpc); > + qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); > +} > + > +static int shpc_load(QEMUFile *f, void *pv, size_t size) > +{ > + PCIDevice *d = container_of(pv, PCIDevice, shpc); > + int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); > + if (ret != SHPC_SIZEOF(d)) { > + return -EINVAL; > + } > + /* Make sure we don't lose notifications. An extra interrupt is harmless. */ > + d->shpc->msi_requested = 0; > + shpc_interrupt_update(d); > + return 0; > +} > + > +VMStateInfo shpc_vmstate_info = { > + .name = "shpc", > + .get = shpc_load, > + .put = shpc_save, > +}; > diff --git a/hw/pci/shpc.h b/hw/pci/shpc.h > new file mode 100644 > index 0000000..130b71d > --- /dev/null > +++ b/hw/pci/shpc.h > @@ -0,0 +1,48 @@ > +#ifndef SHPC_H > +#define SHPC_H > + > +#include "qemu-common.h" > +#include "memory.h" > +#include "vmstate.h" > + > +struct SHPCDevice { > + /* Capability offset in device's config space */ > + int cap; > + > + /* # of hot-pluggable slots */ > + int nslots; > + > + /* SHPC WRS: working register set */ > + uint8_t *config; > + > + /* Used to enable checks on load. Note that writable bits are > + * never checked even if set in cmask. */ > + uint8_t *cmask; > + > + /* Used to implement R/W bytes */ > + uint8_t *wmask; > + > + /* Used to implement RW1C(Write 1 to Clear) bytes */ > + uint8_t *w1cmask; > + > + /* MMIO for the SHPC BAR */ > + MemoryRegion mmio; > + > + /* Bus controlled by this SHPC */ > + PCIBus *sec_bus; > + > + /* MSI already requested for this event */ > + int msi_requested; > +}; > + > +void shpc_reset(PCIDevice *d); > +int shpc_bar_size(PCIDevice *dev); > +int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off); > +void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar); > +void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len); > + > +extern VMStateInfo shpc_vmstate_info; > +#define SHPC_VMSTATE(_field, _type) \ > + VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0) > + > +#endif > diff --git a/hw/pci/slotid_cap.c b/hw/pci/slotid_cap.c > new file mode 100644 > index 0000000..0106452 > --- /dev/null > +++ b/hw/pci/slotid_cap.c > @@ -0,0 +1,44 @@ > +#include "slotid_cap.h" > +#include "pci.h" > + > +#define SLOTID_CAP_LENGTH 4 > +#define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1) > + > +int slotid_cap_init(PCIDevice *d, int nslots, > + uint8_t chassis, > + unsigned offset) > +{ > + int cap; > + if (!chassis) { > + error_report("Bridge chassis not specified. Each bridge is required " > + "to be assigned a unique chassis id > 0."); > + return -EINVAL; > + } > + if (nslots < 0 || nslots > (PCI_SID_ESR_NSLOTS >> SLOTID_NSLOTS_SHIFT)) { > + /* TODO: error report? */ > + return -EINVAL; > + } > + > + cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset, SLOTID_CAP_LENGTH); > + if (cap < 0) { > + return cap; > + } > + /* We make each chassis unique, this way each bridge is First in Chassis */ > + d->config[cap + PCI_SID_ESR] = PCI_SID_ESR_FIC | > + (nslots << SLOTID_NSLOTS_SHIFT); > + d->cmask[cap + PCI_SID_ESR] = 0xff; > + d->config[cap + PCI_SID_CHASSIS_NR] = chassis; > + /* Note: Chassis number register is non-volatile, > + so we don't reset it. */ > + /* TODO: store in eeprom? */ > + d->wmask[cap + PCI_SID_CHASSIS_NR] = 0xff; > + > + d->cap_present |= QEMU_PCI_CAP_SLOTID; > + return 0; > +} > + > +void slotid_cap_cleanup(PCIDevice *d) > +{ > + /* TODO: cleanup config space? */ > + d->cap_present &= ~QEMU_PCI_CAP_SLOTID; > +} > diff --git a/hw/pci/slotid_cap.h b/hw/pci/slotid_cap.h > new file mode 100644 > index 0000000..70db047 > --- /dev/null > +++ b/hw/pci/slotid_cap.h > @@ -0,0 +1,11 @@ > +#ifndef PCI_SLOTID_CAP_H > +#define PCI_SLOTID_CAP_H > + > +#include "qemu-common.h" > + > +int slotid_cap_init(PCIDevice *dev, int nslots, > + uint8_t chassis, > + unsigned offset); > +void slotid_cap_cleanup(PCIDevice *dev); > + > +#endif > diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c > deleted file mode 100644 > index 4680501..0000000 > --- a/hw/pci_bridge.c > +++ /dev/null > @@ -1,363 +0,0 @@ > -/* > - * QEMU PCI bus manager > - * > - * Copyright (c) 2004 Fabrice Bellard > - * > - * Permission is hereby granted, free of charge, to any person obtaining a copy > - * of this software and associated documentation files (the "Software"), to dea > - > - * in the Software without restriction, including without limitation the rights > - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > - * copies of the Software, and to permit persons to whom the Software is > - * furnished to do so, subject to the following conditions: > - * > - * The above copyright notice and this permission notice shall be included in > - * all copies or substantial portions of the Software. > - * > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM > - > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > - * THE SOFTWARE. > - */ > -/* > - * split out from pci.c > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - */ > - > -#include "pci_bridge.h" > -#include "pci_internals.h" > -#include "range.h" > - > -/* PCI bridge subsystem vendor ID helper functions */ > -#define PCI_SSVID_SIZEOF 8 > -#define PCI_SSVID_SVID 4 > -#define PCI_SSVID_SSID 6 > - > -int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, > - uint16_t svid, uint16_t ssid) > -{ > - int pos; > - pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF); > - if (pos < 0) { > - return pos; > - } > - > - pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid); > - pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid); > - return pos; > -} > - > -/* Accessor function to get parent bridge device from pci bus. */ > -PCIDevice *pci_bridge_get_device(PCIBus *bus) > -{ > - return bus->parent_dev; > -} > - > -/* Accessor function to get secondary bus from pci-to-pci bridge device */ > -PCIBus *pci_bridge_get_sec_bus(PCIBridge *br) > -{ > - return &br->sec_bus; > -} > - > -static uint32_t pci_config_get_io_base(const PCIDevice *d, > - uint32_t base, uint32_t base_upper16) > -{ > - uint32_t val; > - > - val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8; > - if (d->config[base] & PCI_IO_RANGE_TYPE_32) { > - val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16; > - } > - return val; > -} > - > -static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base) > -{ > - return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) > - << 16; > -} > - > -static pcibus_t pci_config_get_pref_base(const PCIDevice *d, > - uint32_t base, uint32_t upper) > -{ > - pcibus_t tmp; > - pcibus_t val; > - > - tmp = (pcibus_t)pci_get_word(d->config + base); > - val = (tmp & PCI_PREF_RANGE_MASK) << 16; > - if (tmp & PCI_PREF_RANGE_TYPE_64) { > - val |= (pcibus_t)pci_get_long(d->config + upper) << 32; > - } > - return val; > -} > - > -/* accessor function to get bridge filtering base address */ > -pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type) > -{ > - pcibus_t base; > - if (type & PCI_BASE_ADDRESS_SPACE_IO) { > - base = pci_config_get_io_base(bridge, > - PCI_IO_BASE, PCI_IO_BASE_UPPER16); > - } else { > - if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > - base = pci_config_get_pref_base( > - bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32); > - } else { > - base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE); > - } > - } > - > - return base; > -} > - > -/* accessor funciton to get bridge filtering limit */ > -pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type) > -{ > - pcibus_t limit; > - if (type & PCI_BASE_ADDRESS_SPACE_IO) { > - limit = pci_config_get_io_base(bridge, > - PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16); > - limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */ > - } else { > - if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > - limit = pci_config_get_pref_base( > - bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32); > - } else { > - limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT); > - } > - limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */ > - } > - return limit; > -} > - > -static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, > - uint8_t type, const char *name, > - MemoryRegion *space, > - MemoryRegion *parent_space, > - bool enabled) > -{ > - pcibus_t base = pci_bridge_get_base(&bridge->dev, type); > - pcibus_t limit = pci_bridge_get_limit(&bridge->dev, type); > - /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly. > - * Apparently no way to do this with existing memory APIs. */ > - pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0; > - > - memory_region_init_alias(alias, name, space, base, size); > - memory_region_add_subregion_overlap(parent_space, base, alias, 1); > -} > - > -static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) > -{ > - PCIBus *parent = br->dev.bus; > - PCIBridgeWindows *w = g_new(PCIBridgeWindows, 1); > - uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND); > - > - pci_bridge_init_alias(br, &w->alias_pref_mem, > - PCI_BASE_ADDRESS_MEM_PREFETCH, > - "pci_bridge_pref_mem", > - &br->address_space_mem, > - parent->address_space_mem, > - cmd & PCI_COMMAND_MEMORY); > - pci_bridge_init_alias(br, &w->alias_mem, > - PCI_BASE_ADDRESS_SPACE_MEMORY, > - "pci_bridge_mem", > - &br->address_space_mem, > - parent->address_space_mem, > - cmd & PCI_COMMAND_MEMORY); > - pci_bridge_init_alias(br, &w->alias_io, > - PCI_BASE_ADDRESS_SPACE_IO, > - "pci_bridge_io", > - &br->address_space_io, > - parent->address_space_io, > - cmd & PCI_COMMAND_IO); > - /* TODO: optinal VGA and VGA palette snooping support. */ > - > - return w; > -} > - > -static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w) > -{ > - PCIBus *parent = br->dev.bus; > - > - memory_region_del_subregion(parent->address_space_io, &w->alias_io); > - memory_region_del_subregion(parent->address_space_mem, &w->alias_mem); > - memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem); > -} > - > -static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w) > -{ > - memory_region_destroy(&w->alias_io); > - memory_region_destroy(&w->alias_mem); > - memory_region_destroy(&w->alias_pref_mem); > - g_free(w); > -} > - > -static void pci_bridge_update_mappings(PCIBridge *br) > -{ > - PCIBridgeWindows *w = br->windows; > - > - /* Make updates atomic to: handle the case of one VCPU updating the bridge > - * while another accesses an unaffected region. */ > - memory_region_transaction_begin(); > - pci_bridge_region_del(br, br->windows); > - br->windows = pci_bridge_region_init(br); > - memory_region_transaction_commit(); > - pci_bridge_region_cleanup(br, w); > -} > - > -/* default write_config function for PCI-to-PCI bridge */ > -void pci_bridge_write_config(PCIDevice *d, > - uint32_t address, uint32_t val, int len) > -{ > - PCIBridge *s = container_of(d, PCIBridge, dev); > - uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); > - uint16_t newctl; > - > - pci_default_write_config(d, address, val, len); > - > - if (ranges_overlap(address, len, PCI_COMMAND, 2) || > - > - /* io base/limit */ > - ranges_overlap(address, len, PCI_IO_BASE, 2) || > - > - /* memory base/limit, prefetchable base/limit and > - io base/limit upper 16 */ > - ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { > - pci_bridge_update_mappings(s); > - } > - > - newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); > - if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) { > - /* Trigger hot reset on 0->1 transition. */ > - pci_bus_reset(&s->sec_bus); > - } > -} > - > -void pci_bridge_disable_base_limit(PCIDevice *dev) > -{ > - uint8_t *conf = dev->config; > - > - pci_byte_test_and_set_mask(conf + PCI_IO_BASE, > - PCI_IO_RANGE_MASK & 0xff); > - pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, > - PCI_IO_RANGE_MASK & 0xff); > - pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE, > - PCI_MEMORY_RANGE_MASK & 0xffff); > - pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, > - PCI_MEMORY_RANGE_MASK & 0xffff); > - pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE, > - PCI_PREF_RANGE_MASK & 0xffff); > - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, > - PCI_PREF_RANGE_MASK & 0xffff); > - pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); > - pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); > -} > - > -/* reset bridge specific configuration registers */ > -void pci_bridge_reset(DeviceState *qdev) > -{ > - PCIDevice *dev = PCI_DEVICE(qdev); > - uint8_t *conf = dev->config; > - > - conf[PCI_PRIMARY_BUS] = 0; > - conf[PCI_SECONDARY_BUS] = 0; > - conf[PCI_SUBORDINATE_BUS] = 0; > - conf[PCI_SEC_LATENCY_TIMER] = 0; > - > - /* > - * the default values for base/limit registers aren't specified > - * in the PCI-to-PCI-bridge spec. So we don't thouch them here. > - * Each implementation can override it. > - * typical implementation does > - * zero base/limit registers or > - * disable forwarding: pci_bridge_disable_base_limit() > - * If disable forwarding is wanted, call pci_bridge_disable_base_limit() > - * after this function. > - */ > - pci_byte_test_and_clear_mask(conf + PCI_IO_BASE, > - PCI_IO_RANGE_MASK & 0xff); > - pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, > - PCI_IO_RANGE_MASK & 0xff); > - pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE, > - PCI_MEMORY_RANGE_MASK & 0xffff); > - pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, > - PCI_MEMORY_RANGE_MASK & 0xffff); > - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE, > - PCI_PREF_RANGE_MASK & 0xffff); > - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, > - PCI_PREF_RANGE_MASK & 0xffff); > - pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); > - pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); > - > - pci_set_word(conf + PCI_BRIDGE_CONTROL, 0); > -} > - > -/* default qdev initialization function for PCI-to-PCI bridge */ > -int pci_bridge_initfn(PCIDevice *dev) > -{ > - PCIBus *parent = dev->bus; > - PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); > - PCIBus *sec_bus = &br->sec_bus; > - > - pci_word_test_and_set_mask(dev->config + PCI_STATUS, > - PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); > - pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI); > - dev->config[PCI_HEADER_TYPE] = > - (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) | > - PCI_HEADER_TYPE_BRIDGE; > - pci_set_word(dev->config + PCI_SEC_STATUS, > - PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); > - > - /* > - * If we don't specify the name, the bus will be addressed as <id>.0, where > - * id is the device id. > - * Since PCI Bridge devices have a single bus each, we don't need the index: > - * let users address the bus using the device name. > - */ > - if (!br->bus_name && dev->qdev.id && *dev->qdev.id) { > - br->bus_name = dev->qdev.id; > - } > - > - qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev, > - br->bus_name); > - sec_bus->parent_dev = dev; > - sec_bus->map_irq = br->map_irq; > - sec_bus->address_space_mem = &br->address_space_mem; > - memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX); > - sec_bus->address_space_io = &br->address_space_io; > - memory_region_init(&br->address_space_io, "pci_bridge_io", 65536); > - br->windows = pci_bridge_region_init(br); > - QLIST_INIT(&sec_bus->child); > - QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); > - return 0; > -} > - > -/* default qdev clean up function for PCI-to-PCI bridge */ > -void pci_bridge_exitfn(PCIDevice *pci_dev) > -{ > - PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); > - assert(QLIST_EMPTY(&s->sec_bus.child)); > - QLIST_REMOVE(&s->sec_bus, sibling); > - pci_bridge_region_del(s, s->windows); > - pci_bridge_region_cleanup(s, s->windows); > - memory_region_destroy(&s->address_space_mem); > - memory_region_destroy(&s->address_space_io); > - /* qbus_free() is called automatically by qdev_free() */ > -} > - > -/* > - * before qdev initialization(qdev_init()), this function sets bus_name and > - * map_irq callback which are necessry for pci_bridge_initfn() to > - * initialize bus. > - */ > -void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, > - pci_map_irq_fn map_irq) > -{ > - br->map_irq = map_irq; > - br->bus_name = bus_name; > -} > diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h > deleted file mode 100644 > index a00accc..0000000 > --- a/hw/pci_bridge.h > +++ /dev/null > @@ -1,66 +0,0 @@ > -/* > - * QEMU PCI bridge > - * > - * Copyright (c) 2004 Fabrice Bellard > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - * > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - * You should have received a copy of the GNU General Public License > - * along with this program; if not, write to the Free Software > - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > - * > - * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc] > - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - */ > - > -#ifndef QEMU_PCI_BRIDGE_H > -#define QEMU_PCI_BRIDGE_H > - > -#include "pci.h" > - > -int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, > - uint16_t svid, uint16_t ssid); > - > -PCIDevice *pci_bridge_get_device(PCIBus *bus); > -PCIBus *pci_bridge_get_sec_bus(PCIBridge *br); > - > -pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type); > -pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type); > - > -void pci_bridge_write_config(PCIDevice *d, > - uint32_t address, uint32_t val, int len); > -void pci_bridge_disable_base_limit(PCIDevice *dev); > -void pci_bridge_reset_reg(PCIDevice *dev); > -void pci_bridge_reset(DeviceState *qdev); > - > -int pci_bridge_initfn(PCIDevice *pci_dev); > -void pci_bridge_exitfn(PCIDevice *pci_dev); > - > - > -/* > - * before qdev initialization(qdev_init()), this function sets bus_name and > - * map_irq callback which are necessry for pci_bridge_initfn() to > - * initialize bus. > - */ > -void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, > - pci_map_irq_fn map_irq); > - > -#endif /* QEMU_PCI_BRIDGE_H */ > -/* > - * Local variables: > - * c-indent-level: 4 > - * c-basic-offset: 4 > - * tab-width: 8 > - * indent-tab-mode: nil > - * End: > - */ > diff --git a/hw/pci_host.c b/hw/pci_host.c > deleted file mode 100644 > index 68e328c..0000000 > --- a/hw/pci_host.c > +++ /dev/null > @@ -1,180 +0,0 @@ > -/* > - * pci_host.c > - * > - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#include "pci.h" > -#include "pci_host.h" > - > -/* debug PCI */ > -//#define DEBUG_PCI > - > -#ifdef DEBUG_PCI > -#define PCI_DPRINTF(fmt, ...) \ > -do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0) > -#else > -#define PCI_DPRINTF(fmt, ...) > -#endif > - > -/* > - * PCI address > - * bit 16 - 24: bus number > - * bit 8 - 15: devfun number > - * bit 0 - 7: offset in configuration space of a given pci device > - */ > - > -/* the helper functio to get a PCIDeice* for a given pci address */ > -static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr) > -{ > - uint8_t bus_num = addr >> 16; > - uint8_t devfn = addr >> 8; > - > - return pci_find_device(bus, bus_num, devfn); > -} > - > -void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, > - uint32_t limit, uint32_t val, uint32_t len) > -{ > - assert(len <= 4); > - pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr)); > -} > - > -uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, > - uint32_t limit, uint32_t len) > -{ > - assert(len <= 4); > - return pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr)); > -} > - > -void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len) > -{ > - PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); > - uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); > - > - if (!pci_dev) { > - return; > - } > - > - PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n", > - __func__, pci_dev->name, config_addr, val, len); > - pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE, > - val, len); > -} > - > -uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) > -{ > - PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); > - uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); > - uint32_t val; > - > - if (!pci_dev) { > - return ~0x0; > - } > - > - val = pci_host_config_read_common(pci_dev, config_addr, > - PCI_CONFIG_SPACE_SIZE, len); > - PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n", > - __func__, pci_dev->name, config_addr, val, len); > - > - return val; > -} > - > -static void pci_host_config_write(void *opaque, hwaddr addr, > - uint64_t val, unsigned len) > -{ > - PCIHostState *s = opaque; > - > - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", > - __func__, addr, len, val); > - if (addr != 0 || len != 4) { > - return; > - } > - s->config_reg = val; > -} > - > -static uint64_t pci_host_config_read(void *opaque, hwaddr addr, > - unsigned len) > -{ > - PCIHostState *s = opaque; > - uint32_t val = s->config_reg; > - > - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n", > - __func__, addr, len, val); > - return val; > -} > - > -static void pci_host_data_write(void *opaque, hwaddr addr, > - uint64_t val, unsigned len) > -{ > - PCIHostState *s = opaque; > - PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n", > - addr, len, (unsigned)val); > - if (s->config_reg & (1u << 31)) > - pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); > -} > - > -static uint64_t pci_host_data_read(void *opaque, > - hwaddr addr, unsigned len) > -{ > - PCIHostState *s = opaque; > - uint32_t val; > - if (!(s->config_reg & (1 << 31))) > - return 0xffffffff; > - val = pci_data_read(s->bus, s->config_reg | (addr & 3), len); > - PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n", > - addr, len, val); > - return val; > -} > - > -const MemoryRegionOps pci_host_conf_le_ops = { > - .read = pci_host_config_read, > - .write = pci_host_config_write, > - .endianness = DEVICE_LITTLE_ENDIAN, > -}; > - > -const MemoryRegionOps pci_host_conf_be_ops = { > - .read = pci_host_config_read, > - .write = pci_host_config_write, > - .endianness = DEVICE_BIG_ENDIAN, > -}; > - > -const MemoryRegionOps pci_host_data_le_ops = { > - .read = pci_host_data_read, > - .write = pci_host_data_write, > - .endianness = DEVICE_LITTLE_ENDIAN, > -}; > - > -const MemoryRegionOps pci_host_data_be_ops = { > - .read = pci_host_data_read, > - .write = pci_host_data_write, > - .endianness = DEVICE_BIG_ENDIAN, > -}; > - > -static const TypeInfo pci_host_type_info = { > - .name = TYPE_PCI_HOST_BRIDGE, > - .parent = TYPE_SYS_BUS_DEVICE, > - .abstract = true, > - .instance_size = sizeof(PCIHostState), > -}; > - > -static void pci_host_register_types(void) > -{ > - type_register_static(&pci_host_type_info); > -} > - > -type_init(pci_host_register_types) > diff --git a/hw/pci_host.h b/hw/pci_host.h > deleted file mode 100644 > index 4b9c300..0000000 > --- a/hw/pci_host.h > +++ /dev/null > @@ -1,62 +0,0 @@ > -/* > - * QEMU Common PCI Host bridge configuration data space access routines. > - * > - * Copyright (c) 2006 Fabrice Bellard > - * > - * Permission is hereby granted, free of charge, to any person obtaining a copy > - * of this software and associated documentation files (the "Software"), to deal > - * in the Software without restriction, including without limitation the rights > - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > - * copies of the Software, and to permit persons to whom the Software is > - * furnished to do so, subject to the following conditions: > - * > - * The above copyright notice and this permission notice shall be included in > - * all copies or substantial portions of the Software. > - * > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > - * THE SOFTWARE. > - */ > - > -/* Worker routines for a PCI host controller that uses an {address,data} > - register pair to access PCI configuration space. */ > - > -#ifndef PCI_HOST_H > -#define PCI_HOST_H > - > -#include "sysbus.h" > - > -#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge" > -#define PCI_HOST_BRIDGE(obj) \ > - OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE) > - > -struct PCIHostState { > - SysBusDevice busdev; > - > - MemoryRegion conf_mem; > - MemoryRegion data_mem; > - MemoryRegion mmcfg; > - MemoryRegion *address_space; > - uint32_t config_reg; > - PCIBus *bus; > -}; > - > -/* common internal helpers for PCI/PCIe hosts, cut off overflows */ > -void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, > - uint32_t limit, uint32_t val, uint32_t len); > -uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, > - uint32_t limit, uint32_t len); > - > -void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len); > -uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len); > - > -extern const MemoryRegionOps pci_host_conf_le_ops; > -extern const MemoryRegionOps pci_host_conf_be_ops; > -extern const MemoryRegionOps pci_host_data_le_ops; > -extern const MemoryRegionOps pci_host_data_be_ops; > - > -#endif /* PCI_HOST_H */ > diff --git a/hw/pci_ids.h b/hw/pci_ids.h > deleted file mode 100644 > index 5df7245..0000000 > --- a/hw/pci_ids.h > +++ /dev/null > @@ -1,147 +0,0 @@ > -/* > - * PCI Class, Vendor and Device IDs > - * > - * Please keep sorted. > - * > - * Abbreviated version of linux/pci_ids.h > - * > - * QEMU-specific definitions belong in pci.h > - */ > - > -/* Device classes and subclasses */ > - > -#define PCI_BASE_CLASS_STORAGE 0x01 > -#define PCI_BASE_CLASS_NETWORK 0x02 > - > -#define PCI_CLASS_STORAGE_SCSI 0x0100 > -#define PCI_CLASS_STORAGE_IDE 0x0101 > -#define PCI_CLASS_STORAGE_RAID 0x0104 > -#define PCI_CLASS_STORAGE_SATA 0x0106 > -#define PCI_CLASS_STORAGE_OTHER 0x0180 > - > -#define PCI_CLASS_NETWORK_ETHERNET 0x0200 > - > -#define PCI_CLASS_DISPLAY_VGA 0x0300 > -#define PCI_CLASS_DISPLAY_OTHER 0x0380 > - > -#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 > - > -#define PCI_CLASS_MEMORY_RAM 0x0500 > - > -#define PCI_CLASS_SYSTEM_OTHER 0x0880 > - > -#define PCI_CLASS_SERIAL_USB 0x0c03 > -#define PCI_CLASS_SERIAL_SMBUS 0x0c05 > - > -#define PCI_CLASS_BRIDGE_HOST 0x0600 > -#define PCI_CLASS_BRIDGE_ISA 0x0601 > -#define PCI_CLASS_BRIDGE_PCI 0x0604 > -#define PCI_CLASS_BRDIGE_PCI_INF_SUB 0x01 > -#define PCI_CLASS_BRIDGE_OTHER 0x0680 > - > -#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 > -#define PCI_CLASS_COMMUNICATION_OTHER 0x0780 > - > -#define PCI_CLASS_PROCESSOR_CO 0x0b40 > -#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20 > - > -#define PCI_CLASS_OTHERS 0xff > - > -/* Vendors and devices. Sort key: vendor first, device next. */ > - > -#define PCI_VENDOR_ID_LSI_LOGIC 0x1000 > -#define PCI_DEVICE_ID_LSI_53C895A 0x0012 > -#define PCI_DEVICE_ID_LSI_SAS1078 0x0060 > - > -#define PCI_VENDOR_ID_DEC 0x1011 > -#define PCI_DEVICE_ID_DEC_21154 0x0026 > - > -#define PCI_VENDOR_ID_CIRRUS 0x1013 > - > -#define PCI_VENDOR_ID_IBM 0x1014 > - > -#define PCI_VENDOR_ID_AMD 0x1022 > -#define PCI_DEVICE_ID_AMD_LANCE 0x2000 > -#define PCI_DEVICE_ID_AMD_SCSI 0x2020 > - > -#define PCI_VENDOR_ID_TI 0x104c > - > -#define PCI_VENDOR_ID_MOTOROLA 0x1057 > -#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 > -#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 > - > -#define PCI_VENDOR_ID_APPLE 0x106b > -#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 > -#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b > - > -#define PCI_VENDOR_ID_SUN 0x108e > -#define PCI_DEVICE_ID_SUN_EBUS 0x1000 > -#define PCI_DEVICE_ID_SUN_SIMBA 0x5000 > -#define PCI_DEVICE_ID_SUN_SABRE 0xa000 > - > -#define PCI_VENDOR_ID_CMD 0x1095 > -#define PCI_DEVICE_ID_CMD_646 0x0646 > - > -#define PCI_VENDOR_ID_REALTEK 0x10ec > -#define PCI_DEVICE_ID_REALTEK_8139 0x8139 > - > -#define PCI_VENDOR_ID_XILINX 0x10ee > - > -#define PCI_VENDOR_ID_VIA 0x1106 > -#define PCI_DEVICE_ID_VIA_ISA_BRIDGE 0x0686 > -#define PCI_DEVICE_ID_VIA_IDE 0x0571 > -#define PCI_DEVICE_ID_VIA_UHCI 0x3038 > -#define PCI_DEVICE_ID_VIA_ACPI 0x3057 > -#define PCI_DEVICE_ID_VIA_AC97 0x3058 > -#define PCI_DEVICE_ID_VIA_MC97 0x3068 > - > -#define PCI_VENDOR_ID_MARVELL 0x11ab > - > -#define PCI_VENDOR_ID_ENSONIQ 0x1274 > -#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 > - > -#define PCI_VENDOR_ID_FREESCALE 0x1957 > -#define PCI_DEVICE_ID_MPC8533E 0x0030 > - > -#define PCI_VENDOR_ID_INTEL 0x8086 > -#define PCI_DEVICE_ID_INTEL_82378 0x0484 > -#define PCI_DEVICE_ID_INTEL_82441 0x1237 > -#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 > -#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e > -#define PCI_DEVICE_ID_INTEL_82801D 0x24CD > -#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab > -#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 > -#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 > -#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 > -#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 > -#define PCI_DEVICE_ID_INTEL_82371AB 0x7111 > -#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 > -#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 > - > -#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 > -#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 > -#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 > -#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 > -#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 > -#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 > -#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 > -#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 > -#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 > - > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934 > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935 > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936 > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937 > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938 > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939 > -#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a > -#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c > -#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed > - > -#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 > - > -#define PCI_VENDOR_ID_XEN 0x5853 > -#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 > - > -#define PCI_VENDOR_ID_NEC 0x1033 > -#define PCI_DEVICE_ID_NEC_UPD720200 0x0194 > diff --git a/hw/pci_internals.h b/hw/pci_internals.h > deleted file mode 100644 > index 21d0ce6..0000000 > --- a/hw/pci_internals.h > +++ /dev/null > @@ -1,78 +0,0 @@ > -#ifndef QEMU_PCI_INTERNALS_H > -#define QEMU_PCI_INTERNALS_H > - > -/* > - * This header files is private to pci.c and pci_bridge.c > - * So following structures are opaque to others and shouldn't be > - * accessed. > - * > - * For pci-to-pci bridge needs to include this header file to embed > - * PCIBridge in its structure or to get sizeof(PCIBridge), > - * However, they shouldn't access those following members directly. > - * Use accessor function in pci.h, pci_bridge.h > - */ > - > -#define TYPE_PCI_BUS "PCI" > -#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) > - > -struct PCIBus { > - BusState qbus; > - PCIDMAContextFunc dma_context_fn; > - void *dma_context_opaque; > - uint8_t devfn_min; > - pci_set_irq_fn set_irq; > - pci_map_irq_fn map_irq; > - pci_route_irq_fn route_intx_to_irq; > - pci_hotplug_fn hotplug; > - DeviceState *hotplug_qdev; > - void *irq_opaque; > - PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; > - PCIDevice *parent_dev; > - MemoryRegion *address_space_mem; > - MemoryRegion *address_space_io; > - > - QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ > - QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ > - > - /* The bus IRQ state is the logical OR of the connected devices. > - Keep a count of the number of devices with raised IRQs. */ > - int nirq; > - int *irq_count; > -}; > - > -typedef struct PCIBridgeWindows PCIBridgeWindows; > - > -/* > - * Aliases for each of the address space windows that the bridge > - * can forward. Mapped into the bridge's parent's address space, > - * as subregions. > - */ > -struct PCIBridgeWindows { > - MemoryRegion alias_pref_mem; > - MemoryRegion alias_mem; > - MemoryRegion alias_io; > -}; > - > -struct PCIBridge { > - PCIDevice dev; > - > - /* private member */ > - PCIBus sec_bus; > - /* > - * Memory regions for the bridge's address spaces. These regions are not > - * directly added to system_memory/system_io or its descendants. > - * Bridge's secondary bus points to these, so that devices > - * under the bridge see these regions as its address spaces. > - * The regions are as large as the entire address space - > - * they don't take into account any windows. > - */ > - MemoryRegion address_space_mem; > - MemoryRegion address_space_io; > - > - PCIBridgeWindows *windows; > - > - pci_map_irq_fn map_irq; > - const char *bus_name; > -}; > - > -#endif /* QEMU_PCI_INTERNALS_H */ > diff --git a/hw/pci_regs.h b/hw/pci_regs.h > deleted file mode 100644 > index 56a404b..0000000 > --- a/hw/pci_regs.h > +++ /dev/null > @@ -1,717 +0,0 @@ > -/* > - * pci_regs.h > - * > - * PCI standard defines > - * Copyright 1994, Drew Eckhardt > - * Copyright 1997--1999 Martin Mares <mj@ucw.cz> > - * > - * For more information, please consult the following manuals (look at > - * http://www.pcisig.com/ for how to get them): > - * > - * PCI BIOS Specification > - * PCI Local Bus Specification > - * PCI to PCI Bridge Specification > - * PCI System Design Guide > - * > - * For hypertransport information, please consult the following manuals > - * from http://www.hypertransport.org > - * > - * The Hypertransport I/O Link Specification > - */ > - > -#ifndef LINUX_PCI_REGS_H > -#define LINUX_PCI_REGS_H > - > -/* > - * Under PCI, each device has 256 bytes of configuration address space, > - * of which the first 64 bytes are standardized as follows: > - */ > -#define PCI_VENDOR_ID 0x00 /* 16 bits */ > -#define PCI_DEVICE_ID 0x02 /* 16 bits */ > -#define PCI_COMMAND 0x04 /* 16 bits */ > -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ > -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ > -#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ > -#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ > -#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ > -#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ > -#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ > -#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ > -#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ > -#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ > -#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ > - > -#define PCI_STATUS 0x06 /* 16 bits */ > -#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */ > -#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ > -#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ > -#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ > -#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ > -#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ > -#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ > -#define PCI_STATUS_DEVSEL_FAST 0x000 > -#define PCI_STATUS_DEVSEL_MEDIUM 0x200 > -#define PCI_STATUS_DEVSEL_SLOW 0x400 > -#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ > -#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ > -#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ > -#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ > -#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ > - > -#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ > -#define PCI_REVISION_ID 0x08 /* Revision ID */ > -#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ > -#define PCI_CLASS_DEVICE 0x0a /* Device class */ > - > -#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ > -#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ > -#define PCI_HEADER_TYPE 0x0e /* 8 bits */ > -#define PCI_HEADER_TYPE_NORMAL 0 > -#define PCI_HEADER_TYPE_BRIDGE 1 > -#define PCI_HEADER_TYPE_CARDBUS 2 > - > -#define PCI_BIST 0x0f /* 8 bits */ > -#define PCI_BIST_CODE_MASK 0x0f /* Return result */ > -#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ > -#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ > - > -/* > - * Base addresses specify locations in memory or I/O space. > - * Decoded size can be determined by writing a value of > - * 0xffffffff to the register, and reading it back. Only > - * 1 bits are decoded. > - */ > -#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ > -#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ > -#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ > -#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ > -#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ > -#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ > -#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ > -#define PCI_BASE_ADDRESS_SPACE_IO 0x01 > -#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 > -#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 > -#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ > -#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ > -#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ > -#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ > -#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) > -#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) > -/* bit 1 is reserved if address_space = 1 */ > - > -/* Header type 0 (normal devices) */ > -#define PCI_CARDBUS_CIS 0x28 > -#define PCI_SUBSYSTEM_VENDOR_ID 0x2c > -#define PCI_SUBSYSTEM_ID 0x2e > -#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ > -#define PCI_ROM_ADDRESS_ENABLE 0x01 > -#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) > - > -#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ > - > -/* 0x35-0x3b are reserved */ > -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ > -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ > -#define PCI_MIN_GNT 0x3e /* 8 bits */ > -#define PCI_MAX_LAT 0x3f /* 8 bits */ > - > -/* Header type 1 (PCI-to-PCI bridges) */ > -#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ > -#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ > -#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ > -#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ > -#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ > -#define PCI_IO_LIMIT 0x1d > -#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ > -#define PCI_IO_RANGE_TYPE_16 0x00 > -#define PCI_IO_RANGE_TYPE_32 0x01 > -#define PCI_IO_RANGE_MASK (~0x0fUL) > -#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ > -#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ > -#define PCI_MEMORY_LIMIT 0x22 > -#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL > -#define PCI_MEMORY_RANGE_MASK (~0x0fUL) > -#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ > -#define PCI_PREF_MEMORY_LIMIT 0x26 > -#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL > -#define PCI_PREF_RANGE_TYPE_32 0x00 > -#define PCI_PREF_RANGE_TYPE_64 0x01 > -#define PCI_PREF_RANGE_MASK (~0x0fUL) > -#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ > -#define PCI_PREF_LIMIT_UPPER32 0x2c > -#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ > -#define PCI_IO_LIMIT_UPPER16 0x32 > -/* 0x34 same as for htype 0 */ > -/* 0x35-0x3b is reserved */ > -#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ > -/* 0x3c-0x3d are same as for htype 0 */ > -#define PCI_BRIDGE_CONTROL 0x3e > -#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ > -#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ > -#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */ > -#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ > -#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ > -#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ > -#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ > - > -/* Header type 2 (CardBus bridges) */ > -#define PCI_CB_CAPABILITY_LIST 0x14 > -/* 0x15 reserved */ > -#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */ > -#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */ > -#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */ > -#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */ > -#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ > -#define PCI_CB_MEMORY_BASE_0 0x1c > -#define PCI_CB_MEMORY_LIMIT_0 0x20 > -#define PCI_CB_MEMORY_BASE_1 0x24 > -#define PCI_CB_MEMORY_LIMIT_1 0x28 > -#define PCI_CB_IO_BASE_0 0x2c > -#define PCI_CB_IO_BASE_0_HI 0x2e > -#define PCI_CB_IO_LIMIT_0 0x30 > -#define PCI_CB_IO_LIMIT_0_HI 0x32 > -#define PCI_CB_IO_BASE_1 0x34 > -#define PCI_CB_IO_BASE_1_HI 0x36 > -#define PCI_CB_IO_LIMIT_1 0x38 > -#define PCI_CB_IO_LIMIT_1_HI 0x3a > -#define PCI_CB_IO_RANGE_MASK (~0x03UL) > -/* 0x3c-0x3d are same as for htype 0 */ > -#define PCI_CB_BRIDGE_CONTROL 0x3e > -#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */ > -#define PCI_CB_BRIDGE_CTL_SERR 0x02 > -#define PCI_CB_BRIDGE_CTL_ISA 0x04 > -#define PCI_CB_BRIDGE_CTL_VGA 0x08 > -#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20 > -#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */ > -#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */ > -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */ > -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200 > -#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400 > -#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 > -#define PCI_CB_SUBSYSTEM_ID 0x42 > -#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */ > -/* 0x48-0x7f reserved */ > - > -/* Capability lists */ > - > -#define PCI_CAP_LIST_ID 0 /* Capability ID */ > -#define PCI_CAP_ID_PM 0x01 /* Power Management */ > -#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ > -#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ > -#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ > -#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ > -#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ > -#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ > -#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ > -#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */ > -#define PCI_CAP_ID_DBG 0x0A /* Debug port */ > -#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ > -#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ > -#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ > -#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ > -#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ > -#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ > -#define PCI_CAP_ID_SATA 0x12 /* Serial ATA */ > -#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ > -#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ > -#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ > -#define PCI_CAP_SIZEOF 4 > - > -/* Power Management Registers */ > - > -#define PCI_PM_PMC 2 /* PM Capabilities Register */ > -#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ > -#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ > -#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ > -#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ > -#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */ > -#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ > -#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ > -#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ > -#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ > -#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ > -#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ > -#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ > -#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ > -#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ > -#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */ > -#define PCI_PM_CTRL 4 /* PM control and status register */ > -#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ > -#define PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */ > -#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ > -#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ > -#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ > -#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ > -#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ > -#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ > -#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ > -#define PCI_PM_DATA_REGISTER 7 /* (??) */ > -#define PCI_PM_SIZEOF 8 > - > -/* AGP registers */ > - > -#define PCI_AGP_VERSION 2 /* BCD version number */ > -#define PCI_AGP_RFU 3 /* Rest of capability flags */ > -#define PCI_AGP_STATUS 4 /* Status register */ > -#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ > -#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ > -#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ > -#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ > -#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ > -#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ > -#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ > -#define PCI_AGP_COMMAND 8 /* Control register */ > -#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ > -#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ > -#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ > -#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ > -#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ > -#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ > -#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ > -#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ > -#define PCI_AGP_SIZEOF 12 > - > -/* Vital Product Data */ > - > -#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */ > -#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */ > -#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */ > -#define PCI_VPD_DATA 4 /* 32-bits of data returned here */ > - > -/* Slot Identification */ > - > -#define PCI_SID_ESR 2 /* Expansion Slot Register */ > -#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ > -#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ > -#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ > - > -/* Message Signalled Interrupts registers */ > - > -#define PCI_MSI_FLAGS 2 /* Various flags */ > -#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */ > -#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */ > -#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */ > -#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */ > -#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */ > -#define PCI_MSI_RFU 3 /* Rest of capability flags */ > -#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ > -#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ > -#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ > -#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */ > -#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ > -#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ > - > -/* MSI-X registers */ > -#define PCI_MSIX_FLAGS 2 > -#define PCI_MSIX_FLAGS_QSIZE 0x7FF > -#define PCI_MSIX_FLAGS_ENABLE (1 << 15) > -#define PCI_MSIX_FLAGS_MASKALL (1 << 14) > -#define PCI_MSIX_TABLE 4 > -#define PCI_MSIX_PBA 8 > -#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) > - > -/* MSI-X entry's format */ > -#define PCI_MSIX_ENTRY_SIZE 16 > -#define PCI_MSIX_ENTRY_LOWER_ADDR 0 > -#define PCI_MSIX_ENTRY_UPPER_ADDR 4 > -#define PCI_MSIX_ENTRY_DATA 8 > -#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 > -#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 > - > -/* CompactPCI Hotswap Register */ > - > -#define PCI_CHSWP_CSR 2 /* Control and Status Register */ > -#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */ > -#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */ > -#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */ > -#define PCI_CHSWP_LOO 0x08 /* LED On / Off */ > -#define PCI_CHSWP_PI 0x30 /* Programming Interface */ > -#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ > -#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ > - > -/* PCI Advanced Feature registers */ > - > -#define PCI_AF_LENGTH 2 > -#define PCI_AF_CAP 3 > -#define PCI_AF_CAP_TP 0x01 > -#define PCI_AF_CAP_FLR 0x02 > -#define PCI_AF_CTRL 4 > -#define PCI_AF_CTRL_FLR 0x01 > -#define PCI_AF_STATUS 5 > -#define PCI_AF_STATUS_TP 0x01 > - > -/* PCI-X registers */ > - > -#define PCI_X_CMD 2 /* Modes & Features */ > -#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ > -#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ > -#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ > -#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ > -#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ > -#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ > -#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ > - /* Max # of outstanding split transactions */ > -#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */ > -#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */ > -#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */ > -#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */ > -#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */ > -#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */ > -#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */ > -#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */ > -#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ > -#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */ > -#define PCI_X_STATUS 4 /* PCI-X capabilities */ > -#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */ > -#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */ > -#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */ > -#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */ > -#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */ > -#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */ > -#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */ > -#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count */ > -#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */ > -#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */ > -#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ > -#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ > -#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ > - > -/* PCI Bridge Subsystem ID registers */ > - > -#define PCI_SSVID_VENDOR_ID 4 /* PCI-Bridge subsystem vendor id register */ > -#define PCI_SSVID_DEVICE_ID 6 /* PCI-Bridge subsystem device id register */ > - > -/* PCI Express capability registers */ > - > -#define PCI_EXP_FLAGS 2 /* Capabilities register */ > -#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ > -#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ > -#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ > -#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ > -#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ > -#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ > -#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ > -#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ > -#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */ > -#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ > -#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ > -#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ > -#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ > -#define PCI_EXP_DEVCAP 4 /* Device capabilities */ > -#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */ > -#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */ > -#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */ > -#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */ > -#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */ > -#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ > -#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ > -#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ > -#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ > -#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ > -#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ > -#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ > -#define PCI_EXP_DEVCTL 8 /* Device Control */ > -#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ > -#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ > -#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ > -#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ > -#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */ > -#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ > -#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ > -#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ > -#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ > -#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ > -#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ > -#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ > -#define PCI_EXP_DEVSTA 10 /* Device Status */ > -#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ > -#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ > -#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */ > -#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */ > -#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ > -#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ > -#define PCI_EXP_LNKCAP 12 /* Link Capabilities */ > -#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */ > -#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */ > -#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */ > -#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */ > -#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */ > -#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* L1 Clock Power Management */ > -#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Reporting Capable */ > -#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link Active Reporting Capable */ > -#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notification Capability */ > -#define PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */ > -#define PCI_EXP_LNKCTL 16 /* Link Control */ > -#define PCI_EXP_LNKCTL_ASPMC 0x0003 /* ASPM Control */ > -#define PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */ > -#define PCI_EXP_LNKCTL_LD 0x0010 /* Link Disable */ > -#define PCI_EXP_LNKCTL_RL 0x0020 /* Retrain Link */ > -#define PCI_EXP_LNKCTL_CCC 0x0040 /* Common Clock Configuration */ > -#define PCI_EXP_LNKCTL_ES 0x0080 /* Extended Synch */ > -#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ > -#define PCI_EXP_LNKCTL_HAWD 0x0200 /* Hardware Autonomous Width Disable */ > -#define PCI_EXP_LNKCTL_LBMIE 0x0400 /* Link Bandwidth Management Interrupt Enable */ > -#define PCI_EXP_LNKCTL_LABIE 0x0800 /* Lnk Autonomous Bandwidth Interrupt Enable */ > -#define PCI_EXP_LNKSTA 18 /* Link Status */ > -#define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */ > -#define PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */ > -#define PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */ > -#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Nogotiated Link Width */ > -#define PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */ > -#define PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */ > -#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ > -#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ > -#define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ > -#define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */ > -#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ > -#define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */ > -#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */ > -#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */ > -#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Present */ > -#define PCI_EXP_SLTCAP_PIP 0x00000010 /* Power Indicator Present */ > -#define PCI_EXP_SLTCAP_HPS 0x00000020 /* Hot-Plug Surprise */ > -#define PCI_EXP_SLTCAP_HPC 0x00000040 /* Hot-Plug Capable */ > -#define PCI_EXP_SLTCAP_SPLV 0x00007f80 /* Slot Power Limit Value */ > -#define PCI_EXP_SLTCAP_SPLS 0x00018000 /* Slot Power Limit Scale */ > -#define PCI_EXP_SLTCAP_EIP 0x00020000 /* Electromechanical Interlock Present */ > -#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Support */ > -#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ > -#define PCI_EXP_SLTCTL 24 /* Slot Control */ > -#define PCI_EXP_SLTCTL_ABPE 0x0001 /* Attention Button Pressed Enable */ > -#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enable */ > -#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable */ > -#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed Enable */ > -#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable */ > -#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */ > -#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */ > -#define PCI_EXP_SLTCTL_PIC 0x0300 /* Power Indicator Control */ > -#define PCI_EXP_SLTCTL_PCC 0x0400 /* Power Controller Control */ > -#define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */ > -#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */ > -#define PCI_EXP_SLTSTA 26 /* Slot Status */ > -#define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */ > -#define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */ > -#define PCI_EXP_SLTSTA_MRLSC 0x0004 /* MRL Sensor Changed */ > -#define PCI_EXP_SLTSTA_PDC 0x0008 /* Presence Detect Changed */ > -#define PCI_EXP_SLTSTA_CC 0x0010 /* Command Completed */ > -#define PCI_EXP_SLTSTA_MRLSS 0x0020 /* MRL Sensor State */ > -#define PCI_EXP_SLTSTA_PDS 0x0040 /* Presence Detect State */ > -#define PCI_EXP_SLTSTA_EIS 0x0080 /* Electromechanical Interlock Status */ > -#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Changed */ > -#define PCI_EXP_RTCTL 28 /* Root Control */ > -#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctable Error */ > -#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal Error */ > -#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Error */ > -#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */ > -#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */ > -#define PCI_EXP_RTCAP 30 /* Root Capabilities */ > -#define PCI_EXP_RTSTA 32 /* Root Status */ > -#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ > -#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ > -#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ > -#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ > -#define PCI_EXP_DEVCAP2_LTR 0x800 /* Latency tolerance reporting */ > -#define PCI_EXP_OBFF_MASK 0xc0000 /* OBFF support mechanism */ > -#define PCI_EXP_OBFF_MSG 0x40000 /* New message signaling */ > -#define PCI_EXP_OBFF_WAKE 0x80000 /* Re-use WAKE# for OBFF */ > -#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ > -#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */ > -#define PCI_EXP_IDO_REQ_EN 0x100 /* ID-based ordering request enable */ > -#define PCI_EXP_IDO_CMP_EN 0x200 /* ID-based ordering completion enable */ > -#define PCI_EXP_LTR_EN 0x400 /* Latency tolerance reporting */ > -#define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message type A */ > -#define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message type B */ > -#define PCI_EXP_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ > -#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ > -#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ > - > -/* Extended Capabilities (PCI-X 2.0 and Express) */ > -#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff) > -#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf) > -#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc) > - > -#define PCI_EXT_CAP_ID_ERR 1 > -#define PCI_EXT_CAP_ID_VC 2 > -#define PCI_EXT_CAP_ID_DSN 3 > -#define PCI_EXT_CAP_ID_PWR 4 > -#define PCI_EXT_CAP_ID_VNDR 11 > -#define PCI_EXT_CAP_ID_ACS 13 > -#define PCI_EXT_CAP_ID_ARI 14 > -#define PCI_EXT_CAP_ID_ATS 15 > -#define PCI_EXT_CAP_ID_SRIOV 16 > -#define PCI_EXT_CAP_ID_LTR 24 > - > -/* Advanced Error Reporting */ > -#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ > -#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */ > -#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ > -#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */ > -#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */ > -#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */ > -#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */ > -#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */ > -#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */ > -#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */ > -#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */ > -#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */ > -#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */ > - /* Same bits as above */ > -#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */ > - /* Same bits as above */ > -#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */ > -#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */ > -#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */ > -#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */ > -#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */ > -#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */ > -#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ > - /* Same bits as above */ > -#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ > -#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */ > -#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */ > -#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */ > -#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */ > -#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ > -#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */ > -#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */ > -/* Correctable Err Reporting Enable */ > -#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 > -/* Non-fatal Err Reporting Enable */ > -#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 > -/* Fatal Err Reporting Enable */ > -#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 > -#define PCI_ERR_ROOT_STATUS 48 > -#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ > -/* Multi ERR_COR Received */ > -#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 > -/* ERR_FATAL/NONFATAL Recevied */ > -#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 > -/* Multi ERR_FATAL/NONFATAL Recevied */ > -#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 > -#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */ > -#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ > -#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ > -#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */ > - > -/* Virtual Channel */ > -#define PCI_VC_PORT_REG1 4 > -#define PCI_VC_PORT_REG2 8 > -#define PCI_VC_PORT_CTRL 12 > -#define PCI_VC_PORT_STATUS 14 > -#define PCI_VC_RES_CAP 16 > -#define PCI_VC_RES_CTRL 20 > -#define PCI_VC_RES_STATUS 26 > - > -/* Power Budgeting */ > -#define PCI_PWR_DSR 4 /* Data Select Register */ > -#define PCI_PWR_DATA 8 /* Data Register */ > -#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */ > -#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */ > -#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */ > -#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */ > -#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */ > -#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */ > -#define PCI_PWR_CAP 12 /* Capability */ > -#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ > - > -/* > - * Hypertransport sub capability types > - * > - * Unfortunately there are both 3 bit and 5 bit capability types defined > - * in the HT spec, catering for that is a little messy. You probably don't > - * want to use these directly, just use pci_find_ht_capability() and it > - * will do the right thing for you. > - */ > -#define HT_3BIT_CAP_MASK 0xE0 > -#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ > -#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ > - > -#define HT_5BIT_CAP_MASK 0xF8 > -#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ > -#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ > -#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ > -#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */ > -#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */ > -#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */ > -#define HT_MSI_FLAGS 0x02 /* Offset to flags */ > -#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */ > -#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */ > -#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */ > -#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */ > -#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */ > -#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */ > -#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */ > -#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */ > -#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */ > -#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */ > -#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */ > - > -/* Alternative Routing-ID Interpretation */ > -#define PCI_ARI_CAP 0x04 /* ARI Capability Register */ > -#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */ > -#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */ > -#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */ > -#define PCI_ARI_CTRL 0x06 /* ARI Control Register */ > -#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */ > -#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ > -#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ > - > -/* Address Translation Service */ > -#define PCI_ATS_CAP 0x04 /* ATS Capability Register */ > -#define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f) /* Invalidate Queue Depth */ > -#define PCI_ATS_MAX_QDEP 32 /* Max Invalidate Queue Depth */ > -#define PCI_ATS_CTRL 0x06 /* ATS Control Register */ > -#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */ > -#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */ > -#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */ > - > -/* Single Root I/O Virtualization */ > -#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ > -#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ > -#define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */ > -#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */ > -#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */ > -#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */ > -#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */ > -#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */ > -#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */ > -#define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */ > -#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */ > -#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */ > -#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */ > -#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */ > -#define PCI_SRIOV_FUNC_LINK 0x12 /* Function Dependency Link */ > -#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */ > -#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */ > -#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */ > -#define PCI_SRIOV_SUP_PGSIZE 0x1c /* Supported Page Sizes */ > -#define PCI_SRIOV_SYS_PGSIZE 0x20 /* System Page Size */ > -#define PCI_SRIOV_BAR 0x24 /* VF BAR0 */ > -#define PCI_SRIOV_NUM_BARS 6 /* Number of VF BARs */ > -#define PCI_SRIOV_VFM 0x3c /* VF Migration State Array Offset*/ > -#define PCI_SRIOV_VFM_BIR(x) ((x) & 7) /* State BIR */ > -#define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7) /* State Offset */ > -#define PCI_SRIOV_VFM_UA 0x0 /* Inactive.Unavailable */ > -#define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */ > -#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ > -#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ > - > -#define PCI_LTR_MAX_SNOOP_LAT 0x4 > -#define PCI_LTR_MAX_NOSNOOP_LAT 0x6 > -#define PCI_LTR_VALUE_MASK 0x000003ff > -#define PCI_LTR_SCALE_MASK 0x00001c00 > -#define PCI_LTR_SCALE_SHIFT 10 > - > -/* Access Control Service */ > -#define PCI_ACS_CAP 0x04 /* ACS Capability Register */ > -#define PCI_ACS_SV 0x01 /* Source Validation */ > -#define PCI_ACS_TB 0x02 /* Translation Blocking */ > -#define PCI_ACS_RR 0x04 /* P2P Request Redirect */ > -#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */ > -#define PCI_ACS_UF 0x10 /* Upstream Forwarding */ > -#define PCI_ACS_EC 0x20 /* P2P Egress Control */ > -#define PCI_ACS_DT 0x40 /* Direct Translated P2P */ > -#define PCI_ACS_CTRL 0x06 /* ACS Control Register */ > -#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ > - > -#endif /* LINUX_PCI_REGS_H */ > diff --git a/hw/pcie.c b/hw/pcie.c > deleted file mode 100644 > index 7c92f19..0000000 > --- a/hw/pcie.c > +++ /dev/null > @@ -1,555 +0,0 @@ > -/* > - * pcie.c > - * > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - * > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#include "qemu-common.h" > -#include "pci_bridge.h" > -#include "pcie.h" > -#include "msix.h" > -#include "msi.h" > -#include "pci_internals.h" > -#include "pcie_regs.h" > -#include "range.h" > - > -//#define DEBUG_PCIE > -#ifdef DEBUG_PCIE > -# define PCIE_DPRINTF(fmt, ...) \ > - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > -#else > -# define PCIE_DPRINTF(fmt, ...) do {} while (0) > -#endif > -#define PCIE_DEV_PRINTF(dev, fmt, ...) \ > - PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > - > - > -/*************************************************************************** > - * pci express capability helper functions > - */ > -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) > -{ > - int pos; > - uint8_t *exp_cap; > - > - assert(pci_is_express(dev)); > - > - pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, > - PCI_EXP_VER2_SIZEOF); > - if (pos < 0) { > - return pos; > - } > - dev->exp.exp_cap = pos; > - exp_cap = dev->config + pos; > - > - /* capability register > - interrupt message number defaults to 0 */ > - pci_set_word(exp_cap + PCI_EXP_FLAGS, > - ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) | > - PCI_EXP_FLAGS_VER2); > - > - /* device capability register > - * table 7-12: > - * roll based error reporting bit must be set by all > - * Functions conforming to the ECN, PCI Express Base > - * Specification, Revision 1.1., or subsequent PCI Express Base > - * Specification revisions. > - */ > - pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER); > - > - pci_set_long(exp_cap + PCI_EXP_LNKCAP, > - (port << PCI_EXP_LNKCAP_PN_SHIFT) | > - PCI_EXP_LNKCAP_ASPMS_0S | > - PCI_EXP_LNK_MLW_1 | > - PCI_EXP_LNK_LS_25); > - > - pci_set_word(exp_cap + PCI_EXP_LNKSTA, > - PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25); > - > - pci_set_long(exp_cap + PCI_EXP_DEVCAP2, > - PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP); > - > - pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB); > - return pos; > -} > - > -void pcie_cap_exit(PCIDevice *dev) > -{ > - pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF); > -} > - > -uint8_t pcie_cap_get_type(const PCIDevice *dev) > -{ > - uint32_t pos = dev->exp.exp_cap; > - assert(pos > 0); > - return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) & > - PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT; > -} > - > -/* MSI/MSI-X */ > -/* pci express interrupt message number */ > -/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */ > -void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector) > -{ > - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > - assert(vector < 32); > - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ); > - pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS, > - vector << PCI_EXP_FLAGS_IRQ_SHIFT); > -} > - > -uint8_t pcie_cap_flags_get_vector(PCIDevice *dev) > -{ > - return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) & > - PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT; > -} > - > -void pcie_cap_deverr_init(PCIDevice *dev) > -{ > - uint32_t pos = dev->exp.exp_cap; > - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP, > - PCI_EXP_DEVCAP_RBER); > - pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL, > - PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | > - PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); > - pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA, > - PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED | > - PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD); > -} > - > -void pcie_cap_deverr_reset(PCIDevice *dev) > -{ > - uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; > - pci_long_test_and_clear_mask(devctl, > - PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | > - PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); > -} > - > -static void hotplug_event_update_event_status(PCIDevice *dev) > -{ > - uint32_t pos = dev->exp.exp_cap; > - uint8_t *exp_cap = dev->config + pos; > - uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL); > - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > - > - dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) && > - (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED); > -} > - > -static void hotplug_event_notify(PCIDevice *dev) > -{ > - bool prev = dev->exp.hpev_notified; > - > - hotplug_event_update_event_status(dev); > - > - if (prev == dev->exp.hpev_notified) { > - return; > - } > - > - /* Note: the logic above does not take into account whether interrupts > - * are masked. The result is that interrupt will be sent when it is > - * subsequently unmasked. This appears to be legal: Section 6.7.3.4: > - * The Port may optionally send an MSI when there are hot-plug events that > - * occur while interrupt generation is disabled, and interrupt generation is > - * subsequently enabled. */ > - if (msix_enabled(dev)) { > - msix_notify(dev, pcie_cap_flags_get_vector(dev)); > - } else if (msi_enabled(dev)) { > - msi_notify(dev, pcie_cap_flags_get_vector(dev)); > - } else { > - qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified); > - } > -} > - > -static void hotplug_event_clear(PCIDevice *dev) > -{ > - hotplug_event_update_event_status(dev); > - if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) { > - qemu_set_irq(dev->irq[dev->exp.hpev_intx], 0); > - } > -} > - > -/* > - * A PCI Express Hot-Plug Event has occurred, so update slot status register > - * and notify OS of the event if necessary. > - * > - * 6.7.3 PCI Express Hot-Plug Events > - * 6.7.3.4 Software Notification of Hot-Plug Events > - */ > -static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) > -{ > - /* Minor optimization: if nothing changed - no event is needed. */ > - if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap + > - PCI_EXP_SLTSTA, event)) { > - return; > - } > - hotplug_event_notify(dev); > -} > - > -static int pcie_cap_slot_hotplug(DeviceState *qdev, > - PCIDevice *pci_dev, PCIHotplugState state) > -{ > - PCIDevice *d = PCI_DEVICE(qdev); > - uint8_t *exp_cap = d->config + d->exp.exp_cap; > - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > - > - /* Don't send event when device is enabled during qemu machine creation: > - * it is present on boot, no hotplug event is necessary. We do send an > - * event when the device is disabled later. */ > - if (state == PCI_COLDPLUG_ENABLED) { > - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, > - PCI_EXP_SLTSTA_PDS); > - return 0; > - } > - > - PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state); > - if (sltsta & PCI_EXP_SLTSTA_EIS) { > - /* the slot is electromechanically locked. > - * This error is propagated up to qdev and then to HMP/QMP. > - */ > - return -EBUSY; > - } > - > - /* TODO: multifunction hot-plug. > - * Right now, only a device of function = 0 is allowed to be > - * hot plugged/unplugged. > - */ > - assert(PCI_FUNC(pci_dev->devfn) == 0); > - > - if (state == PCI_HOTPLUG_ENABLED) { > - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, > - PCI_EXP_SLTSTA_PDS); > - pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); > - } else { > - qdev_free(&pci_dev->qdev); > - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, > - PCI_EXP_SLTSTA_PDS); > - pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); > - } > - return 0; > -} > - > -/* pci express slot for pci express root/downstream port > - PCI express capability slot registers */ > -void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot) > -{ > - uint32_t pos = dev->exp.exp_cap; > - > - pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS, > - PCI_EXP_FLAGS_SLOT); > - > - pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP, > - ~PCI_EXP_SLTCAP_PSN); > - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP, > - (slot << PCI_EXP_SLTCAP_PSN_SHIFT) | > - PCI_EXP_SLTCAP_EIP | > - PCI_EXP_SLTCAP_HPS | > - PCI_EXP_SLTCAP_HPC | > - PCI_EXP_SLTCAP_PIP | > - PCI_EXP_SLTCAP_AIP | > - PCI_EXP_SLTCAP_ABP); > - > - pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL, > - PCI_EXP_SLTCTL_PIC | > - PCI_EXP_SLTCTL_AIC); > - pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL, > - PCI_EXP_SLTCTL_PIC_OFF | > - PCI_EXP_SLTCTL_AIC_OFF); > - pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, > - PCI_EXP_SLTCTL_PIC | > - PCI_EXP_SLTCTL_AIC | > - PCI_EXP_SLTCTL_HPIE | > - PCI_EXP_SLTCTL_CCIE | > - PCI_EXP_SLTCTL_PDCE | > - PCI_EXP_SLTCTL_ABPE); > - /* Although reading PCI_EXP_SLTCTL_EIC returns always 0, > - * make the bit writable here in order to detect 1b is written. > - * pcie_cap_slot_write_config() test-and-clear the bit, so > - * this bit always returns 0 to the guest. > - */ > - pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, > - PCI_EXP_SLTCTL_EIC); > - > - pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA, > - PCI_EXP_HP_EV_SUPPORTED); > - > - dev->exp.hpev_notified = false; > - > - pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)), > - pcie_cap_slot_hotplug, &dev->qdev); > -} > - > -void pcie_cap_slot_reset(PCIDevice *dev) > -{ > - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > - > - PCIE_DEV_PRINTF(dev, "reset\n"); > - > - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, > - PCI_EXP_SLTCTL_EIC | > - PCI_EXP_SLTCTL_PIC | > - PCI_EXP_SLTCTL_AIC | > - PCI_EXP_SLTCTL_HPIE | > - PCI_EXP_SLTCTL_CCIE | > - PCI_EXP_SLTCTL_PDCE | > - PCI_EXP_SLTCTL_ABPE); > - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL, > - PCI_EXP_SLTCTL_PIC_OFF | > - PCI_EXP_SLTCTL_AIC_OFF); > - > - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, > - PCI_EXP_SLTSTA_EIS |/* on reset, > - the lock is released */ > - PCI_EXP_SLTSTA_CC | > - PCI_EXP_SLTSTA_PDC | > - PCI_EXP_SLTSTA_ABP); > - > - hotplug_event_update_event_status(dev); > -} > - > -void pcie_cap_slot_write_config(PCIDevice *dev, > - uint32_t addr, uint32_t val, int len) > -{ > - uint32_t pos = dev->exp.exp_cap; > - uint8_t *exp_cap = dev->config + pos; > - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > - > - if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) { > - hotplug_event_clear(dev); > - } > - > - if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) { > - return; > - } > - > - if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, > - PCI_EXP_SLTCTL_EIC)) { > - sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */ > - pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta); > - PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: " > - "sltsta -> 0x%02"PRIx16"\n", > - sltsta); > - } > - > - hotplug_event_notify(dev); > - > - /* > - * 6.7.3.2 Command Completed Events > - * > - * Software issues a command to a hot-plug capable Downstream Port by > - * issuing a write transaction that targets any portion of the Port’s Slot > - * Control register. A single write to the Slot Control register is > - * considered to be a single command, even if the write affects more than > - * one field in the Slot Control register. In response to this transaction, > - * the Port must carry out the requested actions and then set the > - * associated status field for the command completed event. */ > - > - /* Real hardware might take a while to complete requested command because > - * physical movement would be involved like locking the electromechanical > - * lock. However in our case, command is completed instantaneously above, > - * so send a command completion event right now. > - */ > - pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI); > -} > - > -int pcie_cap_slot_post_load(void *opaque, int version_id) > -{ > - PCIDevice *dev = opaque; > - hotplug_event_update_event_status(dev); > - return 0; > -} > - > -void pcie_cap_slot_push_attention_button(PCIDevice *dev) > -{ > - pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP); > -} > - > -/* root control/capabilities/status. PME isn't emulated for now */ > -void pcie_cap_root_init(PCIDevice *dev) > -{ > - pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL, > - PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | > - PCI_EXP_RTCTL_SEFEE); > -} > - > -void pcie_cap_root_reset(PCIDevice *dev) > -{ > - pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0); > -} > - > -/* function level reset(FLR) */ > -void pcie_cap_flr_init(PCIDevice *dev) > -{ > - pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP, > - PCI_EXP_DEVCAP_FLR); > - > - /* Although reading BCR_FLR returns always 0, > - * the bit is made writable here in order to detect the 1b is written > - * pcie_cap_flr_write_config() test-and-clear the bit, so > - * this bit always returns 0 to the guest. > - */ > - pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL, > - PCI_EXP_DEVCTL_BCR_FLR); > -} > - > -void pcie_cap_flr_write_config(PCIDevice *dev, > - uint32_t addr, uint32_t val, int len) > -{ > - uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; > - if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) { > - /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler > - so the handler can detect FLR by looking at this bit. */ > - pci_device_reset(dev); > - pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR); > - } > -} > - > -/* Alternative Routing-ID Interpretation (ARI) */ > -/* ari forwarding support for down stream port */ > -void pcie_cap_ari_init(PCIDevice *dev) > -{ > - uint32_t pos = dev->exp.exp_cap; > - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2, > - PCI_EXP_DEVCAP2_ARI); > - pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2, > - PCI_EXP_DEVCTL2_ARI); > -} > - > -void pcie_cap_ari_reset(PCIDevice *dev) > -{ > - uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2; > - pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI); > -} > - > -bool pcie_cap_is_ari_enabled(const PCIDevice *dev) > -{ > - if (!pci_is_express(dev)) { > - return false; > - } > - if (!dev->exp.exp_cap) { > - return false; > - } > - > - return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & > - PCI_EXP_DEVCTL2_ARI; > -} > - > -/************************************************************************** > - * pci express extended capability allocation functions > - * uint16_t ext_cap_id (16 bit) > - * uint8_t cap_ver (4 bit) > - * uint16_t cap_offset (12 bit) > - * uint16_t ext_cap_size > - */ > - > -static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id, > - uint16_t *prev_p) > -{ > - uint16_t prev = 0; > - uint16_t next; > - uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE); > - > - if (!header) { > - /* no extended capability */ > - next = 0; > - goto out; > - } > - for (next = PCI_CONFIG_SPACE_SIZE; next; > - prev = next, next = PCI_EXT_CAP_NEXT(header)) { > - > - assert(next >= PCI_CONFIG_SPACE_SIZE); > - assert(next <= PCIE_CONFIG_SPACE_SIZE - 8); > - > - header = pci_get_long(dev->config + next); > - if (PCI_EXT_CAP_ID(header) == cap_id) { > - break; > - } > - } > - > -out: > - if (prev_p) { > - *prev_p = prev; > - } > - return next; > -} > - > -uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id) > -{ > - return pcie_find_capability_list(dev, cap_id, NULL); > -} > - > -static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next) > -{ > - uint16_t header = pci_get_long(dev->config + pos); > - assert(!(next & (PCI_EXT_CAP_ALIGN - 1))); > - header = (header & ~PCI_EXT_CAP_NEXT_MASK) | > - ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK); > - pci_set_long(dev->config + pos, header); > -} > - > -/* > - * caller must supply valid (offset, size) * such that the range shouldn't > - * overlap with other capability or other registers. > - * This function doesn't check it. > - */ > -void pcie_add_capability(PCIDevice *dev, > - uint16_t cap_id, uint8_t cap_ver, > - uint16_t offset, uint16_t size) > -{ > - uint32_t header; > - uint16_t next; > - > - assert(offset >= PCI_CONFIG_SPACE_SIZE); > - assert(offset < offset + size); > - assert(offset + size < PCIE_CONFIG_SPACE_SIZE); > - assert(size >= 8); > - assert(pci_is_express(dev)); > - > - if (offset == PCI_CONFIG_SPACE_SIZE) { > - header = pci_get_long(dev->config + offset); > - next = PCI_EXT_CAP_NEXT(header); > - } else { > - uint16_t prev; > - > - /* 0 is reserved cap id. use internally to find the last capability > - in the linked list */ > - next = pcie_find_capability_list(dev, 0, &prev); > - > - assert(prev >= PCI_CONFIG_SPACE_SIZE); > - assert(next == 0); > - pcie_ext_cap_set_next(dev, prev, offset); > - } > - pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next)); > - > - /* Make capability read-only by default */ > - memset(dev->wmask + offset, 0, size); > - memset(dev->w1cmask + offset, 0, size); > - /* Check capability by default */ > - memset(dev->cmask + offset, 0xFF, size); > -} > - > -/************************************************************************** > - * pci express extended capability helper functions > - */ > - > -/* ARI */ > -void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn) > -{ > - pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER, > - offset, PCI_ARI_SIZEOF); > - pci_set_long(dev->config + offset + PCI_ARI_CAP, PCI_ARI_CAP_NFN(nextfn)); > -} > diff --git a/hw/pcie.h b/hw/pcie.h > deleted file mode 100644 > index 4889194..0000000 > --- a/hw/pcie.h > +++ /dev/null > @@ -1,142 +0,0 @@ > -/* > - * pcie.h > - * > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - * > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#ifndef QEMU_PCIE_H > -#define QEMU_PCIE_H > - > -#include "hw.h" > -#include "pci_regs.h" > -#include "pcie_regs.h" > -#include "pcie_aer.h" > - > -typedef enum { > - /* for attention and power indicator */ > - PCI_EXP_HP_IND_RESERVED = PCI_EXP_SLTCTL_IND_RESERVED, > - PCI_EXP_HP_IND_ON = PCI_EXP_SLTCTL_IND_ON, > - PCI_EXP_HP_IND_BLINK = PCI_EXP_SLTCTL_IND_BLINK, > - PCI_EXP_HP_IND_OFF = PCI_EXP_SLTCTL_IND_OFF, > -} PCIExpressIndicator; > - > -typedef enum { > - /* these bits must match the bits in Slot Control/Status registers. > - * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx > - * > - * Not all the bits of slot control register match with the ones of > - * slot status. Not some bits of slot status register is used to > - * show status, not to report event occurrence. > - * So such bits must be masked out when checking the software > - * notification condition. > - */ > - PCI_EXP_HP_EV_ABP = PCI_EXP_SLTCTL_ABPE, > - /* attention button pressed */ > - PCI_EXP_HP_EV_PDC = PCI_EXP_SLTCTL_PDCE, > - /* presence detect changed */ > - PCI_EXP_HP_EV_CCI = PCI_EXP_SLTCTL_CCIE, > - /* command completed */ > - > - PCI_EXP_HP_EV_SUPPORTED = PCI_EXP_HP_EV_ABP | > - PCI_EXP_HP_EV_PDC | > - PCI_EXP_HP_EV_CCI, > - /* supported event mask */ > - > - /* events not listed aren't supported */ > -} PCIExpressHotPlugEvent; > - > -struct PCIExpressDevice { > - /* Offset of express capability in config space */ > - uint8_t exp_cap; > - > - /* SLOT */ > - unsigned int hpev_intx; /* INTx for hot plug event (0-3:INT[A-D]#) > - * default is 0 = INTA# > - * If the chip wants to use other interrupt > - * line, initialize this member with the > - * desired number. > - * If the chip dynamically changes this member, > - * also initialize it when loaded as > - * appropreately. > - */ > - bool hpev_notified; /* Logical AND of conditions for hot plug event. > - Following 6.7.3.4: > - Software Notification of Hot-Plug Events, an interrupt > - is sent whenever the logical and of these conditions > - transitions from false to true. */ > - > - /* AER */ > - uint16_t aer_cap; > - PCIEAERLog aer_log; > - unsigned int aer_intx; /* INTx for error reporting > - * default is 0 = INTA# > - * If the chip wants to use other interrupt > - * line, initialize this member with the > - * desired number. > - * If the chip dynamically changes this member, > - * also initialize it when loaded as > - * appropreately. > - */ > -}; > - > -/* PCI express capability helper functions */ > -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port); > -void pcie_cap_exit(PCIDevice *dev); > -uint8_t pcie_cap_get_type(const PCIDevice *dev); > -void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector); > -uint8_t pcie_cap_flags_get_vector(PCIDevice *dev); > - > -void pcie_cap_deverr_init(PCIDevice *dev); > -void pcie_cap_deverr_reset(PCIDevice *dev); > - > -void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot); > -void pcie_cap_slot_reset(PCIDevice *dev); > -void pcie_cap_slot_write_config(PCIDevice *dev, > - uint32_t addr, uint32_t val, int len); > -int pcie_cap_slot_post_load(void *opaque, int version_id); > -void pcie_cap_slot_push_attention_button(PCIDevice *dev); > - > -void pcie_cap_root_init(PCIDevice *dev); > -void pcie_cap_root_reset(PCIDevice *dev); > - > -void pcie_cap_flr_init(PCIDevice *dev); > -void pcie_cap_flr_write_config(PCIDevice *dev, > - uint32_t addr, uint32_t val, int len); > - > -void pcie_cap_ari_init(PCIDevice *dev); > -void pcie_cap_ari_reset(PCIDevice *dev); > -bool pcie_cap_is_ari_enabled(const PCIDevice *dev); > - > -/* PCI express extended capability helper functions */ > -uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id); > -void pcie_add_capability(PCIDevice *dev, > - uint16_t cap_id, uint8_t cap_ver, > - uint16_t offset, uint16_t size); > - > -void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn); > - > -extern const VMStateDescription vmstate_pcie_device; > - > -#define VMSTATE_PCIE_DEVICE(_field, _state) { \ > - .name = (stringify(_field)), \ > - .size = sizeof(PCIDevice), \ > - .vmsd = &vmstate_pcie_device, \ > - .flags = VMS_STRUCT, \ > - .offset = vmstate_offset_value(_state, _field, PCIDevice), \ > -} > - > -#endif /* QEMU_PCIE_H */ > diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c > deleted file mode 100644 > index b04c164..0000000 > --- a/hw/pcie_aer.c > +++ /dev/null > @@ -1,1032 +0,0 @@ > -/* > - * pcie_aer.c > - * > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - * > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#include "sysemu.h" > -#include "qemu-objects.h" > -#include "monitor.h" > -#include "pci_bridge.h" > -#include "pcie.h" > -#include "msix.h" > -#include "msi.h" > -#include "pci_internals.h" > -#include "pcie_regs.h" > - > -//#define DEBUG_PCIE > -#ifdef DEBUG_PCIE > -# define PCIE_DPRINTF(fmt, ...) \ > - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > -#else > -# define PCIE_DPRINTF(fmt, ...) do {} while (0) > -#endif > -#define PCIE_DEV_PRINTF(dev, fmt, ...) \ > - PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > - > -#define PCI_ERR_SRC_COR_OFFS 0 > -#define PCI_ERR_SRC_UNCOR_OFFS 2 > - > -/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */ > -static uint32_t pcie_aer_uncor_default_severity(uint32_t status) > -{ > - switch (status) { > - case PCI_ERR_UNC_INTN: > - case PCI_ERR_UNC_DLP: > - case PCI_ERR_UNC_SDN: > - case PCI_ERR_UNC_RX_OVER: > - case PCI_ERR_UNC_FCP: > - case PCI_ERR_UNC_MALF_TLP: > - return PCI_ERR_ROOT_CMD_FATAL_EN; > - case PCI_ERR_UNC_POISON_TLP: > - case PCI_ERR_UNC_ECRC: > - case PCI_ERR_UNC_UNSUP: > - case PCI_ERR_UNC_COMP_TIME: > - case PCI_ERR_UNC_COMP_ABORT: > - case PCI_ERR_UNC_UNX_COMP: > - case PCI_ERR_UNC_ACSV: > - case PCI_ERR_UNC_MCBTLP: > - case PCI_ERR_UNC_ATOP_EBLOCKED: > - case PCI_ERR_UNC_TLP_PRF_BLOCKED: > - return PCI_ERR_ROOT_CMD_NONFATAL_EN; > - default: > - abort(); > - break; > - } > - return PCI_ERR_ROOT_CMD_FATAL_EN; > -} > - > -static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err) > -{ > - if (aer_log->log_num == aer_log->log_max) { > - return -1; > - } > - memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err); > - aer_log->log_num++; > - return 0; > -} > - > -static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err) > -{ > - assert(aer_log->log_num); > - *err = aer_log->log[0]; > - aer_log->log_num--; > - memmove(&aer_log->log[0], &aer_log->log[1], > - aer_log->log_num * sizeof *err); > -} > - > -static void aer_log_clear_all_err(PCIEAERLog *aer_log) > -{ > - aer_log->log_num = 0; > -} > - > -int pcie_aer_init(PCIDevice *dev, uint16_t offset) > -{ > - PCIExpressDevice *exp; > - > - pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER, > - offset, PCI_ERR_SIZEOF); > - exp = &dev->exp; > - exp->aer_cap = offset; > - > - /* log_max is property */ > - if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) { > - dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT; > - } > - /* clip down the value to avoid unreasobale memory usage */ > - if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) { > - return -EINVAL; > - } > - dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] * > - dev->exp.aer_log.log_max); > - > - pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS, > - PCI_ERR_UNC_SUPPORTED); > - > - pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER, > - PCI_ERR_UNC_SEVERITY_DEFAULT); > - pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER, > - PCI_ERR_UNC_SUPPORTED); > - > - pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS, > - PCI_ERR_COR_STATUS); > - > - pci_set_long(dev->config + offset + PCI_ERR_COR_MASK, > - PCI_ERR_COR_MASK_DEFAULT); > - pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK, > - PCI_ERR_COR_SUPPORTED); > - > - /* capabilities and control. multiple header logging is supported */ > - if (dev->exp.aer_log.log_max > 0) { > - pci_set_long(dev->config + offset + PCI_ERR_CAP, > - PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC | > - PCI_ERR_CAP_MHRC); > - pci_set_long(dev->wmask + offset + PCI_ERR_CAP, > - PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE | > - PCI_ERR_CAP_MHRE); > - } else { > - pci_set_long(dev->config + offset + PCI_ERR_CAP, > - PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC); > - pci_set_long(dev->wmask + offset + PCI_ERR_CAP, > - PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); > - } > - > - switch (pcie_cap_get_type(dev)) { > - case PCI_EXP_TYPE_ROOT_PORT: > - /* this case will be set by pcie_aer_root_init() */ > - /* fallthrough */ > - case PCI_EXP_TYPE_DOWNSTREAM: > - case PCI_EXP_TYPE_UPSTREAM: > - pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL, > - PCI_BRIDGE_CTL_SERR); > - pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS, > - PCI_SEC_STATUS_RCV_SYSTEM_ERROR); > - break; > - default: > - /* nothing */ > - break; > - } > - return 0; > -} > - > -void pcie_aer_exit(PCIDevice *dev) > -{ > - g_free(dev->exp.aer_log.log); > -} > - > -static void pcie_aer_update_uncor_status(PCIDevice *dev) > -{ > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > - PCIEAERLog *aer_log = &dev->exp.aer_log; > - > - uint16_t i; > - for (i = 0; i < aer_log->log_num; i++) { > - pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS, > - dev->exp.aer_log.log[i].status); > - } > -} > - > -/* > - * return value: > - * true: error message needs to be sent up > - * false: error message is masked > - * > - * 6.2.6 Error Message Control > - * Figure 6-3 > - * all pci express devices part > - */ > -static bool > -pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg) > -{ > - if (!(pcie_aer_msg_is_uncor(msg) && > - (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) { > - return false; > - } > - > - /* Signaled System Error > - * > - * 7.5.1.1 Command register > - * Bit 8 SERR# Enable > - * > - * When Set, this bit enables reporting of Non-fatal and Fatal > - * errors detected by the Function to the Root Complex. Note that > - * errors are reported if enabled either through this bit or through > - * the PCI Express specific bits in the Device Control register (see > - * Section 7.8.4). > - */ > - pci_word_test_and_set_mask(dev->config + PCI_STATUS, > - PCI_STATUS_SIG_SYSTEM_ERROR); > - > - if (!(msg->severity & > - pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) { > - return false; > - } > - > - /* send up error message */ > - return true; > -} > - > -/* > - * return value: > - * true: error message is sent up > - * false: error message is masked > - * > - * 6.2.6 Error Message Control > - * Figure 6-3 > - * virtual pci bridge part > - */ > -static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg) > -{ > - uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL); > - > - if (pcie_aer_msg_is_uncor(msg)) { > - /* Received System Error */ > - pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS, > - PCI_SEC_STATUS_RCV_SYSTEM_ERROR); > - } > - > - if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) { > - return false; > - } > - return true; > -} > - > -void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector) > -{ > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > - assert(vector < PCI_ERR_ROOT_IRQ_MAX); > - pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS, > - PCI_ERR_ROOT_IRQ); > - pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS, > - vector << PCI_ERR_ROOT_IRQ_SHIFT); > -} > - > -static unsigned int pcie_aer_root_get_vector(PCIDevice *dev) > -{ > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > - uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > - return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT; > -} > - > -/* Given a status register, get corresponding bits in the command register */ > -static uint32_t pcie_aer_status_to_cmd(uint32_t status) > -{ > - uint32_t cmd = 0; > - if (status & PCI_ERR_ROOT_COR_RCV) { > - cmd |= PCI_ERR_ROOT_CMD_COR_EN; > - } > - if (status & PCI_ERR_ROOT_NONFATAL_RCV) { > - cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN; > - } > - if (status & PCI_ERR_ROOT_FATAL_RCV) { > - cmd |= PCI_ERR_ROOT_CMD_FATAL_EN; > - } > - return cmd; > -} > - > -static void pcie_aer_root_notify(PCIDevice *dev) > -{ > - if (msix_enabled(dev)) { > - msix_notify(dev, pcie_aer_root_get_vector(dev)); > - } else if (msi_enabled(dev)) { > - msi_notify(dev, pcie_aer_root_get_vector(dev)); > - } else { > - qemu_set_irq(dev->irq[dev->exp.aer_intx], 1); > - } > -} > - > -/* > - * 6.2.6 Error Message Control > - * Figure 6-3 > - * root port part > - */ > -static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg) > -{ > - uint16_t cmd; > - uint8_t *aer_cap; > - uint32_t root_cmd; > - uint32_t root_status, prev_status; > - > - cmd = pci_get_word(dev->config + PCI_COMMAND); > - aer_cap = dev->config + dev->exp.aer_cap; > - root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); > - prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > - > - if (cmd & PCI_COMMAND_SERR) { > - /* System Error. > - * > - * The way to report System Error is platform specific and > - * it isn't implemented in qemu right now. > - * So just discard the error for now. > - * OS which cares of aer would receive errors via > - * native aer mechanims, so this wouldn't matter. > - */ > - } > - > - /* Errro Message Received: Root Error Status register */ > - switch (msg->severity) { > - case PCI_ERR_ROOT_CMD_COR_EN: > - if (root_status & PCI_ERR_ROOT_COR_RCV) { > - root_status |= PCI_ERR_ROOT_MULTI_COR_RCV; > - } else { > - pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SRC_COR_OFFS, > - msg->source_id); > - } > - root_status |= PCI_ERR_ROOT_COR_RCV; > - break; > - case PCI_ERR_ROOT_CMD_NONFATAL_EN: > - root_status |= PCI_ERR_ROOT_NONFATAL_RCV; > - break; > - case PCI_ERR_ROOT_CMD_FATAL_EN: > - if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) { > - root_status |= PCI_ERR_ROOT_FIRST_FATAL; > - } > - root_status |= PCI_ERR_ROOT_FATAL_RCV; > - break; > - default: > - abort(); > - break; > - } > - if (pcie_aer_msg_is_uncor(msg)) { > - if (root_status & PCI_ERR_ROOT_UNCOR_RCV) { > - root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV; > - } else { > - pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + > - PCI_ERR_SRC_UNCOR_OFFS, msg->source_id); > - } > - root_status |= PCI_ERR_ROOT_UNCOR_RCV; > - } > - pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status); > - > - /* 6.2.4.1.2 Interrupt Generation */ > - /* All the above did was set some bits in the status register. > - * Specifically these that match message severity. > - * The below code relies on this fact. */ > - if (!(root_cmd & msg->severity) || > - (pcie_aer_status_to_cmd(prev_status) & root_cmd)) { > - /* Condition is not being set or was already true so nothing to do. */ > - return; > - } > - > - pcie_aer_root_notify(dev); > -} > - > -/* > - * 6.2.6 Error Message Control Figure 6-3 > - * > - * Walk up the bus tree from the device, propagate the error message. > - */ > -static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) > -{ > - uint8_t type; > - > - while (dev) { > - if (!pci_is_express(dev)) { > - /* just ignore it */ > - /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR? > - * Consider e.g. a PCI bridge above a PCI Express device. */ > - return; > - } > - > - type = pcie_cap_get_type(dev); > - if ((type == PCI_EXP_TYPE_ROOT_PORT || > - type == PCI_EXP_TYPE_UPSTREAM || > - type == PCI_EXP_TYPE_DOWNSTREAM) && > - !pcie_aer_msg_vbridge(dev, msg)) { > - return; > - } > - if (!pcie_aer_msg_alldev(dev, msg)) { > - return; > - } > - if (type == PCI_EXP_TYPE_ROOT_PORT) { > - pcie_aer_msg_root_port(dev, msg); > - /* Root port can notify system itself, > - or send the error message to root complex event collector. */ > - /* > - * if root port is associated with an event collector, > - * return the root complex event collector here. > - * For now root complex event collector isn't supported. > - */ > - return; > - } > - dev = pci_bridge_get_device(dev->bus); > - } > -} > - > -static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err) > -{ > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > - uint8_t first_bit = ffs(err->status) - 1; > - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > - int i; > - > - assert(err->status); > - assert(!(err->status & (err->status - 1))); > - > - errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); > - errcap |= PCI_ERR_CAP_FEP(first_bit); > - > - if (err->flags & PCIE_AER_ERR_HEADER_VALID) { > - for (i = 0; i < ARRAY_SIZE(err->header); ++i) { > - /* 7.10.8 Header Log Register */ > - uint8_t *header_log = > - aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0]; > - cpu_to_be32wu((uint32_t*)header_log, err->header[i]); > - } > - } else { > - assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT)); > - memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); > - } > - > - if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) && > - (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & > - PCI_EXP_DEVCAP2_EETLPP)) { > - for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) { > - /* 7.10.12 tlp prefix log register */ > - uint8_t *prefix_log = > - aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0]; > - cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]); > - } > - errcap |= PCI_ERR_CAP_TLP; > - } else { > - memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, > - PCI_ERR_TLP_PREFIX_LOG_SIZE); > - } > - pci_set_long(aer_cap + PCI_ERR_CAP, errcap); > -} > - > -static void pcie_aer_clear_log(PCIDevice *dev) > -{ > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > - > - pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP, > - PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); > - > - memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); > - memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE); > -} > - > -static void pcie_aer_clear_error(PCIDevice *dev) > -{ > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > - PCIEAERLog *aer_log = &dev->exp.aer_log; > - PCIEAERErr err; > - > - if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) { > - pcie_aer_clear_log(dev); > - return; > - } > - > - /* > - * If more errors are queued, set corresponding bits in uncorrectable > - * error status. > - * We emulate uncorrectable error status register as W1CS. > - * So set bit in uncorrectable error status here again for multiple > - * error recording support. > - * > - * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability) > - */ > - pcie_aer_update_uncor_status(dev); > - > - aer_log_del_err(aer_log, &err); > - pcie_aer_update_log(dev, &err); > -} > - > -static int pcie_aer_record_error(PCIDevice *dev, > - const PCIEAERErr *err) > -{ > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > - int fep = PCI_ERR_CAP_FEP(errcap); > - > - assert(err->status); > - assert(!(err->status & (err->status - 1))); > - > - if (errcap & PCI_ERR_CAP_MHRE && > - (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) { > - /* Not first error. queue error */ > - if (aer_log_add_err(&dev->exp.aer_log, err) < 0) { > - /* overflow */ > - return -1; > - } > - return 0; > - } > - > - pcie_aer_update_log(dev, err); > - return 0; > -} > - > -typedef struct PCIEAERInject { > - PCIDevice *dev; > - uint8_t *aer_cap; > - const PCIEAERErr *err; > - uint16_t devctl; > - uint16_t devsta; > - uint32_t error_status; > - bool unsupported_request; > - bool log_overflow; > - PCIEAERMsg msg; > -} PCIEAERInject; > - > -static bool pcie_aer_inject_cor_error(PCIEAERInject *inj, > - uint32_t uncor_status, > - bool is_advisory_nonfatal) > -{ > - PCIDevice *dev = inj->dev; > - > - inj->devsta |= PCI_EXP_DEVSTA_CED; > - if (inj->unsupported_request) { > - inj->devsta |= PCI_EXP_DEVSTA_URD; > - } > - pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); > - > - if (inj->aer_cap) { > - uint32_t mask; > - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS, > - inj->error_status); > - mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK); > - if (mask & inj->error_status) { > - return false; > - } > - if (is_advisory_nonfatal) { > - uint32_t uncor_mask = > - pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); > - if (!(uncor_mask & uncor_status)) { > - inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); > - } > - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > - uncor_status); > - } > - } > - > - if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) { > - return false; > - } > - if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) { > - return false; > - } > - > - inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN; > - return true; > -} > - > -static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal) > -{ > - PCIDevice *dev = inj->dev; > - uint16_t cmd; > - > - if (is_fatal) { > - inj->devsta |= PCI_EXP_DEVSTA_FED; > - } else { > - inj->devsta |= PCI_EXP_DEVSTA_NFED; > - } > - if (inj->unsupported_request) { > - inj->devsta |= PCI_EXP_DEVSTA_URD; > - } > - pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); > - > - if (inj->aer_cap) { > - uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); > - if (mask & inj->error_status) { > - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > - inj->error_status); > - return false; > - } > - > - inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); > - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > - inj->error_status); > - } > - > - cmd = pci_get_word(dev->config + PCI_COMMAND); > - if (inj->unsupported_request && > - !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) { > - return false; > - } > - if (is_fatal) { > - if (!((cmd & PCI_COMMAND_SERR) || > - (inj->devctl & PCI_EXP_DEVCTL_FERE))) { > - return false; > - } > - inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN; > - } else { > - if (!((cmd & PCI_COMMAND_SERR) || > - (inj->devctl & PCI_EXP_DEVCTL_NFERE))) { > - return false; > - } > - inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN; > - } > - return true; > -} > - > -/* > - * non-Function specific error must be recorded in all functions. > - * It is the responsibility of the caller of this function. > - * It is also caller's responsibility to determine which function should > - * report the rerror. > - * > - * 6.2.4 Error Logging > - * 6.2.5 Sqeunce of Device Error Signaling and Logging Operations > - * table 6-2: Flowchard Showing Sequence of Device Error Signaling and Logging > - * Operations > - */ > -int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err) > -{ > - uint8_t *aer_cap = NULL; > - uint16_t devctl = 0; > - uint16_t devsta = 0; > - uint32_t error_status = err->status; > - PCIEAERInject inj; > - > - if (!pci_is_express(dev)) { > - return -ENOSYS; > - } > - > - if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > - error_status &= PCI_ERR_COR_SUPPORTED; > - } else { > - error_status &= PCI_ERR_UNC_SUPPORTED; > - } > - > - /* invalid status bit. one and only one bit must be set */ > - if (!error_status || (error_status & (error_status - 1))) { > - return -EINVAL; > - } > - > - if (dev->exp.aer_cap) { > - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > - aer_cap = dev->config + dev->exp.aer_cap; > - devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL); > - devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA); > - } > - > - inj.dev = dev; > - inj.aer_cap = aer_cap; > - inj.err = err; > - inj.devctl = devctl; > - inj.devsta = devsta; > - inj.error_status = error_status; > - inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) && > - err->status == PCI_ERR_UNC_UNSUP; > - inj.log_overflow = false; > - > - if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > - if (!pcie_aer_inject_cor_error(&inj, 0, false)) { > - return 0; > - } > - } else { > - bool is_fatal = > - pcie_aer_uncor_default_severity(error_status) == > - PCI_ERR_ROOT_CMD_FATAL_EN; > - if (aer_cap) { > - is_fatal = > - error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER); > - } > - if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) { > - inj.error_status = PCI_ERR_COR_ADV_NONFATAL; > - if (!pcie_aer_inject_cor_error(&inj, error_status, true)) { > - return 0; > - } > - } else { > - if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) { > - return 0; > - } > - } > - } > - > - /* send up error message */ > - inj.msg.source_id = err->source_id; > - pcie_aer_msg(dev, &inj.msg); > - > - if (inj.log_overflow) { > - PCIEAERErr header_log_overflow = { > - .status = PCI_ERR_COR_HL_OVERFLOW, > - .flags = PCIE_AER_ERR_IS_CORRECTABLE, > - }; > - int ret = pcie_aer_inject_error(dev, &header_log_overflow); > - assert(!ret); > - } > - return 0; > -} > - > -void pcie_aer_write_config(PCIDevice *dev, > - uint32_t addr, uint32_t val, int len) > -{ > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > - uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap); > - uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS); > - > - /* uncorrectable error */ > - if (!(uncorsta & first_error)) { > - /* the bit that corresponds to the first error is cleared */ > - pcie_aer_clear_error(dev); > - } else if (errcap & PCI_ERR_CAP_MHRE) { > - /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared > - * nothing should happen. So we have to revert the modification to > - * the register. > - */ > - pcie_aer_update_uncor_status(dev); > - } else { > - /* capability & control > - * PCI_ERR_CAP_MHRE might be cleared, so clear of header log. > - */ > - aer_log_clear_all_err(&dev->exp.aer_log); > - } > -} > - > -void pcie_aer_root_init(PCIDevice *dev) > -{ > - uint16_t pos = dev->exp.aer_cap; > - > - pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND, > - PCI_ERR_ROOT_CMD_EN_MASK); > - pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS, > - PCI_ERR_ROOT_STATUS_REPORT_MASK); > - /* PCI_ERR_ROOT_IRQ is RO but devices change it using a > - * device-specific method. > - */ > - pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS, > - ~PCI_ERR_ROOT_IRQ); > -} > - > -void pcie_aer_root_reset(PCIDevice *dev) > -{ > - uint8_t* aer_cap = dev->config + dev->exp.aer_cap; > - > - pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0); > - > - /* > - * Advanced Error Interrupt Message Number in Root Error Status Register > - * must be updated by chip dependent code because it's chip dependent > - * which number is used. > - */ > -} > - > -void pcie_aer_root_write_config(PCIDevice *dev, > - uint32_t addr, uint32_t val, int len, > - uint32_t root_cmd_prev) > -{ > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > - uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > - uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status); > - uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); > - /* 6.2.4.1.2 Interrupt Generation */ > - if (!msix_enabled(dev) && !msi_enabled(dev)) { > - qemu_set_irq(dev->irq[dev->exp.aer_intx], !!(root_cmd & enabled_cmd)); > - return; > - } > - > - if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) { > - /* Send MSI on transition from false to true. */ > - return; > - } > - > - pcie_aer_root_notify(dev); > -} > - > -static const VMStateDescription vmstate_pcie_aer_err = { > - .name = "PCIE_AER_ERROR", > - .version_id = 1, > - .minimum_version_id = 1, > - .minimum_version_id_old = 1, > - .fields = (VMStateField[]) { > - VMSTATE_UINT32(status, PCIEAERErr), > - VMSTATE_UINT16(source_id, PCIEAERErr), > - VMSTATE_UINT16(flags, PCIEAERErr), > - VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4), > - VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4), > - VMSTATE_END_OF_LIST() > - } > -}; > - > -const VMStateDescription vmstate_pcie_aer_log = { > - .name = "PCIE_AER_ERROR_LOG", > - .version_id = 1, > - .minimum_version_id = 1, > - .minimum_version_id_old = 1, > - .fields = (VMStateField[]) { > - VMSTATE_UINT16(log_num, PCIEAERLog), > - VMSTATE_UINT16(log_max, PCIEAERLog), > - VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num, > - vmstate_pcie_aer_err, PCIEAERErr), > - VMSTATE_END_OF_LIST() > - } > -}; > - > -void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) > -{ > - QDict *qdict; > - int devfn; > - assert(qobject_type(data) == QTYPE_QDICT); > - qdict = qobject_to_qdict(data); > - > - devfn = (int)qdict_get_int(qdict, "devfn"); > - monitor_printf(mon, "OK id: %s domain: %x, bus: %x devfn: %x.%x\n", > - qdict_get_str(qdict, "id"), > - (int) qdict_get_int(qdict, "domain"), > - (int) qdict_get_int(qdict, "bus"), > - PCI_SLOT(devfn), PCI_FUNC(devfn)); > -} > - > -typedef struct PCIEAERErrorName { > - const char *name; > - uint32_t val; > - bool correctable; > -} PCIEAERErrorName; > - > -/* > - * AER error name -> value conversion table > - * This naming scheme is same to linux aer-injection tool. > - */ > -static const struct PCIEAERErrorName pcie_aer_error_list[] = { > - { > - .name = "TRAIN", > - .val = PCI_ERR_UNC_TRAIN, > - .correctable = false, > - }, { > - .name = "DLP", > - .val = PCI_ERR_UNC_DLP, > - .correctable = false, > - }, { > - .name = "SDN", > - .val = PCI_ERR_UNC_SDN, > - .correctable = false, > - }, { > - .name = "POISON_TLP", > - .val = PCI_ERR_UNC_POISON_TLP, > - .correctable = false, > - }, { > - .name = "FCP", > - .val = PCI_ERR_UNC_FCP, > - .correctable = false, > - }, { > - .name = "COMP_TIME", > - .val = PCI_ERR_UNC_COMP_TIME, > - .correctable = false, > - }, { > - .name = "COMP_ABORT", > - .val = PCI_ERR_UNC_COMP_ABORT, > - .correctable = false, > - }, { > - .name = "UNX_COMP", > - .val = PCI_ERR_UNC_UNX_COMP, > - .correctable = false, > - }, { > - .name = "RX_OVER", > - .val = PCI_ERR_UNC_RX_OVER, > - .correctable = false, > - }, { > - .name = "MALF_TLP", > - .val = PCI_ERR_UNC_MALF_TLP, > - .correctable = false, > - }, { > - .name = "ECRC", > - .val = PCI_ERR_UNC_ECRC, > - .correctable = false, > - }, { > - .name = "UNSUP", > - .val = PCI_ERR_UNC_UNSUP, > - .correctable = false, > - }, { > - .name = "ACSV", > - .val = PCI_ERR_UNC_ACSV, > - .correctable = false, > - }, { > - .name = "INTN", > - .val = PCI_ERR_UNC_INTN, > - .correctable = false, > - }, { > - .name = "MCBTLP", > - .val = PCI_ERR_UNC_MCBTLP, > - .correctable = false, > - }, { > - .name = "ATOP_EBLOCKED", > - .val = PCI_ERR_UNC_ATOP_EBLOCKED, > - .correctable = false, > - }, { > - .name = "TLP_PRF_BLOCKED", > - .val = PCI_ERR_UNC_TLP_PRF_BLOCKED, > - .correctable = false, > - }, { > - .name = "RCVR", > - .val = PCI_ERR_COR_RCVR, > - .correctable = true, > - }, { > - .name = "BAD_TLP", > - .val = PCI_ERR_COR_BAD_TLP, > - .correctable = true, > - }, { > - .name = "BAD_DLLP", > - .val = PCI_ERR_COR_BAD_DLLP, > - .correctable = true, > - }, { > - .name = "REP_ROLL", > - .val = PCI_ERR_COR_REP_ROLL, > - .correctable = true, > - }, { > - .name = "REP_TIMER", > - .val = PCI_ERR_COR_REP_TIMER, > - .correctable = true, > - }, { > - .name = "ADV_NONFATAL", > - .val = PCI_ERR_COR_ADV_NONFATAL, > - .correctable = true, > - }, { > - .name = "INTERNAL", > - .val = PCI_ERR_COR_INTERNAL, > - .correctable = true, > - }, { > - .name = "HL_OVERFLOW", > - .val = PCI_ERR_COR_HL_OVERFLOW, > - .correctable = true, > - }, > -}; > - > -static int pcie_aer_parse_error_string(const char *error_name, > - uint32_t *status, bool *correctable) > -{ > - int i; > - > - for (i = 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) { > - const PCIEAERErrorName *e = &pcie_aer_error_list[i]; > - if (strcmp(error_name, e->name)) { > - continue; > - } > - > - *status = e->val; > - *correctable = e->correctable; > - return 0; > - } > - return -EINVAL; > -} > - > -int do_pcie_aer_inject_error(Monitor *mon, > - const QDict *qdict, QObject **ret_data) > -{ > - const char *id = qdict_get_str(qdict, "id"); > - const char *error_name; > - uint32_t error_status; > - bool correctable; > - PCIDevice *dev; > - PCIEAERErr err; > - int ret; > - > - ret = pci_qdev_find_device(id, &dev); > - if (ret < 0) { > - monitor_printf(mon, > - "id or pci device path is invalid or device not " > - "found. %s\n", id); > - return ret; > - } > - if (!pci_is_express(dev)) { > - monitor_printf(mon, "the device doesn't support pci express. %s\n", > - id); > - return -ENOSYS; > - } > - > - error_name = qdict_get_str(qdict, "error_status"); > - if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) { > - char *e = NULL; > - error_status = strtoul(error_name, &e, 0); > - correctable = qdict_get_try_bool(qdict, "correctable", 0); > - if (!e || *e != '\0') { > - monitor_printf(mon, "invalid error status value. \"%s\"", > - error_name); > - return -EINVAL; > - } > - } > - err.status = error_status; > - err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn; > - > - err.flags = 0; > - if (correctable) { > - err.flags |= PCIE_AER_ERR_IS_CORRECTABLE; > - } > - if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) { > - err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY; > - } > - if (qdict_haskey(qdict, "header0")) { > - err.flags |= PCIE_AER_ERR_HEADER_VALID; > - } > - if (qdict_haskey(qdict, "prefix0")) { > - err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT; > - } > - > - err.header[0] = qdict_get_try_int(qdict, "header0", 0); > - err.header[1] = qdict_get_try_int(qdict, "header1", 0); > - err.header[2] = qdict_get_try_int(qdict, "header2", 0); > - err.header[3] = qdict_get_try_int(qdict, "header3", 0); > - > - err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0); > - err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0); > - err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0); > - err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0); > - > - ret = pcie_aer_inject_error(dev, &err); > - *ret_data = qobject_from_jsonf("{'id': %s, " > - "'domain': %d, 'bus': %d, 'devfn': %d, " > - "'ret': %d}", > - id, > - pci_find_domain(dev->bus), > - pci_bus_num(dev->bus), dev->devfn, > - ret); > - assert(*ret_data); > - > - return 0; > -} > diff --git a/hw/pcie_aer.h b/hw/pcie_aer.h > deleted file mode 100644 > index 7539500..0000000 > --- a/hw/pcie_aer.h > +++ /dev/null > @@ -1,106 +0,0 @@ > -/* > - * pcie_aer.h > - * > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - * > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#ifndef QEMU_PCIE_AER_H > -#define QEMU_PCIE_AER_H > - > -#include "hw.h" > - > -/* definitions which PCIExpressDevice uses */ > - > -/* AER log */ > -struct PCIEAERLog { > - /* This structure is saved/loaded. > - So explicitly size them instead of unsigned int */ > - > - /* the number of currently recorded log in log member */ > - uint16_t log_num; > - > - /* > - * The maximum number of the log. Errors can be logged up to this. > - * > - * This is configurable property. > - * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT > - * to avoid unreasonable memory usage. > - * I bet that 128 log size would be big enough, otherwise too many errors > - * for system to function normaly. But could consecutive errors occur? > - */ > -#define PCIE_AER_LOG_MAX_DEFAULT 8 > -#define PCIE_AER_LOG_MAX_LIMIT 128 > -#define PCIE_AER_LOG_MAX_UNSET 0xffff > - uint16_t log_max; > - > - /* Error log. log_max-sized array */ > - PCIEAERErr *log; > -}; > - > -/* aer error message: error signaling message has only error sevirity and > - source id. See 2.2.8.3 error signaling messages */ > -struct PCIEAERMsg { > - /* > - * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN > - * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE} > - */ > - uint32_t severity; > - > - uint16_t source_id; /* bdf */ > -}; > - > -static inline bool > -pcie_aer_msg_is_uncor(const PCIEAERMsg *msg) > -{ > - return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN || > - msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN; > -} > - > -/* error */ > -struct PCIEAERErr { > - uint32_t status; /* error status bits */ > - uint16_t source_id; /* bdf */ > - > -#define PCIE_AER_ERR_IS_CORRECTABLE 0x1 /* correctable/uncorrectable */ > -#define PCIE_AER_ERR_MAYBE_ADVISORY 0x2 /* maybe advisory non-fatal */ > -#define PCIE_AER_ERR_HEADER_VALID 0x4 /* TLP header is logged */ > -#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8 /* TLP Prefix is logged */ > - uint16_t flags; > - > - uint32_t header[4]; /* TLP header */ > - uint32_t prefix[4]; /* TLP header prefix */ > -}; > - > -extern const VMStateDescription vmstate_pcie_aer_log; > - > -int pcie_aer_init(PCIDevice *dev, uint16_t offset); > -void pcie_aer_exit(PCIDevice *dev); > -void pcie_aer_write_config(PCIDevice *dev, > - uint32_t addr, uint32_t val, int len); > - > -/* aer root port */ > -void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector); > -void pcie_aer_root_init(PCIDevice *dev); > -void pcie_aer_root_reset(PCIDevice *dev); > -void pcie_aer_root_write_config(PCIDevice *dev, > - uint32_t addr, uint32_t val, int len, > - uint32_t root_cmd_prev); > - > -/* error injection */ > -int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err); > - > -#endif /* QEMU_PCIE_AER_H */ > diff --git a/hw/pcie_host.c b/hw/pcie_host.c > deleted file mode 100644 > index c257fb4..0000000 > --- a/hw/pcie_host.c > +++ /dev/null > @@ -1,161 +0,0 @@ > -/* > - * pcie_host.c > - * utility functions for pci express host bridge. > - * > - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#include "hw.h" > -#include "pci.h" > -#include "pcie_host.h" > -#include "exec-memory.h" > - > -/* > - * PCI express mmcfig address > - * bit 20 - 28: bus number > - * bit 15 - 19: device number > - * bit 12 - 14: function number > - * bit 0 - 11: offset in configuration space of a given device > - */ > -#define PCIE_MMCFG_SIZE_MAX (1ULL << 28) > -#define PCIE_MMCFG_SIZE_MIN (1ULL << 20) > -#define PCIE_MMCFG_BUS_BIT 20 > -#define PCIE_MMCFG_BUS_MASK 0x1ff > -#define PCIE_MMCFG_DEVFN_BIT 12 > -#define PCIE_MMCFG_DEVFN_MASK 0xff > -#define PCIE_MMCFG_CONFOFFSET_MASK 0xfff > -#define PCIE_MMCFG_BUS(addr) (((addr) >> PCIE_MMCFG_BUS_BIT) & \ > - PCIE_MMCFG_BUS_MASK) > -#define PCIE_MMCFG_DEVFN(addr) (((addr) >> PCIE_MMCFG_DEVFN_BIT) & \ > - PCIE_MMCFG_DEVFN_MASK) > -#define PCIE_MMCFG_CONFOFFSET(addr) ((addr) & PCIE_MMCFG_CONFOFFSET_MASK) > - > - > -/* a helper function to get a PCIDevice for a given mmconfig address */ > -static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, > - uint32_t mmcfg_addr) > -{ > - return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), > - PCIE_MMCFG_DEVFN(mmcfg_addr)); > -} > - > -static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr, > - uint64_t val, unsigned len) > -{ > - PCIExpressHost *e = opaque; > - PCIBus *s = e->pci.bus; > - PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); > - uint32_t addr; > - uint32_t limit; > - > - if (!pci_dev) { > - return; > - } > - addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > - limit = pci_config_size(pci_dev); > - if (limit <= addr) { > - /* conventional pci device can be behind pcie-to-pci bridge. > - 256 <= addr < 4K has no effects. */ > - return; > - } > - pci_host_config_write_common(pci_dev, addr, limit, val, len); > -} > - > -static uint64_t pcie_mmcfg_data_read(void *opaque, > - hwaddr mmcfg_addr, > - unsigned len) > -{ > - PCIExpressHost *e = opaque; > - PCIBus *s = e->pci.bus; > - PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); > - uint32_t addr; > - uint32_t limit; > - > - if (!pci_dev) { > - return ~0x0; > - } > - addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > - limit = pci_config_size(pci_dev); > - if (limit <= addr) { > - /* conventional pci device can be behind pcie-to-pci bridge. > - 256 <= addr < 4K has no effects. */ > - return ~0x0; > - } > - return pci_host_config_read_common(pci_dev, addr, limit, len); > -} > - > -static const MemoryRegionOps pcie_mmcfg_ops = { > - .read = pcie_mmcfg_data_read, > - .write = pcie_mmcfg_data_write, > - .endianness = DEVICE_NATIVE_ENDIAN, > -}; > - > -/* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */ > -#define PCIE_BASE_ADDR_UNMAPPED ((hwaddr)-1ULL) > - > -int pcie_host_init(PCIExpressHost *e) > -{ > - e->base_addr = PCIE_BASE_ADDR_UNMAPPED; > - > - return 0; > -} > - > -void pcie_host_mmcfg_unmap(PCIExpressHost *e) > -{ > - if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { > - memory_region_del_subregion(get_system_memory(), &e->mmio); > - memory_region_destroy(&e->mmio); > - e->base_addr = PCIE_BASE_ADDR_UNMAPPED; > - } > -} > - > -void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, > - uint32_t size) > -{ > - assert(!(size & (size - 1))); /* power of 2 */ > - assert(size >= PCIE_MMCFG_SIZE_MIN); > - assert(size <= PCIE_MMCFG_SIZE_MAX); > - e->size = size; > - memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size); > - e->base_addr = addr; > - memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio); > -} > - > -void pcie_host_mmcfg_update(PCIExpressHost *e, > - int enable, > - hwaddr addr, > - uint32_t size) > -{ > - pcie_host_mmcfg_unmap(e); > - if (enable) { > - pcie_host_mmcfg_map(e, addr, size); > - } > -} > - > -static const TypeInfo pcie_host_type_info = { > - .name = TYPE_PCIE_HOST_BRIDGE, > - .parent = TYPE_PCI_HOST_BRIDGE, > - .abstract = true, > - .instance_size = sizeof(PCIExpressHost), > -}; > - > -static void pcie_host_register_types(void) > -{ > - type_register_static(&pcie_host_type_info); > -} > - > -type_init(pcie_host_register_types) > diff --git a/hw/pcie_host.h b/hw/pcie_host.h > deleted file mode 100644 > index 3921935..0000000 > --- a/hw/pcie_host.h > +++ /dev/null > @@ -1,54 +0,0 @@ > -/* > - * pcie_host.h > - * > - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#ifndef PCIE_HOST_H > -#define PCIE_HOST_H > - > -#include "pci_host.h" > -#include "memory.h" > - > -#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge" > -#define PCIE_HOST_BRIDGE(obj) \ > - OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE) > - > -struct PCIExpressHost { > - PCIHostState pci; > - > - /* express part */ > - > - /* base address where MMCONFIG area is mapped. */ > - hwaddr base_addr; > - > - /* the size of MMCONFIG area. It's host bridge dependent */ > - hwaddr size; > - > - /* MMCONFIG mmio area */ > - MemoryRegion mmio; > -}; > - > -int pcie_host_init(PCIExpressHost *e); > -void pcie_host_mmcfg_unmap(PCIExpressHost *e); > -void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size); > -void pcie_host_mmcfg_update(PCIExpressHost *e, > - int enable, > - hwaddr addr, > - uint32_t size); > - > -#endif /* PCIE_HOST_H */ > diff --git a/hw/pcie_port.c b/hw/pcie_port.c > deleted file mode 100644 > index d6350e5..0000000 > --- a/hw/pcie_port.c > +++ /dev/null > @@ -1,114 +0,0 @@ > -/* > - * pcie_port.c > - * > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - * > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#include "pcie_port.h" > - > -void pcie_port_init_reg(PCIDevice *d) > -{ > - /* Unlike pci bridge, > - 66MHz and fast back to back don't apply to pci express port. */ > - pci_set_word(d->config + PCI_STATUS, 0); > - pci_set_word(d->config + PCI_SEC_STATUS, 0); > - > - /* Unlike conventional pci bridge, some bits are hardwired to 0. */ > - pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, > - PCI_BRIDGE_CTL_PARITY | > - PCI_BRIDGE_CTL_ISA | > - PCI_BRIDGE_CTL_VGA | > - PCI_BRIDGE_CTL_SERR | > - PCI_BRIDGE_CTL_BUS_RESET); > -} > - > -/************************************************************************** > - * (chassis number, pcie physical slot number) -> pcie slot conversion > - */ > -struct PCIEChassis { > - uint8_t number; > - > - QLIST_HEAD(, PCIESlot) slots; > - QLIST_ENTRY(PCIEChassis) next; > -}; > - > -static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis); > - > -static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number) > -{ > - struct PCIEChassis *c; > - QLIST_FOREACH(c, &chassis, next) { > - if (c->number == chassis_number) { > - break; > - } > - } > - return c; > -} > - > -void pcie_chassis_create(uint8_t chassis_number) > -{ > - struct PCIEChassis *c; > - c = pcie_chassis_find(chassis_number); > - if (c) { > - return; > - } > - c = g_malloc0(sizeof(*c)); > - c->number = chassis_number; > - QLIST_INIT(&c->slots); > - QLIST_INSERT_HEAD(&chassis, c, next); > -} > - > -static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c, > - uint8_t slot) > -{ > - PCIESlot *s; > - QLIST_FOREACH(s, &c->slots, next) { > - if (s->slot == slot) { > - break; > - } > - } > - return s; > -} > - > -PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot) > -{ > - struct PCIEChassis *c; > - c = pcie_chassis_find(chassis_number); > - if (!c) { > - return NULL; > - } > - return pcie_chassis_find_slot_with_chassis(c, slot); > -} > - > -int pcie_chassis_add_slot(struct PCIESlot *slot) > -{ > - struct PCIEChassis *c; > - c = pcie_chassis_find(slot->chassis); > - if (!c) { > - return -ENODEV; > - } > - if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) { > - return -EBUSY; > - } > - QLIST_INSERT_HEAD(&c->slots, slot, next); > - return 0; > -} > - > -void pcie_chassis_del_slot(PCIESlot *s) > -{ > - QLIST_REMOVE(s, next); > -} > diff --git a/hw/pcie_port.h b/hw/pcie_port.h > deleted file mode 100644 > index 3709583..0000000 > --- a/hw/pcie_port.h > +++ /dev/null > @@ -1,51 +0,0 @@ > -/* > - * pcie_port.h > - * > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > - * VA Linux Systems Japan K.K. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - * > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - * You should have received a copy of the GNU General Public License along > - * with this program; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -#ifndef QEMU_PCIE_PORT_H > -#define QEMU_PCIE_PORT_H > - > -#include "pci_bridge.h" > -#include "pci_internals.h" > - > -struct PCIEPort { > - PCIBridge br; > - > - /* pci express switch port */ > - uint8_t port; > -}; > - > -void pcie_port_init_reg(PCIDevice *d); > - > -struct PCIESlot { > - PCIEPort port; > - > - /* pci express switch port with slot */ > - uint8_t chassis; > - uint16_t slot; > - QLIST_ENTRY(PCIESlot) next; > -}; > - > -void pcie_chassis_create(uint8_t chassis_number); > -void pcie_main_chassis_create(void); > -PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot); > -int pcie_chassis_add_slot(struct PCIESlot *slot); > -void pcie_chassis_del_slot(PCIESlot *s); > - > -#endif /* QEMU_PCIE_PORT_H */ > diff --git a/hw/pcie_regs.h b/hw/pcie_regs.h > deleted file mode 100644 > index 4d123d9..0000000 > --- a/hw/pcie_regs.h > +++ /dev/null > @@ -1,156 +0,0 @@ > -/* > - * constants for pcie configurations space from pci express spec. > - * > - * TODO: > - * Those constants and macros should go to Linux pci_regs.h > - * Once they're merged, they will go away. > - */ > -#ifndef QEMU_PCIE_REGS_H > -#define QEMU_PCIE_REGS_H > - > - > -/* express capability */ > - > -#define PCI_EXP_VER2_SIZEOF 0x3c /* express capability of ver. 2 */ > -#define PCI_EXT_CAP_VER_SHIFT 16 > -#define PCI_EXT_CAP_NEXT_SHIFT 20 > -#define PCI_EXT_CAP_NEXT_MASK (0xffc << PCI_EXT_CAP_NEXT_SHIFT) > - > -#define PCI_EXT_CAP(id, ver, next) \ > - ((id) | \ > - ((ver) << PCI_EXT_CAP_VER_SHIFT) | \ > - ((next) << PCI_EXT_CAP_NEXT_SHIFT)) > - > -#define PCI_EXT_CAP_ALIGN 4 > -#define PCI_EXT_CAP_ALIGNUP(x) \ > - (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1)) > - > -/* PCI_EXP_FLAGS */ > -#define PCI_EXP_FLAGS_VER2 2 /* for now, supports only ver. 2 */ > -#define PCI_EXP_FLAGS_IRQ_SHIFT (ffs(PCI_EXP_FLAGS_IRQ) - 1) > -#define PCI_EXP_FLAGS_TYPE_SHIFT (ffs(PCI_EXP_FLAGS_TYPE) - 1) > - > - > -/* PCI_EXP_LINK{CAP, STA} */ > -/* link speed */ > -#define PCI_EXP_LNK_LS_25 1 > - > -#define PCI_EXP_LNK_MLW_SHIFT (ffs(PCI_EXP_LNKCAP_MLW) - 1) > -#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT) > - > -/* PCI_EXP_LINKCAP */ > -#define PCI_EXP_LNKCAP_ASPMS_SHIFT (ffs(PCI_EXP_LNKCAP_ASPMS) - 1) > -#define PCI_EXP_LNKCAP_ASPMS_0S (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT) > - > -#define PCI_EXP_LNKCAP_PN_SHIFT (ffs(PCI_EXP_LNKCAP_PN) - 1) > - > -#define PCI_EXP_SLTCAP_PSN_SHIFT (ffs(PCI_EXP_SLTCAP_PSN) - 1) > - > -#define PCI_EXP_SLTCTL_IND_RESERVED 0x0 > -#define PCI_EXP_SLTCTL_IND_ON 0x1 > -#define PCI_EXP_SLTCTL_IND_BLINK 0x2 > -#define PCI_EXP_SLTCTL_IND_OFF 0x3 > -#define PCI_EXP_SLTCTL_AIC_SHIFT (ffs(PCI_EXP_SLTCTL_AIC) - 1) > -#define PCI_EXP_SLTCTL_AIC_OFF \ > - (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT) > - > -#define PCI_EXP_SLTCTL_PIC_SHIFT (ffs(PCI_EXP_SLTCTL_PIC) - 1) > -#define PCI_EXP_SLTCTL_PIC_OFF \ > - (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT) > - > -#define PCI_EXP_SLTCTL_SUPPORTED \ > - (PCI_EXP_SLTCTL_ABPE | \ > - PCI_EXP_SLTCTL_PDCE | \ > - PCI_EXP_SLTCTL_CCIE | \ > - PCI_EXP_SLTCTL_HPIE | \ > - PCI_EXP_SLTCTL_AIC | \ > - PCI_EXP_SLTCTL_PCC | \ > - PCI_EXP_SLTCTL_EIC) > - > -#define PCI_EXP_DEVCAP2_EFF 0x100000 > -#define PCI_EXP_DEVCAP2_EETLPP 0x200000 > - > -#define PCI_EXP_DEVCTL2_EETLPPB 0x80 > - > -/* ARI */ > -#define PCI_ARI_VER 1 > -#define PCI_ARI_SIZEOF 8 > - > -/* AER */ > -#define PCI_ERR_VER 2 > -#define PCI_ERR_SIZEOF 0x48 > - > -#define PCI_ERR_UNC_SDN 0x00000020 /* surprise down */ > -#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */ > -#define PCI_ERR_UNC_INTN 0x00400000 /* Internal Error */ > -#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC Blcoked TLP */ > -#define PCI_ERR_UNC_ATOP_EBLOCKED 0x01000000 /* atomic op egress blocked */ > -#define PCI_ERR_UNC_TLP_PRF_BLOCKED 0x02000000 /* TLP Prefix Blocked */ > -#define PCI_ERR_COR_ADV_NONFATAL 0x00002000 /* Advisory Non-Fatal */ > -#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected Internal */ > -#define PCI_ERR_COR_HL_OVERFLOW 0x00008000 /* Header Long Overflow */ > -#define PCI_ERR_CAP_FEP_MASK 0x0000001f > -#define PCI_ERR_CAP_MHRC 0x00000200 > -#define PCI_ERR_CAP_MHRE 0x00000400 > -#define PCI_ERR_CAP_TLP 0x00000800 > - > -#define PCI_ERR_HEADER_LOG_SIZE 16 > -#define PCI_ERR_TLP_PREFIX_LOG 0x38 > -#define PCI_ERR_TLP_PREFIX_LOG_SIZE 16 > - > -#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR 0x4000 > - > -/* aer root error command/status */ > -#define PCI_ERR_ROOT_CMD_EN_MASK (PCI_ERR_ROOT_CMD_COR_EN | \ > - PCI_ERR_ROOT_CMD_NONFATAL_EN | \ > - PCI_ERR_ROOT_CMD_FATAL_EN) > - > -#define PCI_ERR_ROOT_IRQ_MAX 32 > -#define PCI_ERR_ROOT_IRQ 0xf8000000 > -#define PCI_ERR_ROOT_IRQ_SHIFT (ffs(PCI_ERR_ROOT_IRQ) - 1) > -#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV | \ > - PCI_ERR_ROOT_MULTI_COR_RCV | \ > - PCI_ERR_ROOT_UNCOR_RCV | \ > - PCI_ERR_ROOT_MULTI_UNCOR_RCV | \ > - PCI_ERR_ROOT_FIRST_FATAL | \ > - PCI_ERR_ROOT_NONFATAL_RCV | \ > - PCI_ERR_ROOT_FATAL_RCV) > - > -#define PCI_ERR_UNC_SUPPORTED (PCI_ERR_UNC_DLP | \ > - PCI_ERR_UNC_SDN | \ > - PCI_ERR_UNC_POISON_TLP | \ > - PCI_ERR_UNC_FCP | \ > - PCI_ERR_UNC_COMP_TIME | \ > - PCI_ERR_UNC_COMP_ABORT | \ > - PCI_ERR_UNC_UNX_COMP | \ > - PCI_ERR_UNC_RX_OVER | \ > - PCI_ERR_UNC_MALF_TLP | \ > - PCI_ERR_UNC_ECRC | \ > - PCI_ERR_UNC_UNSUP | \ > - PCI_ERR_UNC_ACSV | \ > - PCI_ERR_UNC_INTN | \ > - PCI_ERR_UNC_MCBTLP | \ > - PCI_ERR_UNC_ATOP_EBLOCKED | \ > - PCI_ERR_UNC_TLP_PRF_BLOCKED) > - > -#define PCI_ERR_UNC_SEVERITY_DEFAULT (PCI_ERR_UNC_DLP | \ > - PCI_ERR_UNC_SDN | \ > - PCI_ERR_UNC_FCP | \ > - PCI_ERR_UNC_RX_OVER | \ > - PCI_ERR_UNC_MALF_TLP | \ > - PCI_ERR_UNC_INTN) > - > -#define PCI_ERR_COR_SUPPORTED (PCI_ERR_COR_RCVR | \ > - PCI_ERR_COR_BAD_TLP | \ > - PCI_ERR_COR_BAD_DLLP | \ > - PCI_ERR_COR_REP_ROLL | \ > - PCI_ERR_COR_REP_TIMER | \ > - PCI_ERR_COR_ADV_NONFATAL | \ > - PCI_ERR_COR_INTERNAL | \ > - PCI_ERR_COR_HL_OVERFLOW) > - > -#define PCI_ERR_COR_MASK_DEFAULT (PCI_ERR_COR_ADV_NONFATAL | \ > - PCI_ERR_COR_INTERNAL | \ > - PCI_ERR_COR_HL_OVERFLOW) > - > -#endif /* QEMU_PCIE_REGS_H */ > diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs > index 8fe2123..cb7cf8f 100644 > --- a/hw/ppc/Makefile.objs > +++ b/hw/ppc/Makefile.objs > @@ -10,7 +10,7 @@ obj-y += ppc_newworld.o > # IBM pSeries (sPAPR) > obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o > obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o > -obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o > +obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o > obj-$(CONFIG_PSERIES) += spapr_events.o > # PowerPC 4xx boards > obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o > diff --git a/hw/shpc.c b/hw/shpc.c > deleted file mode 100644 > index 4597bbd..0000000 > --- a/hw/shpc.c > +++ /dev/null > @@ -1,681 +0,0 @@ > -#include <strings.h> > -#include <stdint.h> > -#include "range.h" > -#include "range.h" > -#include "shpc.h" > -#include "pci.h" > -#include "pci_internals.h" > -#include "msi.h" > - > -/* TODO: model power only and disabled slot states. */ > -/* TODO: handle SERR and wakeups */ > -/* TODO: consider enabling 66MHz support */ > - > -/* TODO: remove fully only on state DISABLED and LED off. > - * track state to properly record this. */ > - > -/* SHPC Working Register Set */ > -#define SHPC_BASE_OFFSET 0x00 /* 4 bytes */ > -#define SHPC_SLOTS_33 0x04 /* 4 bytes. Also encodes PCI-X slots. */ > -#define SHPC_SLOTS_66 0x08 /* 4 bytes. */ > -#define SHPC_NSLOTS 0x0C /* 1 byte */ > -#define SHPC_FIRST_DEV 0x0D /* 1 byte */ > -#define SHPC_PHYS_SLOT 0x0E /* 2 byte */ > -#define SHPC_PHYS_NUM_MAX 0x7ff > -#define SHPC_PHYS_NUM_UP 0x2000 > -#define SHPC_PHYS_MRL 0x4000 > -#define SHPC_PHYS_BUTTON 0x8000 > -#define SHPC_SEC_BUS 0x10 /* 2 bytes */ > -#define SHPC_SEC_BUS_33 0x0 > -#define SHPC_SEC_BUS_66 0x1 /* Unused */ > -#define SHPC_SEC_BUS_MASK 0x7 > -#define SHPC_MSI_CTL 0x12 /* 1 byte */ > -#define SHPC_PROG_IFC 0x13 /* 1 byte */ > -#define SHPC_PROG_IFC_1_0 0x1 > -#define SHPC_CMD_CODE 0x14 /* 1 byte */ > -#define SHPC_CMD_TRGT 0x15 /* 1 byte */ > -#define SHPC_CMD_TRGT_MIN 0x1 > -#define SHPC_CMD_TRGT_MAX 0x1f > -#define SHPC_CMD_STATUS 0x16 /* 2 bytes */ > -#define SHPC_CMD_STATUS_BUSY 0x1 > -#define SHPC_CMD_STATUS_MRL_OPEN 0x2 > -#define SHPC_CMD_STATUS_INVALID_CMD 0x4 > -#define SHPC_CMD_STATUS_INVALID_MODE 0x8 > -#define SHPC_INT_LOCATOR 0x18 /* 4 bytes */ > -#define SHPC_INT_COMMAND 0x1 > -#define SHPC_SERR_LOCATOR 0x1C /* 4 bytes */ > -#define SHPC_SERR_INT 0x20 /* 4 bytes */ > -#define SHPC_INT_DIS 0x1 > -#define SHPC_SERR_DIS 0x2 > -#define SHPC_CMD_INT_DIS 0x4 > -#define SHPC_ARB_SERR_DIS 0x8 > -#define SHPC_CMD_DETECTED 0x10000 > -#define SHPC_ARB_DETECTED 0x20000 > - /* 4 bytes * slot # (start from 0) */ > -#define SHPC_SLOT_REG(s) (0x24 + (s) * 4) > - /* 2 bytes */ > -#define SHPC_SLOT_STATUS(s) (0x0 + SHPC_SLOT_REG(s)) > - > -/* Same slot state masks are used for command and status registers */ > -#define SHPC_SLOT_STATE_MASK 0x03 > -#define SHPC_SLOT_STATE_SHIFT \ > - (ffs(SHPC_SLOT_STATE_MASK) - 1) > - > -#define SHPC_STATE_NO 0x0 > -#define SHPC_STATE_PWRONLY 0x1 > -#define SHPC_STATE_ENABLED 0x2 > -#define SHPC_STATE_DISABLED 0x3 > - > -#define SHPC_SLOT_PWR_LED_MASK 0xC > -#define SHPC_SLOT_PWR_LED_SHIFT \ > - (ffs(SHPC_SLOT_PWR_LED_MASK) - 1) > -#define SHPC_SLOT_ATTN_LED_MASK 0x30 > -#define SHPC_SLOT_ATTN_LED_SHIFT \ > - (ffs(SHPC_SLOT_ATTN_LED_MASK) - 1) > - > -#define SHPC_LED_NO 0x0 > -#define SHPC_LED_ON 0x1 > -#define SHPC_LED_BLINK 0x2 > -#define SHPC_LED_OFF 0x3 > - > -#define SHPC_SLOT_STATUS_PWR_FAULT 0x40 > -#define SHPC_SLOT_STATUS_BUTTON 0x80 > -#define SHPC_SLOT_STATUS_MRL_OPEN 0x100 > -#define SHPC_SLOT_STATUS_66 0x200 > -#define SHPC_SLOT_STATUS_PRSNT_MASK 0xC00 > -#define SHPC_SLOT_STATUS_PRSNT_EMPTY 0x3 > -#define SHPC_SLOT_STATUS_PRSNT_25W 0x1 > -#define SHPC_SLOT_STATUS_PRSNT_15W 0x2 > -#define SHPC_SLOT_STATUS_PRSNT_7_5W 0x0 > - > -#define SHPC_SLOT_STATUS_PRSNT_PCIX 0x3000 > - > - > - /* 1 byte */ > -#define SHPC_SLOT_EVENT_LATCH(s) (0x2 + SHPC_SLOT_REG(s)) > - /* 1 byte */ > -#define SHPC_SLOT_EVENT_SERR_INT_DIS(d, s) (0x3 + SHPC_SLOT_REG(s)) > -#define SHPC_SLOT_EVENT_PRESENCE 0x01 > -#define SHPC_SLOT_EVENT_ISOLATED_FAULT 0x02 > -#define SHPC_SLOT_EVENT_BUTTON 0x04 > -#define SHPC_SLOT_EVENT_MRL 0x08 > -#define SHPC_SLOT_EVENT_CONNECTED_FAULT 0x10 > -/* Bits below are used for Serr/Int disable only */ > -#define SHPC_SLOT_EVENT_MRL_SERR_DIS 0x20 > -#define SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS 0x40 > - > -#define SHPC_MIN_SLOTS 1 > -#define SHPC_MAX_SLOTS 31 > -#define SHPC_SIZEOF(d) SHPC_SLOT_REG((d)->shpc->nslots) > - > -/* SHPC Slot identifiers */ > - > -/* Hotplug supported at 31 slots out of the total 32. We reserve slot 0, > - and give the rest of them physical *and* pci numbers starting from 1, so > - they match logical numbers. Note: this means that multiple slots must have > - different chassis number values, to make chassis+physical slot unique. > - TODO: make this configurable? */ > -#define SHPC_IDX_TO_LOGICAL(slot) ((slot) + 1) > -#define SHPC_LOGICAL_TO_IDX(target) ((target) - 1) > -#define SHPC_IDX_TO_PCI(slot) ((slot) + 1) > -#define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1) > -#define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1) > - > -static int roundup_pow_of_two(int x) > -{ > - x |= (x >> 1); > - x |= (x >> 2); > - x |= (x >> 4); > - x |= (x >> 8); > - x |= (x >> 16); > - return x + 1; > -} > - > -static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk) > -{ > - uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); > - return (pci_get_word(status) & msk) >> (ffs(msk) - 1); > -} > - > -static void shpc_set_status(SHPCDevice *shpc, > - int slot, uint8_t value, uint16_t msk) > -{ > - uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); > - pci_word_test_and_clear_mask(status, msk); > - pci_word_test_and_set_mask(status, value << (ffs(msk) - 1)); > -} > - > -static void shpc_interrupt_update(PCIDevice *d) > -{ > - SHPCDevice *shpc = d->shpc; > - int slot; > - int level = 0; > - uint32_t serr_int; > - uint32_t int_locator = 0; > - > - /* Update interrupt locator register */ > - for (slot = 0; slot < shpc->nslots; ++slot) { > - uint8_t event = shpc->config[SHPC_SLOT_EVENT_LATCH(slot)]; > - uint8_t disable = shpc->config[SHPC_SLOT_EVENT_SERR_INT_DIS(d, slot)]; > - uint32_t mask = 1 << SHPC_IDX_TO_LOGICAL(slot); > - if (event & ~disable) { > - int_locator |= mask; > - } > - } > - serr_int = pci_get_long(shpc->config + SHPC_SERR_INT); > - if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_DIS)) { > - int_locator |= SHPC_INT_COMMAND; > - } > - pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator); > - level = (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0; > - if (msi_enabled(d) && shpc->msi_requested != level) > - msi_notify(d, 0); > - else > - qemu_set_irq(d->irq[0], level); > - shpc->msi_requested = level; > -} > - > -static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed) > -{ > - switch (speed) { > - case SHPC_SEC_BUS_33: > - shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK; > - shpc->config[SHPC_SEC_BUS] |= speed; > - break; > - default: > - pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, > - SHPC_CMD_STATUS_INVALID_MODE); > - } > -} > - > -void shpc_reset(PCIDevice *d) > -{ > - SHPCDevice *shpc = d->shpc; > - int nslots = shpc->nslots; > - int i; > - memset(shpc->config, 0, SHPC_SIZEOF(d)); > - pci_set_byte(shpc->config + SHPC_NSLOTS, nslots); > - pci_set_long(shpc->config + SHPC_SLOTS_33, nslots); > - pci_set_long(shpc->config + SHPC_SLOTS_66, 0); > - pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0)); > - pci_set_word(shpc->config + SHPC_PHYS_SLOT, > - SHPC_IDX_TO_PHYSICAL(0) | > - SHPC_PHYS_NUM_UP | > - SHPC_PHYS_MRL | > - SHPC_PHYS_BUTTON); > - pci_set_long(shpc->config + SHPC_SERR_INT, SHPC_INT_DIS | > - SHPC_SERR_DIS | > - SHPC_CMD_INT_DIS | > - SHPC_ARB_SERR_DIS); > - pci_set_byte(shpc->config + SHPC_PROG_IFC, SHPC_PROG_IFC_1_0); > - pci_set_word(shpc->config + SHPC_SEC_BUS, SHPC_SEC_BUS_33); > - for (i = 0; i < shpc->nslots; ++i) { > - pci_set_byte(shpc->config + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), > - SHPC_SLOT_EVENT_PRESENCE | > - SHPC_SLOT_EVENT_ISOLATED_FAULT | > - SHPC_SLOT_EVENT_BUTTON | > - SHPC_SLOT_EVENT_MRL | > - SHPC_SLOT_EVENT_CONNECTED_FAULT | > - SHPC_SLOT_EVENT_MRL_SERR_DIS | > - SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); > - if (shpc->sec_bus->devices[PCI_DEVFN(SHPC_IDX_TO_PCI(i), 0)]) { > - shpc_set_status(shpc, i, SHPC_STATE_ENABLED, SHPC_SLOT_STATE_MASK); > - shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_MRL_OPEN); > - shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_7_5W, > - SHPC_SLOT_STATUS_PRSNT_MASK); > - shpc_set_status(shpc, i, SHPC_LED_ON, SHPC_SLOT_PWR_LED_MASK); > - } else { > - shpc_set_status(shpc, i, SHPC_STATE_DISABLED, SHPC_SLOT_STATE_MASK); > - shpc_set_status(shpc, i, 1, SHPC_SLOT_STATUS_MRL_OPEN); > - shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_EMPTY, > - SHPC_SLOT_STATUS_PRSNT_MASK); > - shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK); > - } > - shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66); > - } > - shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33); > - shpc->msi_requested = 0; > - shpc_interrupt_update(d); > -} > - > -static void shpc_invalid_command(SHPCDevice *shpc) > -{ > - pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, > - SHPC_CMD_STATUS_INVALID_CMD); > -} > - > -static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot) > -{ > - int devfn; > - int pci_slot = SHPC_IDX_TO_PCI(slot); > - for (devfn = PCI_DEVFN(pci_slot, 0); > - devfn <= PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1); > - ++devfn) { > - PCIDevice *affected_dev = shpc->sec_bus->devices[devfn]; > - if (affected_dev) { > - qdev_free(&affected_dev->qdev); > - } > - } > -} > - > -static void shpc_slot_command(SHPCDevice *shpc, uint8_t target, > - uint8_t state, uint8_t power, uint8_t attn) > -{ > - uint8_t current_state; > - int slot = SHPC_LOGICAL_TO_IDX(target); > - if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) { > - shpc_invalid_command(shpc); > - return; > - } > - current_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); > - if (current_state == SHPC_STATE_ENABLED && state == SHPC_STATE_PWRONLY) { > - shpc_invalid_command(shpc); > - return; > - } > - > - switch (power) { > - case SHPC_LED_NO: > - break; > - default: > - /* TODO: send event to monitor */ > - shpc_set_status(shpc, slot, power, SHPC_SLOT_PWR_LED_MASK); > - } > - switch (attn) { > - case SHPC_LED_NO: > - break; > - default: > - /* TODO: send event to monitor */ > - shpc_set_status(shpc, slot, attn, SHPC_SLOT_ATTN_LED_MASK); > - } > - > - if ((current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_PWRONLY) || > - (current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_ENABLED)) { > - shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > - } else if ((current_state == SHPC_STATE_ENABLED || > - current_state == SHPC_STATE_PWRONLY) && > - state == SHPC_STATE_DISABLED) { > - shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > - power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); > - /* TODO: track what monitor requested. */ > - /* Look at LED to figure out whether it's ok to remove the device. */ > - if (power == SHPC_LED_OFF) { > - shpc_free_devices_in_slot(shpc, slot); > - shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); > - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, > - SHPC_SLOT_STATUS_PRSNT_MASK); > - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > - SHPC_SLOT_EVENT_BUTTON | > - SHPC_SLOT_EVENT_MRL | > - SHPC_SLOT_EVENT_PRESENCE; > - } > - } > -} > - > -static void shpc_command(SHPCDevice *shpc) > -{ > - uint8_t code = pci_get_byte(shpc->config + SHPC_CMD_CODE); > - uint8_t speed; > - uint8_t target; > - uint8_t attn; > - uint8_t power; > - uint8_t state; > - int i; > - > - /* Clear status from the previous command. */ > - pci_word_test_and_clear_mask(shpc->config + SHPC_CMD_STATUS, > - SHPC_CMD_STATUS_BUSY | > - SHPC_CMD_STATUS_MRL_OPEN | > - SHPC_CMD_STATUS_INVALID_CMD | > - SHPC_CMD_STATUS_INVALID_MODE); > - switch (code) { > - case 0x00 ... 0x3f: > - target = shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX; > - state = (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_SHIFT; > - power = (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_LED_SHIFT; > - attn = (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_LED_SHIFT; > - shpc_slot_command(shpc, target, state, power, attn); > - break; > - case 0x40 ... 0x47: > - speed = code & SHPC_SEC_BUS_MASK; > - shpc_set_sec_bus_speed(shpc, speed); > - break; > - case 0x48: > - /* Power only all slots */ > - /* first verify no slots are enabled */ > - for (i = 0; i < shpc->nslots; ++i) { > - state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); > - if (state == SHPC_STATE_ENABLED) { > - shpc_invalid_command(shpc); > - goto done; > - } > - } > - for (i = 0; i < shpc->nslots; ++i) { > - if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { > - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > - SHPC_STATE_PWRONLY, SHPC_LED_ON, SHPC_LED_NO); > - } else { > - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > - SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); > - } > - } > - break; > - case 0x49: > - /* Enable all slots */ > - /* TODO: Spec says this shall fail if some are already enabled. > - * This doesn't make sense - why not? a spec bug? */ > - for (i = 0; i < shpc->nslots; ++i) { > - state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); > - if (state == SHPC_STATE_ENABLED) { > - shpc_invalid_command(shpc); > - goto done; > - } > - } > - for (i = 0; i < shpc->nslots; ++i) { > - if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { > - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > - SHPC_STATE_ENABLED, SHPC_LED_ON, SHPC_LED_NO); > - } else { > - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > - SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); > - } > - } > - break; > - default: > - shpc_invalid_command(shpc); > - break; > - } > -done: > - pci_long_test_and_set_mask(shpc->config + SHPC_SERR_INT, SHPC_CMD_DETECTED); > -} > - > -static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, int l) > -{ > - SHPCDevice *shpc = d->shpc; > - int i; > - if (addr >= SHPC_SIZEOF(d)) { > - return; > - } > - l = MIN(l, SHPC_SIZEOF(d) - addr); > - > - /* TODO: code duplicated from pci.c */ > - for (i = 0; i < l; val >>= 8, ++i) { > - unsigned a = addr + i; > - uint8_t wmask = shpc->wmask[a]; > - uint8_t w1cmask = shpc->w1cmask[a]; > - assert(!(wmask & w1cmask)); > - shpc->config[a] = (shpc->config[a] & ~wmask) | (val & wmask); > - shpc->config[a] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ > - } > - if (ranges_overlap(addr, l, SHPC_CMD_CODE, 2)) { > - shpc_command(shpc); > - } > - shpc_interrupt_update(d); > -} > - > -static uint64_t shpc_read(PCIDevice *d, unsigned addr, int l) > -{ > - uint64_t val = 0x0; > - if (addr >= SHPC_SIZEOF(d)) { > - return val; > - } > - l = MIN(l, SHPC_SIZEOF(d) - addr); > - memcpy(&val, d->shpc->config + addr, l); > - return val; > -} > - > -/* SHPC Bridge Capability */ > -#define SHPC_CAP_LENGTH 0x08 > -#define SHPC_CAP_DWORD_SELECT 0x2 /* 1 byte */ > -#define SHPC_CAP_CxP 0x3 /* 1 byte: CSP, CIP */ > -#define SHPC_CAP_DWORD_DATA 0x4 /* 4 bytes */ > -#define SHPC_CAP_CSP_MASK 0x4 > -#define SHPC_CAP_CIP_MASK 0x8 > - > -static uint8_t shpc_cap_dword(PCIDevice *d) > -{ > - return pci_get_byte(d->config + d->shpc->cap + SHPC_CAP_DWORD_SELECT); > -} > - > -/* Update dword data capability register */ > -static void shpc_cap_update_dword(PCIDevice *d) > -{ > - unsigned data; > - data = shpc_read(d, shpc_cap_dword(d) * 4, 4); > - pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, data); > -} > - > -/* Add SHPC capability to the config space for the device. */ > -static int shpc_cap_add_config(PCIDevice *d) > -{ > - uint8_t *config; > - int config_offset; > - config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC, > - 0, SHPC_CAP_LENGTH); > - if (config_offset < 0) { > - return config_offset; > - } > - config = d->config + config_offset; > - > - pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0); > - pci_set_byte(config + SHPC_CAP_CxP, 0); > - pci_set_long(config + SHPC_CAP_DWORD_DATA, 0); > - d->shpc->cap = config_offset; > - /* Make dword select and data writeable. */ > - pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff); > - pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff); > - return 0; > -} > - > -static uint64_t shpc_mmio_read(void *opaque, hwaddr addr, > - unsigned size) > -{ > - return shpc_read(opaque, addr, size); > -} > - > -static void shpc_mmio_write(void *opaque, hwaddr addr, > - uint64_t val, unsigned size) > -{ > - shpc_write(opaque, addr, val, size); > -} > - > -static const MemoryRegionOps shpc_mmio_ops = { > - .read = shpc_mmio_read, > - .write = shpc_mmio_write, > - .endianness = DEVICE_LITTLE_ENDIAN, > - .valid = { > - /* SHPC ECN requires dword accesses, but the original 1.0 spec doesn't. > - * It's easier to suppport all sizes than worry about it. */ > - .min_access_size = 1, > - .max_access_size = 4, > - }, > -}; > - > -static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev, > - PCIHotplugState hotplug_state) > -{ > - int pci_slot = PCI_SLOT(affected_dev->devfn); > - uint8_t state; > - uint8_t led; > - PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); > - SHPCDevice *shpc = d->shpc; > - int slot = SHPC_PCI_TO_IDX(pci_slot); > - if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) { > - error_report("Unsupported PCI slot %d for standard hotplug " > - "controller. Valid slots are between %d and %d.", > - pci_slot, SHPC_IDX_TO_PCI(0), > - SHPC_IDX_TO_PCI(shpc->nslots) - 1); > - return -1; > - } > - /* Don't send event when device is enabled during qemu machine creation: > - * it is present on boot, no hotplug event is necessary. We do send an > - * event when the device is disabled later. */ > - if (hotplug_state == PCI_COLDPLUG_ENABLED) { > - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); > - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, > - SHPC_SLOT_STATUS_PRSNT_MASK); > - return 0; > - } > - if (hotplug_state == PCI_HOTPLUG_DISABLED) { > - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON; > - state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); > - led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); > - if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) { > - shpc_free_devices_in_slot(shpc, slot); > - shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); > - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, > - SHPC_SLOT_STATUS_PRSNT_MASK); > - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > - SHPC_SLOT_EVENT_MRL | > - SHPC_SLOT_EVENT_PRESENCE; > - } > - } else { > - /* This could be a cancellation of the previous removal. > - * We check MRL state to figure out. */ > - if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) { > - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); > - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, > - SHPC_SLOT_STATUS_PRSNT_MASK); > - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > - SHPC_SLOT_EVENT_BUTTON | > - SHPC_SLOT_EVENT_MRL | > - SHPC_SLOT_EVENT_PRESENCE; > - } else { > - /* Press attention button to cancel removal */ > - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > - SHPC_SLOT_EVENT_BUTTON; > - } > - } > - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66); > - shpc_interrupt_update(d); > - return 0; > -} > - > -/* Initialize the SHPC structure in bridge's BAR. */ > -int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset) > -{ > - int i, ret; > - int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */ > - SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc)); > - shpc->sec_bus = sec_bus; > - ret = shpc_cap_add_config(d); > - if (ret) { > - g_free(d->shpc); > - return ret; > - } > - if (nslots < SHPC_MIN_SLOTS) { > - return 0; > - } > - if (nslots > SHPC_MAX_SLOTS || > - SHPC_IDX_TO_PCI(nslots) > PCI_SLOT_MAX) { > - /* TODO: report an error mesage that makes sense. */ > - return -EINVAL; > - } > - shpc->nslots = nslots; > - shpc->config = g_malloc0(SHPC_SIZEOF(d)); > - shpc->cmask = g_malloc0(SHPC_SIZEOF(d)); > - shpc->wmask = g_malloc0(SHPC_SIZEOF(d)); > - shpc->w1cmask = g_malloc0(SHPC_SIZEOF(d)); > - > - shpc_reset(d); > - > - pci_set_long(shpc->config + SHPC_BASE_OFFSET, offset); > - > - pci_set_byte(shpc->wmask + SHPC_CMD_CODE, 0xff); > - pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); > - pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); > - pci_set_long(shpc->wmask + SHPC_SERR_INT, > - SHPC_INT_DIS | > - SHPC_SERR_DIS | > - SHPC_CMD_INT_DIS | > - SHPC_ARB_SERR_DIS); > - pci_set_long(shpc->w1cmask + SHPC_SERR_INT, > - SHPC_CMD_DETECTED | > - SHPC_ARB_DETECTED); > - for (i = 0; i < nslots; ++i) { > - pci_set_byte(shpc->wmask + > - SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), > - SHPC_SLOT_EVENT_PRESENCE | > - SHPC_SLOT_EVENT_ISOLATED_FAULT | > - SHPC_SLOT_EVENT_BUTTON | > - SHPC_SLOT_EVENT_MRL | > - SHPC_SLOT_EVENT_CONNECTED_FAULT | > - SHPC_SLOT_EVENT_MRL_SERR_DIS | > - SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); > - pci_set_byte(shpc->w1cmask + > - SHPC_SLOT_EVENT_LATCH(i), > - SHPC_SLOT_EVENT_PRESENCE | > - SHPC_SLOT_EVENT_ISOLATED_FAULT | > - SHPC_SLOT_EVENT_BUTTON | > - SHPC_SLOT_EVENT_MRL | > - SHPC_SLOT_EVENT_CONNECTED_FAULT); > - } > - > - /* TODO: init cmask */ > - memory_region_init_io(&shpc->mmio, &shpc_mmio_ops, d, "shpc-mmio", > - SHPC_SIZEOF(d)); > - shpc_cap_update_dword(d); > - memory_region_add_subregion(bar, offset, &shpc->mmio); > - pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev); > - > - d->cap_present |= QEMU_PCI_CAP_SHPC; > - return 0; > -} > - > -int shpc_bar_size(PCIDevice *d) > -{ > - return roundup_pow_of_two(SHPC_SLOT_REG(SHPC_MAX_SLOTS)); > -} > - > -void shpc_cleanup(PCIDevice *d, MemoryRegion *bar) > -{ > - SHPCDevice *shpc = d->shpc; > - d->cap_present &= ~QEMU_PCI_CAP_SHPC; > - memory_region_del_subregion(bar, &shpc->mmio); > - /* TODO: cleanup config space changes? */ > - g_free(shpc->config); > - g_free(shpc->cmask); > - g_free(shpc->wmask); > - g_free(shpc->w1cmask); > - memory_region_destroy(&shpc->mmio); > - g_free(shpc); > -} > - > -void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) > -{ > - if (!ranges_overlap(addr, l, d->shpc->cap, SHPC_CAP_LENGTH)) { > - return; > - } > - if (ranges_overlap(addr, l, d->shpc->cap + SHPC_CAP_DWORD_DATA, 4)) { > - unsigned dword_data; > - dword_data = pci_get_long(d->shpc->config + d->shpc->cap > - + SHPC_CAP_DWORD_DATA); > - shpc_write(d, shpc_cap_dword(d) * 4, dword_data, 4); > - } > - /* Update cap dword data in case guest is going to read it. */ > - shpc_cap_update_dword(d); > -} > - > -static void shpc_save(QEMUFile *f, void *pv, size_t size) > -{ > - PCIDevice *d = container_of(pv, PCIDevice, shpc); > - qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); > -} > - > -static int shpc_load(QEMUFile *f, void *pv, size_t size) > -{ > - PCIDevice *d = container_of(pv, PCIDevice, shpc); > - int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); > - if (ret != SHPC_SIZEOF(d)) { > - return -EINVAL; > - } > - /* Make sure we don't lose notifications. An extra interrupt is harmless. */ > - d->shpc->msi_requested = 0; > - shpc_interrupt_update(d); > - return 0; > -} > - > -VMStateInfo shpc_vmstate_info = { > - .name = "shpc", > - .get = shpc_load, > - .put = shpc_save, > -}; > diff --git a/hw/shpc.h b/hw/shpc.h > deleted file mode 100644 > index 130b71d..0000000 > --- a/hw/shpc.h > +++ /dev/null > @@ -1,48 +0,0 @@ > -#ifndef SHPC_H > -#define SHPC_H > - > -#include "qemu-common.h" > -#include "memory.h" > -#include "vmstate.h" > - > -struct SHPCDevice { > - /* Capability offset in device's config space */ > - int cap; > - > - /* # of hot-pluggable slots */ > - int nslots; > - > - /* SHPC WRS: working register set */ > - uint8_t *config; > - > - /* Used to enable checks on load. Note that writable bits are > - * never checked even if set in cmask. */ > - uint8_t *cmask; > - > - /* Used to implement R/W bytes */ > - uint8_t *wmask; > - > - /* Used to implement RW1C(Write 1 to Clear) bytes */ > - uint8_t *w1cmask; > - > - /* MMIO for the SHPC BAR */ > - MemoryRegion mmio; > - > - /* Bus controlled by this SHPC */ > - PCIBus *sec_bus; > - > - /* MSI already requested for this event */ > - int msi_requested; > -}; > - > -void shpc_reset(PCIDevice *d); > -int shpc_bar_size(PCIDevice *dev); > -int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off); > -void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar); > -void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len); > - > -extern VMStateInfo shpc_vmstate_info; > -#define SHPC_VMSTATE(_field, _type) \ > - VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0) > - > -#endif > diff --git a/hw/slotid_cap.c b/hw/slotid_cap.c > deleted file mode 100644 > index 0106452..0000000 > --- a/hw/slotid_cap.c > +++ /dev/null > @@ -1,44 +0,0 @@ > -#include "slotid_cap.h" > -#include "pci.h" > - > -#define SLOTID_CAP_LENGTH 4 > -#define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1) > - > -int slotid_cap_init(PCIDevice *d, int nslots, > - uint8_t chassis, > - unsigned offset) > -{ > - int cap; > - if (!chassis) { > - error_report("Bridge chassis not specified. Each bridge is required " > - "to be assigned a unique chassis id > 0."); > - return -EINVAL; > - } > - if (nslots < 0 || nslots > (PCI_SID_ESR_NSLOTS >> SLOTID_NSLOTS_SHIFT)) { > - /* TODO: error report? */ > - return -EINVAL; > - } > - > - cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset, SLOTID_CAP_LENGTH); > - if (cap < 0) { > - return cap; > - } > - /* We make each chassis unique, this way each bridge is First in Chassis */ > - d->config[cap + PCI_SID_ESR] = PCI_SID_ESR_FIC | > - (nslots << SLOTID_NSLOTS_SHIFT); > - d->cmask[cap + PCI_SID_ESR] = 0xff; > - d->config[cap + PCI_SID_CHASSIS_NR] = chassis; > - /* Note: Chassis number register is non-volatile, > - so we don't reset it. */ > - /* TODO: store in eeprom? */ > - d->wmask[cap + PCI_SID_CHASSIS_NR] = 0xff; > - > - d->cap_present |= QEMU_PCI_CAP_SLOTID; > - return 0; > -} > - > -void slotid_cap_cleanup(PCIDevice *d) > -{ > - /* TODO: cleanup config space? */ > - d->cap_present &= ~QEMU_PCI_CAP_SLOTID; > -} > diff --git a/hw/slotid_cap.h b/hw/slotid_cap.h > deleted file mode 100644 > index 70db047..0000000 > --- a/hw/slotid_cap.h > +++ /dev/null > @@ -1,11 +0,0 @@ > -#ifndef PCI_SLOTID_CAP_H > -#define PCI_SLOTID_CAP_H > - > -#include "qemu-common.h" > - > -int slotid_cap_init(PCIDevice *dev, int nslots, > - uint8_t chassis, > - unsigned offset); > -void slotid_cap_cleanup(PCIDevice *dev); > - > -#endif > -- > MST > > ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci 2012-12-12 19:53 ` Blue Swirl @ 2012-12-12 20:56 ` Michael S. Tsirkin 0 siblings, 0 replies; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 20:56 UTC (permalink / raw) To: Blue Swirl; +Cc: qemu-devel 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 <mst@redhat.com> wrote: > > Move files and modify makefiles to pick them at the > > new location. > > 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 <mst@redhat.com> > > --- > > hw/Makefile.objs | 10 +- > > hw/i386/Makefile.objs | 2 +- > > hw/msi.c | 395 --------- > > hw/msi.h | 50 -- > > hw/msix.c | 562 ------------- > > hw/msix.h | 41 - > > hw/pci-hotplug.c | 293 ------- > > hw/pci-stub.c | 47 -- > > hw/pci.c | 2168 ------------------------------------------------ > > hw/pci.h | 684 --------------- > > hw/pci/Makefile.objs | 6 + > > hw/pci/msi.c | 395 +++++++++ > > hw/pci/msi.h | 50 ++ > > hw/pci/msix.c | 562 +++++++++++++ > > hw/pci/msix.h | 41 + > > hw/pci/pci-hotplug.c | 293 +++++++ > > hw/pci/pci-stub.c | 47 ++ > > hw/pci/pci.c | 2168 ++++++++++++++++++++++++++++++++++++++++++++++++ > > hw/pci/pci.h | 684 +++++++++++++++ > > hw/pci/pci_bridge.c | 363 ++++++++ > > hw/pci/pci_bridge.h | 66 ++ > > hw/pci/pci_host.c | 180 ++++ > > hw/pci/pci_host.h | 62 ++ > > hw/pci/pci_ids.h | 147 ++++ > > hw/pci/pci_internals.h | 78 ++ > > hw/pci/pci_regs.h | 717 ++++++++++++++++ > > hw/pci/pcie.c | 555 +++++++++++++ > > hw/pci/pcie.h | 142 ++++ > > hw/pci/pcie_aer.c | 1032 +++++++++++++++++++++++ > > hw/pci/pcie_aer.h | 106 +++ > > hw/pci/pcie_host.c | 161 ++++ > > hw/pci/pcie_host.h | 54 ++ > > hw/pci/pcie_port.c | 114 +++ > > hw/pci/pcie_port.h | 51 ++ > > hw/pci/pcie_regs.h | 156 ++++ > > hw/pci/shpc.c | 681 +++++++++++++++ > > hw/pci/shpc.h | 48 ++ > > hw/pci/slotid_cap.c | 44 + > > hw/pci/slotid_cap.h | 11 + > > hw/pci_bridge.c | 363 -------- > > hw/pci_bridge.h | 66 -- > > hw/pci_host.c | 180 ---- > > hw/pci_host.h | 62 -- > > hw/pci_ids.h | 147 ---- > > hw/pci_internals.h | 78 -- > > hw/pci_regs.h | 717 ---------------- > > hw/pcie.c | 555 ------------- > > hw/pcie.h | 142 ---- > > hw/pcie_aer.c | 1032 ----------------------- > > hw/pcie_aer.h | 106 --- > > hw/pcie_host.c | 161 ---- > > hw/pcie_host.h | 54 -- > > hw/pcie_port.c | 114 --- > > hw/pcie_port.h | 51 -- > > hw/pcie_regs.h | 156 ---- > > hw/ppc/Makefile.objs | 2 +- > > hw/shpc.c | 681 --------------- > > hw/shpc.h | 48 -- > > hw/slotid_cap.c | 44 - > > hw/slotid_cap.h | 11 - > > 60 files changed, 9018 insertions(+), 9018 deletions(-) > > delete mode 100644 hw/msi.c > > delete mode 100644 hw/msi.h > > delete mode 100644 hw/msix.c > > delete mode 100644 hw/msix.h > > delete mode 100644 hw/pci-hotplug.c > > delete mode 100644 hw/pci-stub.c > > delete mode 100644 hw/pci.c > > delete mode 100644 hw/pci.h > > create mode 100644 hw/pci/Makefile.objs > > create mode 100644 hw/pci/msi.c > > create mode 100644 hw/pci/msi.h > > create mode 100644 hw/pci/msix.c > > create mode 100644 hw/pci/msix.h > > create mode 100644 hw/pci/pci-hotplug.c > > create mode 100644 hw/pci/pci-stub.c > > create mode 100644 hw/pci/pci.c > > create mode 100644 hw/pci/pci.h > > create mode 100644 hw/pci/pci_bridge.c > > create mode 100644 hw/pci/pci_bridge.h > > create mode 100644 hw/pci/pci_host.c > > create mode 100644 hw/pci/pci_host.h > > create mode 100644 hw/pci/pci_ids.h > > create mode 100644 hw/pci/pci_internals.h > > create mode 100644 hw/pci/pci_regs.h > > create mode 100644 hw/pci/pcie.c > > create mode 100644 hw/pci/pcie.h > > create mode 100644 hw/pci/pcie_aer.c > > create mode 100644 hw/pci/pcie_aer.h > > create mode 100644 hw/pci/pcie_host.c > > create mode 100644 hw/pci/pcie_host.h > > create mode 100644 hw/pci/pcie_port.c > > create mode 100644 hw/pci/pcie_port.h > > create mode 100644 hw/pci/pcie_regs.h > > create mode 100644 hw/pci/shpc.c > > create mode 100644 hw/pci/shpc.h > > create mode 100644 hw/pci/slotid_cap.c > > create mode 100644 hw/pci/slotid_cap.h > > delete mode 100644 hw/pci_bridge.c > > delete mode 100644 hw/pci_bridge.h > > delete mode 100644 hw/pci_host.c > > delete mode 100644 hw/pci_host.h > > delete mode 100644 hw/pci_ids.h > > delete mode 100644 hw/pci_internals.h > > delete mode 100644 hw/pci_regs.h > > delete mode 100644 hw/pcie.c > > delete mode 100644 hw/pcie.h > > delete mode 100644 hw/pcie_aer.c > > delete mode 100644 hw/pcie_aer.h > > delete mode 100644 hw/pcie_host.c > > delete mode 100644 hw/pcie_host.h > > delete mode 100644 hw/pcie_port.c > > delete mode 100644 hw/pcie_port.h > > delete mode 100644 hw/pcie_regs.h > > delete mode 100644 hw/shpc.c > > delete mode 100644 hw/shpc.h > > delete mode 100644 hw/slotid_cap.c > > delete mode 100644 hw/slotid_cap.h > > > > diff --git a/hw/Makefile.objs b/hw/Makefile.objs > > index d581d8d..228acd6 100644 > > --- a/hw/Makefile.objs > > +++ b/hw/Makefile.objs > > @@ -1,14 +1,10 @@ > > -common-obj-y = usb/ ide/ > > +common-obj-y = usb/ ide/ pci/ > > common-obj-y += loader.o > > common-obj-$(CONFIG_VIRTIO) += virtio-console.o > > common-obj-$(CONFIG_VIRTIO) += virtio-rng.o > > common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o > > common-obj-y += fw_cfg.o > > -common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o > > -common-obj-$(CONFIG_PCI) += msix.o msi.o > > -common-obj-$(CONFIG_PCI) += shpc.o > > -common-obj-$(CONFIG_PCI) += slotid_cap.o > > -common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o > > +common-obj-$(CONFIG_PCI) += pci_bridge_dev.o > > common-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o > > common-obj-$(CONFIG_PCI) += i82801b11.o > > common-obj-y += watchdog.o > > @@ -102,8 +98,6 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o > > # PCI watchdog devices > > common-obj-$(CONFIG_PCI) += wdt_i6300esb.o > > > > -common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o > > - > > # PCI network cards > > common-obj-$(CONFIG_NE2000_PCI) += ne2000.o > > common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o > > diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs > > index 0d3f6a8..257f3c1 100644 > > --- a/hw/i386/Makefile.objs > > +++ b/hw/i386/Makefile.objs > > @@ -2,7 +2,7 @@ obj-y += mc146818rtc.o pc.o > > obj-y += apic_common.o apic.o kvmvapic.o > > obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o > > obj-y += vmport.o > > -obj-y += pci-hotplug.o smbios.o wdt_ib700.o > > +obj-y += pci/pci-hotplug.o smbios.o wdt_ib700.o > > obj-y += debugcon.o multiboot.o > > obj-y += pc_piix.o > > obj-y += pc_sysfw.o > > diff --git a/hw/msi.c b/hw/msi.c > > deleted file mode 100644 > > index 33037a8..0000000 > > --- a/hw/msi.c > > +++ /dev/null > > @@ -1,395 +0,0 @@ > > -/* > > - * msi.c > > - * > > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#include "msi.h" > > -#include "range.h" > > - > > -/* Eventually those constants should go to Linux pci_regs.h */ > > -#define PCI_MSI_PENDING_32 0x10 > > -#define PCI_MSI_PENDING_64 0x14 > > - > > -/* PCI_MSI_ADDRESS_LO */ > > -#define PCI_MSI_ADDRESS_LO_MASK (~0x3) > > - > > -/* If we get rid of cap allocator, we won't need those. */ > > -#define PCI_MSI_32_SIZEOF 0x0a > > -#define PCI_MSI_64_SIZEOF 0x0e > > -#define PCI_MSI_32M_SIZEOF 0x14 > > -#define PCI_MSI_64M_SIZEOF 0x18 > > - > > -#define PCI_MSI_VECTORS_MAX 32 > > - > > -/* Flag for interrupt controller to declare MSI/MSI-X support */ > > -bool msi_supported; > > - > > -/* If we get rid of cap allocator, we won't need this. */ > > -static inline uint8_t msi_cap_sizeof(uint16_t flags) > > -{ > > - switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) { > > - case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT: > > - return PCI_MSI_64M_SIZEOF; > > - case PCI_MSI_FLAGS_64BIT: > > - return PCI_MSI_64_SIZEOF; > > - case PCI_MSI_FLAGS_MASKBIT: > > - return PCI_MSI_32M_SIZEOF; > > - case 0: > > - return PCI_MSI_32_SIZEOF; > > - default: > > - abort(); > > - break; > > - } > > - return 0; > > -} > > - > > -//#define MSI_DEBUG > > - > > -#ifdef MSI_DEBUG > > -# define MSI_DPRINTF(fmt, ...) \ > > - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > > -#else > > -# define MSI_DPRINTF(fmt, ...) do { } while (0) > > -#endif > > -#define MSI_DEV_PRINTF(dev, fmt, ...) \ > > - MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > > - > > -static inline unsigned int msi_nr_vectors(uint16_t flags) > > -{ > > - return 1U << > > - ((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1)); > > -} > > - > > -static inline uint8_t msi_flags_off(const PCIDevice* dev) > > -{ > > - return dev->msi_cap + PCI_MSI_FLAGS; > > -} > > - > > -static inline uint8_t msi_address_lo_off(const PCIDevice* dev) > > -{ > > - return dev->msi_cap + PCI_MSI_ADDRESS_LO; > > -} > > - > > -static inline uint8_t msi_address_hi_off(const PCIDevice* dev) > > -{ > > - return dev->msi_cap + PCI_MSI_ADDRESS_HI; > > -} > > - > > -static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit) > > -{ > > - return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32); > > -} > > - > > -static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit) > > -{ > > - return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32); > > -} > > - > > -static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit) > > -{ > > - return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_PENDING_32); > > -} > > - > > -/* > > - * Special API for POWER to configure the vectors through > > - * a side channel. Should never be used by devices. > > - */ > > -void msi_set_message(PCIDevice *dev, MSIMessage msg) > > -{ > > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > > - > > - if (msi64bit) { > > - pci_set_quad(dev->config + msi_address_lo_off(dev), msg.address); > > - } else { > > - pci_set_long(dev->config + msi_address_lo_off(dev), msg.address); > > - } > > - pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data); > > -} > > - > > -MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) > > -{ > > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > > - unsigned int nr_vectors = msi_nr_vectors(flags); > > - MSIMessage msg; > > - > > - assert(vector < nr_vectors); > > - > > - if (msi64bit) { > > - msg.address = pci_get_quad(dev->config + msi_address_lo_off(dev)); > > - } else { > > - msg.address = pci_get_long(dev->config + msi_address_lo_off(dev)); > > - } > > - > > - /* upper bit 31:16 is zero */ > > - msg.data = pci_get_word(dev->config + msi_data_off(dev, msi64bit)); > > - if (nr_vectors > 1) { > > - msg.data &= ~(nr_vectors - 1); > > - msg.data |= vector; > > - } > > - > > - return msg; > > -} > > - > > -bool msi_enabled(const PCIDevice *dev) > > -{ > > - return msi_present(dev) && > > - (pci_get_word(dev->config + msi_flags_off(dev)) & > > - PCI_MSI_FLAGS_ENABLE); > > -} > > - > > -int msi_init(struct PCIDevice *dev, uint8_t offset, > > - unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask) > > -{ > > - unsigned int vectors_order; > > - uint16_t flags; > > - uint8_t cap_size; > > - int config_offset; > > - > > - if (!msi_supported) { > > - return -ENOTSUP; > > - } > > - > > - MSI_DEV_PRINTF(dev, > > - "init offset: 0x%"PRIx8" vector: %"PRId8 > > - " 64bit %d mask %d\n", > > - offset, nr_vectors, msi64bit, msi_per_vector_mask); > > - > > - assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */ > > - assert(nr_vectors > 0); > > - assert(nr_vectors <= PCI_MSI_VECTORS_MAX); > > - /* the nr of MSI vectors is up to 32 */ > > - vectors_order = ffs(nr_vectors) - 1; > > - > > - flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1); > > - if (msi64bit) { > > - flags |= PCI_MSI_FLAGS_64BIT; > > - } > > - if (msi_per_vector_mask) { > > - flags |= PCI_MSI_FLAGS_MASKBIT; > > - } > > - > > - cap_size = msi_cap_sizeof(flags); > > - config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size); > > - if (config_offset < 0) { > > - return config_offset; > > - } > > - > > - dev->msi_cap = config_offset; > > - dev->cap_present |= QEMU_PCI_CAP_MSI; > > - > > - pci_set_word(dev->config + msi_flags_off(dev), flags); > > - pci_set_word(dev->wmask + msi_flags_off(dev), > > - PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); > > - pci_set_long(dev->wmask + msi_address_lo_off(dev), > > - PCI_MSI_ADDRESS_LO_MASK); > > - if (msi64bit) { > > - pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff); > > - } > > - pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff); > > - > > - if (msi_per_vector_mask) { > > - /* Make mask bits 0 to nr_vectors - 1 writable. */ > > - pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit), > > - 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors)); > > - } > > - return config_offset; > > -} > > - > > -void msi_uninit(struct PCIDevice *dev) > > -{ > > - uint16_t flags; > > - uint8_t cap_size; > > - > > - if (!msi_present(dev)) { > > - return; > > - } > > - flags = pci_get_word(dev->config + msi_flags_off(dev)); > > - cap_size = msi_cap_sizeof(flags); > > - pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size); > > - dev->cap_present &= ~QEMU_PCI_CAP_MSI; > > - > > - MSI_DEV_PRINTF(dev, "uninit\n"); > > -} > > - > > -void msi_reset(PCIDevice *dev) > > -{ > > - uint16_t flags; > > - bool msi64bit; > > - > > - if (!msi_present(dev)) { > > - return; > > - } > > - > > - flags = pci_get_word(dev->config + msi_flags_off(dev)); > > - flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); > > - msi64bit = flags & PCI_MSI_FLAGS_64BIT; > > - > > - pci_set_word(dev->config + msi_flags_off(dev), flags); > > - pci_set_long(dev->config + msi_address_lo_off(dev), 0); > > - if (msi64bit) { > > - pci_set_long(dev->config + msi_address_hi_off(dev), 0); > > - } > > - pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0); > > - if (flags & PCI_MSI_FLAGS_MASKBIT) { > > - pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0); > > - pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0); > > - } > > - MSI_DEV_PRINTF(dev, "reset\n"); > > -} > > - > > -static bool msi_is_masked(const PCIDevice *dev, unsigned int vector) > > -{ > > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > - uint32_t mask; > > - assert(vector < PCI_MSI_VECTORS_MAX); > > - > > - if (!(flags & PCI_MSI_FLAGS_MASKBIT)) { > > - return false; > > - } > > - > > - mask = pci_get_long(dev->config + > > - msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT)); > > - return mask & (1U << vector); > > -} > > - > > -void msi_notify(PCIDevice *dev, unsigned int vector) > > -{ > > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > > - unsigned int nr_vectors = msi_nr_vectors(flags); > > - MSIMessage msg; > > - > > - assert(vector < nr_vectors); > > - if (msi_is_masked(dev, vector)) { > > - assert(flags & PCI_MSI_FLAGS_MASKBIT); > > - pci_long_test_and_set_mask( > > - dev->config + msi_pending_off(dev, msi64bit), 1U << vector); > > - MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector); > > - return; > > - } > > - > > - msg = msi_get_message(dev, vector); > > - > > - MSI_DEV_PRINTF(dev, > > - "notify vector 0x%x" > > - " address: 0x%"PRIx64" data: 0x%"PRIx32"\n", > > - vector, msg.address, msg.data); > > - stl_le_phys(msg.address, msg.data); > > -} > > - > > -/* Normally called by pci_default_write_config(). */ > > -void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len) > > -{ > > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > > - bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT; > > - unsigned int nr_vectors; > > - uint8_t log_num_vecs; > > - uint8_t log_max_vecs; > > - unsigned int vector; > > - uint32_t pending; > > - > > - if (!msi_present(dev) || > > - !ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) { > > - return; > > - } > > - > > -#ifdef MSI_DEBUG > > - MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n", > > - addr, val, len); > > - MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32, > > - flags, > > - pci_get_long(dev->config + msi_address_lo_off(dev))); > > - if (msi64bit) { > > - fprintf(stderr, " address-hi: 0x%"PRIx32, > > - pci_get_long(dev->config + msi_address_hi_off(dev))); > > - } > > - fprintf(stderr, " data: 0x%"PRIx16, > > - pci_get_word(dev->config + msi_data_off(dev, msi64bit))); > > - if (flags & PCI_MSI_FLAGS_MASKBIT) { > > - fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32, > > - pci_get_long(dev->config + msi_mask_off(dev, msi64bit)), > > - pci_get_long(dev->config + msi_pending_off(dev, msi64bit))); > > - } > > - fprintf(stderr, "\n"); > > -#endif > > - > > - if (!(flags & PCI_MSI_FLAGS_ENABLE)) { > > - return; > > - } > > - > > - /* > > - * Now MSI is enabled, clear INTx# interrupts. > > - * the driver is prohibited from writing enable bit to mask > > - * a service request. But the guest OS could do this. > > - * So we just discard the interrupts as moderate fallback. > > - * > > - * 6.8.3.3. Enabling Operation > > - * While enabled for MSI or MSI-X operation, a function is prohibited > > - * from using its INTx# pin (if implemented) to request > > - * service (MSI, MSI-X, and INTx# are mutually exclusive). > > - */ > > - pci_device_deassert_intx(dev); > > - > > - /* > > - * nr_vectors might be set bigger than capable. So clamp it. > > - * This is not legal by spec, so we can do anything we like, > > - * just don't crash the host > > - */ > > - log_num_vecs = > > - (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1); > > - log_max_vecs = > > - (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1); > > - if (log_num_vecs > log_max_vecs) { > > - flags &= ~PCI_MSI_FLAGS_QSIZE; > > - flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1); > > - pci_set_word(dev->config + msi_flags_off(dev), flags); > > - } > > - > > - if (!msi_per_vector_mask) { > > - /* if per vector masking isn't supported, > > - there is no pending interrupt. */ > > - return; > > - } > > - > > - nr_vectors = msi_nr_vectors(flags); > > - > > - /* This will discard pending interrupts, if any. */ > > - pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit)); > > - pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors); > > - pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending); > > - > > - /* deliver pending interrupts which are unmasked */ > > - for (vector = 0; vector < nr_vectors; ++vector) { > > - if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) { > > - continue; > > - } > > - > > - pci_long_test_and_clear_mask( > > - dev->config + msi_pending_off(dev, msi64bit), 1U << vector); > > - msi_notify(dev, vector); > > - } > > -} > > - > > -unsigned int msi_nr_vectors_allocated(const PCIDevice *dev) > > -{ > > - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > - return msi_nr_vectors(flags); > > -} > > diff --git a/hw/msi.h b/hw/msi.h > > deleted file mode 100644 > > index 150b09a..0000000 > > --- a/hw/msi.h > > +++ /dev/null > > @@ -1,50 +0,0 @@ > > -/* > > - * msi.h > > - * > > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#ifndef QEMU_MSI_H > > -#define QEMU_MSI_H > > - > > -#include "qemu-common.h" > > -#include "pci.h" > > - > > -struct MSIMessage { > > - uint64_t address; > > - uint32_t data; > > -}; > > - > > -extern bool msi_supported; > > - > > -void msi_set_message(PCIDevice *dev, MSIMessage msg); > > -MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector); > > -bool msi_enabled(const PCIDevice *dev); > > -int msi_init(struct PCIDevice *dev, uint8_t offset, > > - unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask); > > -void msi_uninit(struct PCIDevice *dev); > > -void msi_reset(PCIDevice *dev); > > -void msi_notify(PCIDevice *dev, unsigned int vector); > > -void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); > > -unsigned int msi_nr_vectors_allocated(const PCIDevice *dev); > > - > > -static inline bool msi_present(const PCIDevice *dev) > > -{ > > - return dev->cap_present & QEMU_PCI_CAP_MSI; > > -} > > - > > -#endif /* QEMU_MSI_H */ > > diff --git a/hw/msix.c b/hw/msix.c > > deleted file mode 100644 > > index 136ef09..0000000 > > --- a/hw/msix.c > > +++ /dev/null > > @@ -1,562 +0,0 @@ > > -/* > > - * MSI-X device support > > - * > > - * This module includes support for MSI-X in pci devices. > > - * > > - * Author: Michael S. Tsirkin <mst@redhat.com> > > - * > > - * 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 the > > - * GNU GPL, version 2 or (at your option) any later version. > > - */ > > - > > -#include "hw.h" > > -#include "msi.h" > > -#include "msix.h" > > -#include "pci.h" > > -#include "range.h" > > - > > -#define MSIX_CAP_LENGTH 12 > > - > > -/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */ > > -#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1) > > -#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8) > > -#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8) > > - > > -static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) > > -{ > > - uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; > > - MSIMessage msg; > > - > > - msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); > > - msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); > > - return msg; > > -} > > - > > -/* > > - * Special API for POWER to configure the vectors through > > - * a side channel. Should never be used by devices. > > - */ > > -void msix_set_message(PCIDevice *dev, int vector, struct MSIMessage msg) > > -{ > > - uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; > > - > > - pci_set_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR, msg.address); > > - pci_set_long(table_entry + PCI_MSIX_ENTRY_DATA, msg.data); > > - table_entry[PCI_MSIX_ENTRY_VECTOR_CTRL] &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; > > -} > > - > > -static uint8_t msix_pending_mask(int vector) > > -{ > > - return 1 << (vector % 8); > > -} > > - > > -static uint8_t *msix_pending_byte(PCIDevice *dev, int vector) > > -{ > > - return dev->msix_pba + vector / 8; > > -} > > - > > -static int msix_is_pending(PCIDevice *dev, int vector) > > -{ > > - return *msix_pending_byte(dev, vector) & msix_pending_mask(vector); > > -} > > - > > -static void msix_set_pending(PCIDevice *dev, int vector) > > -{ > > - *msix_pending_byte(dev, vector) |= msix_pending_mask(vector); > > -} > > - > > -static void msix_clr_pending(PCIDevice *dev, int vector) > > -{ > > - *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector); > > -} > > - > > -static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask) > > -{ > > - unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; > > - return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT; > > -} > > - > > -static bool msix_is_masked(PCIDevice *dev, int vector) > > -{ > > - return msix_vector_masked(dev, vector, dev->msix_function_masked); > > -} > > - > > -static void msix_fire_vector_notifier(PCIDevice *dev, > > - unsigned int vector, bool is_masked) > > -{ > > - MSIMessage msg; > > - int ret; > > - > > - if (!dev->msix_vector_use_notifier) { > > - return; > > - } > > - if (is_masked) { > > - dev->msix_vector_release_notifier(dev, vector); > > - } else { > > - msg = msix_get_message(dev, vector); > > - ret = dev->msix_vector_use_notifier(dev, vector, msg); > > - assert(ret >= 0); > > - } > > -} > > - > > -static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked) > > -{ > > - bool is_masked = msix_is_masked(dev, vector); > > - > > - if (is_masked == was_masked) { > > - return; > > - } > > - > > - msix_fire_vector_notifier(dev, vector, is_masked); > > - > > - if (!is_masked && msix_is_pending(dev, vector)) { > > - msix_clr_pending(dev, vector); > > - msix_notify(dev, vector); > > - } > > -} > > - > > -static void msix_update_function_masked(PCIDevice *dev) > > -{ > > - dev->msix_function_masked = !msix_enabled(dev) || > > - (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK); > > -} > > - > > -/* Handle MSI-X capability config write. */ > > -void msix_write_config(PCIDevice *dev, uint32_t addr, > > - uint32_t val, int len) > > -{ > > - unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET; > > - int vector; > > - bool was_masked; > > - > > - if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) { > > - return; > > - } > > - > > - was_masked = dev->msix_function_masked; > > - msix_update_function_masked(dev); > > - > > - if (!msix_enabled(dev)) { > > - return; > > - } > > - > > - pci_device_deassert_intx(dev); > > - > > - if (dev->msix_function_masked == was_masked) { > > - return; > > - } > > - > > - for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > > - msix_handle_mask_update(dev, vector, > > - msix_vector_masked(dev, vector, was_masked)); > > - } > > -} > > - > > -static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr, > > - unsigned size) > > -{ > > - PCIDevice *dev = opaque; > > - > > - return pci_get_long(dev->msix_table + addr); > > -} > > - > > -static void msix_table_mmio_write(void *opaque, hwaddr addr, > > - uint64_t val, unsigned size) > > -{ > > - PCIDevice *dev = opaque; > > - int vector = addr / PCI_MSIX_ENTRY_SIZE; > > - bool was_masked; > > - > > - was_masked = msix_is_masked(dev, vector); > > - pci_set_long(dev->msix_table + addr, val); > > - msix_handle_mask_update(dev, vector, was_masked); > > -} > > - > > -static const MemoryRegionOps msix_table_mmio_ops = { > > - .read = msix_table_mmio_read, > > - .write = msix_table_mmio_write, > > - /* TODO: MSIX should be LITTLE_ENDIAN. */ > > - .endianness = DEVICE_NATIVE_ENDIAN, > > - .valid = { > > - .min_access_size = 4, > > - .max_access_size = 4, > > - }, > > -}; > > - > > -static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, > > - unsigned size) > > -{ > > - PCIDevice *dev = opaque; > > - > > - return pci_get_long(dev->msix_pba + addr); > > -} > > - > > -static const MemoryRegionOps msix_pba_mmio_ops = { > > - .read = msix_pba_mmio_read, > > - /* TODO: MSIX should be LITTLE_ENDIAN. */ > > - .endianness = DEVICE_NATIVE_ENDIAN, > > - .valid = { > > - .min_access_size = 4, > > - .max_access_size = 4, > > - }, > > -}; > > - > > -static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) > > -{ > > - int vector; > > - > > - for (vector = 0; vector < nentries; ++vector) { > > - unsigned offset = > > - vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; > > - bool was_masked = msix_is_masked(dev, vector); > > - > > - dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT; > > - msix_handle_mask_update(dev, vector, was_masked); > > - } > > -} > > - > > -/* Initialize the MSI-X structures */ > > -int msix_init(struct PCIDevice *dev, unsigned short nentries, > > - MemoryRegion *table_bar, uint8_t table_bar_nr, > > - unsigned table_offset, MemoryRegion *pba_bar, > > - uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos) > > -{ > > - int cap; > > - unsigned table_size, pba_size; > > - uint8_t *config; > > - > > - /* Nothing to do if MSI is not supported by interrupt controller */ > > - if (!msi_supported) { > > - return -ENOTSUP; > > - } > > - > > - if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) { > > - return -EINVAL; > > - } > > - > > - table_size = nentries * PCI_MSIX_ENTRY_SIZE; > > - pba_size = QEMU_ALIGN_UP(nentries, 64) / 8; > > - > > - /* Sanity test: table & pba don't overlap, fit within BARs, min aligned */ > > - if ((table_bar_nr == pba_bar_nr && > > - ranges_overlap(table_offset, table_size, pba_offset, pba_size)) || > > - table_offset + table_size > memory_region_size(table_bar) || > > - pba_offset + pba_size > memory_region_size(pba_bar) || > > - (table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) { > > - return -EINVAL; > > - } > > - > > - cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH); > > - if (cap < 0) { > > - return cap; > > - } > > - > > - dev->msix_cap = cap; > > - dev->cap_present |= QEMU_PCI_CAP_MSIX; > > - config = dev->config + cap; > > - > > - pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1); > > - dev->msix_entries_nr = nentries; > > - dev->msix_function_masked = true; > > - > > - pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_nr); > > - pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr); > > - > > - /* Make flags bit writable. */ > > - dev->wmask[cap + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK | > > - MSIX_MASKALL_MASK; > > - > > - dev->msix_table = g_malloc0(table_size); > > - dev->msix_pba = g_malloc0(pba_size); > > - dev->msix_entry_used = g_malloc0(nentries * sizeof *dev->msix_entry_used); > > - > > - msix_mask_all(dev, nentries); > > - > > - memory_region_init_io(&dev->msix_table_mmio, &msix_table_mmio_ops, dev, > > - "msix-table", table_size); > > - memory_region_add_subregion(table_bar, table_offset, &dev->msix_table_mmio); > > - memory_region_init_io(&dev->msix_pba_mmio, &msix_pba_mmio_ops, dev, > > - "msix-pba", pba_size); > > - memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio); > > - > > - return 0; > > -} > > - > > -int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, > > - uint8_t bar_nr) > > -{ > > - int ret; > > - char *name; > > - > > - /* > > - * Migration compatibility dictates that this remains a 4k > > - * BAR with the vector table in the lower half and PBA in > > - * the upper half. Do not use these elsewhere! > > - */ > > -#define MSIX_EXCLUSIVE_BAR_SIZE 4096 > > -#define MSIX_EXCLUSIVE_BAR_TABLE_OFFSET 0 > > -#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2) > > -#define MSIX_EXCLUSIVE_CAP_OFFSET 0 > > - > > - if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) { > > - return -EINVAL; > > - } > > - > > - name = g_strdup_printf("%s-msix", dev->name); > > - memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE); > > - g_free(name); > > - > > - ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr, > > - MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar, > > - bar_nr, MSIX_EXCLUSIVE_BAR_PBA_OFFSET, > > - MSIX_EXCLUSIVE_CAP_OFFSET); > > - if (ret) { > > - memory_region_destroy(&dev->msix_exclusive_bar); > > - return ret; > > - } > > - > > - pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY, > > - &dev->msix_exclusive_bar); > > - > > - return 0; > > -} > > - > > -static void msix_free_irq_entries(PCIDevice *dev) > > -{ > > - int vector; > > - > > - for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > > - dev->msix_entry_used[vector] = 0; > > - msix_clr_pending(dev, vector); > > - } > > -} > > - > > -static void msix_clear_all_vectors(PCIDevice *dev) > > -{ > > - int vector; > > - > > - for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > > - msix_clr_pending(dev, vector); > > - } > > -} > > - > > -/* Clean up resources for the device. */ > > -void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar) > > -{ > > - if (!msix_present(dev)) { > > - return; > > - } > > - pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH); > > - dev->msix_cap = 0; > > - msix_free_irq_entries(dev); > > - dev->msix_entries_nr = 0; > > - memory_region_del_subregion(pba_bar, &dev->msix_pba_mmio); > > - memory_region_destroy(&dev->msix_pba_mmio); > > - g_free(dev->msix_pba); > > - dev->msix_pba = NULL; > > - memory_region_del_subregion(table_bar, &dev->msix_table_mmio); > > - memory_region_destroy(&dev->msix_table_mmio); > > - g_free(dev->msix_table); > > - dev->msix_table = NULL; > > - g_free(dev->msix_entry_used); > > - dev->msix_entry_used = NULL; > > - dev->cap_present &= ~QEMU_PCI_CAP_MSIX; > > -} > > - > > -void msix_uninit_exclusive_bar(PCIDevice *dev) > > -{ > > - if (msix_present(dev)) { > > - msix_uninit(dev, &dev->msix_exclusive_bar, &dev->msix_exclusive_bar); > > - memory_region_destroy(&dev->msix_exclusive_bar); > > - } > > -} > > - > > -void msix_save(PCIDevice *dev, QEMUFile *f) > > -{ > > - unsigned n = dev->msix_entries_nr; > > - > > - if (!msix_present(dev)) { > > - return; > > - } > > - > > - qemu_put_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); > > - qemu_put_buffer(f, dev->msix_pba, (n + 7) / 8); > > -} > > - > > -/* Should be called after restoring the config space. */ > > -void msix_load(PCIDevice *dev, QEMUFile *f) > > -{ > > - unsigned n = dev->msix_entries_nr; > > - unsigned int vector; > > - > > - if (!msix_present(dev)) { > > - return; > > - } > > - > > - msix_clear_all_vectors(dev); > > - qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); > > - qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8); > > - msix_update_function_masked(dev); > > - > > - for (vector = 0; vector < n; vector++) { > > - msix_handle_mask_update(dev, vector, true); > > - } > > -} > > - > > -/* Does device support MSI-X? */ > > -int msix_present(PCIDevice *dev) > > -{ > > - return dev->cap_present & QEMU_PCI_CAP_MSIX; > > -} > > - > > -/* Is MSI-X enabled? */ > > -int msix_enabled(PCIDevice *dev) > > -{ > > - return (dev->cap_present & QEMU_PCI_CAP_MSIX) && > > - (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > > - MSIX_ENABLE_MASK); > > -} > > - > > -/* Send an MSI-X message */ > > -void msix_notify(PCIDevice *dev, unsigned vector) > > -{ > > - MSIMessage msg; > > - > > - if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) > > - return; > > - if (msix_is_masked(dev, vector)) { > > - msix_set_pending(dev, vector); > > - return; > > - } > > - > > - msg = msix_get_message(dev, vector); > > - > > - stl_le_phys(msg.address, msg.data); > > -} > > - > > -void msix_reset(PCIDevice *dev) > > -{ > > - if (!msix_present(dev)) { > > - return; > > - } > > - msix_clear_all_vectors(dev); > > - dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &= > > - ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET]; > > - memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE); > > - memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8); > > - msix_mask_all(dev, dev->msix_entries_nr); > > -} > > - > > -/* PCI spec suggests that devices make it possible for software to configure > > - * less vectors than supported by the device, but does not specify a standard > > - * mechanism for devices to do so. > > - * > > - * We support this by asking devices to declare vectors software is going to > > - * actually use, and checking this on the notification path. Devices that > > - * don't want to follow the spec suggestion can declare all vectors as used. */ > > - > > -/* Mark vector as used. */ > > -int msix_vector_use(PCIDevice *dev, unsigned vector) > > -{ > > - if (vector >= dev->msix_entries_nr) > > - return -EINVAL; > > - dev->msix_entry_used[vector]++; > > - return 0; > > -} > > - > > -/* Mark vector as unused. */ > > -void msix_vector_unuse(PCIDevice *dev, unsigned vector) > > -{ > > - if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) { > > - return; > > - } > > - if (--dev->msix_entry_used[vector]) { > > - return; > > - } > > - msix_clr_pending(dev, vector); > > -} > > - > > -void msix_unuse_all_vectors(PCIDevice *dev) > > -{ > > - if (!msix_present(dev)) { > > - return; > > - } > > - msix_free_irq_entries(dev); > > -} > > - > > -unsigned int msix_nr_vectors_allocated(const PCIDevice *dev) > > -{ > > - return dev->msix_entries_nr; > > -} > > - > > -static int msix_set_notifier_for_vector(PCIDevice *dev, unsigned int vector) > > -{ > > - MSIMessage msg; > > - > > - if (msix_is_masked(dev, vector)) { > > - return 0; > > - } > > - msg = msix_get_message(dev, vector); > > - return dev->msix_vector_use_notifier(dev, vector, msg); > > -} > > - > > -static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector) > > -{ > > - if (msix_is_masked(dev, vector)) { > > - return; > > - } > > - dev->msix_vector_release_notifier(dev, vector); > > -} > > - > > -int msix_set_vector_notifiers(PCIDevice *dev, > > - MSIVectorUseNotifier use_notifier, > > - MSIVectorReleaseNotifier release_notifier) > > -{ > > - int vector, ret; > > - > > - assert(use_notifier && release_notifier); > > - > > - dev->msix_vector_use_notifier = use_notifier; > > - dev->msix_vector_release_notifier = release_notifier; > > - > > - if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > > - (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { > > - for (vector = 0; vector < dev->msix_entries_nr; vector++) { > > - ret = msix_set_notifier_for_vector(dev, vector); > > - if (ret < 0) { > > - goto undo; > > - } > > - } > > - } > > - return 0; > > - > > -undo: > > - while (--vector >= 0) { > > - msix_unset_notifier_for_vector(dev, vector); > > - } > > - dev->msix_vector_use_notifier = NULL; > > - dev->msix_vector_release_notifier = NULL; > > - return ret; > > -} > > - > > -void msix_unset_vector_notifiers(PCIDevice *dev) > > -{ > > - int vector; > > - > > - assert(dev->msix_vector_use_notifier && > > - dev->msix_vector_release_notifier); > > - > > - if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > > - (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { > > - for (vector = 0; vector < dev->msix_entries_nr; vector++) { > > - msix_unset_notifier_for_vector(dev, vector); > > - } > > - } > > - dev->msix_vector_use_notifier = NULL; > > - dev->msix_vector_release_notifier = NULL; > > -} > > diff --git a/hw/msix.h b/hw/msix.h > > deleted file mode 100644 > > index 15211cb..0000000 > > --- a/hw/msix.h > > +++ /dev/null > > @@ -1,41 +0,0 @@ > > -#ifndef QEMU_MSIX_H > > -#define QEMU_MSIX_H > > - > > -#include "qemu-common.h" > > -#include "pci.h" > > - > > -void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg); > > -int msix_init(PCIDevice *dev, unsigned short nentries, > > - MemoryRegion *table_bar, uint8_t table_bar_nr, > > - unsigned table_offset, MemoryRegion *pba_bar, > > - uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos); > > -int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, > > - uint8_t bar_nr); > > - > > -void msix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len); > > - > > -void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, > > - MemoryRegion *pba_bar); > > -void msix_uninit_exclusive_bar(PCIDevice *dev); > > - > > -unsigned int msix_nr_vectors_allocated(const PCIDevice *dev); > > - > > -void msix_save(PCIDevice *dev, QEMUFile *f); > > -void msix_load(PCIDevice *dev, QEMUFile *f); > > - > > -int msix_enabled(PCIDevice *dev); > > -int msix_present(PCIDevice *dev); > > - > > -int msix_vector_use(PCIDevice *dev, unsigned vector); > > -void msix_vector_unuse(PCIDevice *dev, unsigned vector); > > -void msix_unuse_all_vectors(PCIDevice *dev); > > - > > -void msix_notify(PCIDevice *dev, unsigned vector); > > - > > -void msix_reset(PCIDevice *dev); > > - > > -int msix_set_vector_notifiers(PCIDevice *dev, > > - MSIVectorUseNotifier use_notifier, > > - MSIVectorReleaseNotifier release_notifier); > > -void msix_unset_vector_notifiers(PCIDevice *dev); > > -#endif > > diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c > > deleted file mode 100644 > > index 0ca5546..0000000 > > --- a/hw/pci-hotplug.c > > +++ /dev/null > > @@ -1,293 +0,0 @@ > > -/* > > - * QEMU PCI hotplug support > > - * > > - * Copyright (c) 2004 Fabrice Bellard > > - * > > - * Permission is hereby granted, free of charge, to any person obtaining a copy > > - * of this software and associated documentation files (the "Software"), to deal > > - * in the Software without restriction, including without limitation the rights > > - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > > - * copies of the Software, and to permit persons to whom the Software is > > - * furnished to do so, subject to the following conditions: > > - * > > - * The above copyright notice and this permission notice shall be included in > > - * all copies or substantial portions of the Software. > > - * > > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > > - * THE SOFTWARE. > > - */ > > - > > -#include "hw.h" > > -#include "boards.h" > > -#include "pci.h" > > -#include "net.h" > > -#include "pc.h" > > -#include "monitor.h" > > -#include "scsi.h" > > -#include "virtio-blk.h" > > -#include "qemu-config.h" > > -#include "blockdev.h" > > -#include "error.h" > > - > > -#if defined(TARGET_I386) > > -static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, > > - const char *devaddr, > > - const char *opts_str) > > -{ > > - Error *local_err = NULL; > > - QemuOpts *opts; > > - PCIBus *bus; > > - int ret, devfn; > > - > > - bus = pci_get_bus_devfn(&devfn, devaddr); > > - if (!bus) { > > - monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); > > - return NULL; > > - } > > - if (!((BusState*)bus)->allow_hotplug) { > > - monitor_printf(mon, "PCI bus doesn't support hotplug\n"); > > - return NULL; > > - } > > - > > - opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0); > > - if (!opts) { > > - return NULL; > > - } > > - > > - qemu_opt_set(opts, "type", "nic"); > > - > > - ret = net_client_init(opts, 0, &local_err); > > - if (error_is_set(&local_err)) { > > - qerror_report_err(local_err); > > - error_free(local_err); > > - return NULL; > > - } > > - if (nd_table[ret].devaddr) { > > - monitor_printf(mon, "Parameter addr not supported\n"); > > - return NULL; > > - } > > - return pci_nic_init(&nd_table[ret], "rtl8139", devaddr); > > -} > > - > > -static int scsi_hot_add(Monitor *mon, DeviceState *adapter, > > - DriveInfo *dinfo, int printinfo) > > -{ > > - SCSIBus *scsibus; > > - SCSIDevice *scsidev; > > - > > - scsibus = (SCSIBus *) > > - object_dynamic_cast(OBJECT(QLIST_FIRST(&adapter->child_bus)), > > - TYPE_SCSI_BUS); > > - if (!scsibus) { > > - error_report("Device is not a SCSI adapter"); > > - return -1; > > - } > > - > > - /* > > - * drive_init() tries to find a default for dinfo->unit. Doesn't > > - * work at all for hotplug though as we assign the device to a > > - * specific bus instead of the first bus with spare scsi ids. > > - * > > - * Ditch the calculated value and reload from option string (if > > - * specified). > > - */ > > - dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1); > > - dinfo->bus = scsibus->busnr; > > - scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, > > - false, -1); > > - if (!scsidev) { > > - return -1; > > - } > > - dinfo->unit = scsidev->id; > > - > > - if (printinfo) > > - monitor_printf(mon, "OK bus %d, unit %d\n", > > - scsibus->busnr, scsidev->id); > > - return 0; > > -} > > - > > -int pci_drive_hot_add(Monitor *mon, const QDict *qdict, > > - DriveInfo *dinfo, int type) > > -{ > > - int dom, pci_bus; > > - unsigned slot; > > - PCIDevice *dev; > > - const char *pci_addr = qdict_get_str(qdict, "pci_addr"); > > - > > - switch (type) { > > - case IF_SCSI: > > - if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) { > > - goto err; > > - } > > - dev = pci_find_device(pci_find_root_bus(dom), pci_bus, > > - PCI_DEVFN(slot, 0)); > > - if (!dev) { > > - monitor_printf(mon, "no pci device with address %s\n", pci_addr); > > - goto err; > > - } > > - if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) != 0) { > > - goto err; > > - } > > - break; > > - default: > > - monitor_printf(mon, "Can't hot-add drive to type %d\n", type); > > - goto err; > > - } > > - > > - return 0; > > -err: > > - return -1; > > -} > > - > > -static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, > > - const char *devaddr, > > - const char *opts) > > -{ > > - PCIDevice *dev; > > - DriveInfo *dinfo = NULL; > > - int type = -1; > > - char buf[128]; > > - PCIBus *bus; > > - int devfn; > > - > > - if (get_param_value(buf, sizeof(buf), "if", opts)) { > > - if (!strcmp(buf, "scsi")) > > - type = IF_SCSI; > > - else if (!strcmp(buf, "virtio")) { > > - type = IF_VIRTIO; > > - } else { > > - monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf); > > - return NULL; > > - } > > - } else { > > - monitor_printf(mon, "no if= specified\n"); > > - return NULL; > > - } > > - > > - if (get_param_value(buf, sizeof(buf), "file", opts)) { > > - dinfo = add_init_drive(opts); > > - if (!dinfo) > > - return NULL; > > - if (dinfo->devaddr) { > > - monitor_printf(mon, "Parameter addr not supported\n"); > > - return NULL; > > - } > > - } else { > > - dinfo = NULL; > > - } > > - > > - bus = pci_get_bus_devfn(&devfn, devaddr); > > - if (!bus) { > > - monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); > > - return NULL; > > - } > > - if (!((BusState*)bus)->allow_hotplug) { > > - monitor_printf(mon, "PCI bus doesn't support hotplug\n"); > > - return NULL; > > - } > > - > > - switch (type) { > > - case IF_SCSI: > > - dev = pci_create(bus, devfn, "lsi53c895a"); > > - if (qdev_init(&dev->qdev) < 0) > > - dev = NULL; > > - if (dev && dinfo) { > > - if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) { > > - qdev_unplug(&dev->qdev, NULL); > > - dev = NULL; > > - } > > - } > > - break; > > - case IF_VIRTIO: > > - if (!dinfo) { > > - monitor_printf(mon, "virtio requires a backing file/device.\n"); > > - return NULL; > > - } > > - dev = pci_create(bus, devfn, "virtio-blk-pci"); > > - if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) { > > - qdev_free(&dev->qdev); > > - dev = NULL; > > - break; > > - } > > - if (qdev_init(&dev->qdev) < 0) > > - dev = NULL; > > - break; > > - default: > > - dev = NULL; > > - } > > - return dev; > > -} > > - > > -void pci_device_hot_add(Monitor *mon, const QDict *qdict) > > -{ > > - PCIDevice *dev = NULL; > > - const char *pci_addr = qdict_get_str(qdict, "pci_addr"); > > - const char *type = qdict_get_str(qdict, "type"); > > - const char *opts = qdict_get_try_str(qdict, "opts"); > > - > > - /* strip legacy tag */ > > - if (!strncmp(pci_addr, "pci_addr=", 9)) { > > - pci_addr += 9; > > - } > > - > > - if (!opts) { > > - opts = ""; > > - } > > - > > - if (!strcmp(pci_addr, "auto")) > > - pci_addr = NULL; > > - > > - if (strcmp(type, "nic") == 0) { > > - dev = qemu_pci_hot_add_nic(mon, pci_addr, opts); > > - } else if (strcmp(type, "storage") == 0) { > > - dev = qemu_pci_hot_add_storage(mon, pci_addr, opts); > > - } else { > > - monitor_printf(mon, "invalid type: %s\n", type); > > - } > > - > > - if (dev) { > > - monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n", > > - pci_find_domain(dev->bus), > > - pci_bus_num(dev->bus), PCI_SLOT(dev->devfn), > > - PCI_FUNC(dev->devfn)); > > - } else > > - monitor_printf(mon, "failed to add %s\n", opts); > > -} > > -#endif > > - > > -static int pci_device_hot_remove(Monitor *mon, const char *pci_addr) > > -{ > > - PCIDevice *d; > > - int dom, bus; > > - unsigned slot; > > - Error *local_err = NULL; > > - > > - if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) { > > - return -1; > > - } > > - > > - d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0)); > > - if (!d) { > > - monitor_printf(mon, "slot %d empty\n", slot); > > - return -1; > > - } > > - > > - qdev_unplug(&d->qdev, &local_err); > > - if (error_is_set(&local_err)) { > > - monitor_printf(mon, "%s\n", error_get_pretty(local_err)); > > - error_free(local_err); > > - return -1; > > - } > > - > > - return 0; > > -} > > - > > -void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict) > > -{ > > - pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr")); > > -} > > diff --git a/hw/pci-stub.c b/hw/pci-stub.c > > deleted file mode 100644 > > index 134c448..0000000 > > --- a/hw/pci-stub.c > > +++ /dev/null > > @@ -1,47 +0,0 @@ > > -/* > > - * PCI stubs for platforms that don't support pci bus. > > - * > > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - * > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - * > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#include "sysemu.h" > > -#include "monitor.h" > > -#include "pci.h" > > -#include "qmp-commands.h" > > - > > -PciInfoList *qmp_query_pci(Error **errp) > > -{ > > - error_set(errp, QERR_UNSUPPORTED); > > - return NULL; > > -} > > - > > -static void pci_error_message(Monitor *mon) > > -{ > > - monitor_printf(mon, "PCI devices not supported\n"); > > -} > > - > > -int do_pcie_aer_inject_error(Monitor *mon, > > - const QDict *qdict, QObject **ret_data) > > -{ > > - pci_error_message(mon); > > - return -ENOSYS; > > -} > > - > > -void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) > > -{ > > - pci_error_message(mon); > > -} > > diff --git a/hw/pci.c b/hw/pci.c > > deleted file mode 100644 > > index 97a0cd7..0000000 > > --- a/hw/pci.c > > +++ /dev/null > > @@ -1,2168 +0,0 @@ > > -/* > > - * QEMU PCI bus manager > > - * > > - * Copyright (c) 2004 Fabrice Bellard > > - * > > - * Permission is hereby granted, free of charge, to any person obtaining a copy > > - * of this software and associated documentation files (the "Software"), to deal > > - * in the Software without restriction, including without limitation the rights > > - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > > - * copies of the Software, and to permit persons to whom the Software is > > - * furnished to do so, subject to the following conditions: > > - * > > - * The above copyright notice and this permission notice shall be included in > > - * all copies or substantial portions of the Software. > > - * > > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > > - * THE SOFTWARE. > > - */ > > -#include "hw.h" > > -#include "pci.h" > > -#include "pci_bridge.h" > > -#include "pci_internals.h" > > -#include "monitor.h" > > -#include "net.h" > > -#include "sysemu.h" > > -#include "loader.h" > > -#include "range.h" > > -#include "qmp-commands.h" > > -#include "msi.h" > > -#include "msix.h" > > -#include "exec-memory.h" > > - > > -//#define DEBUG_PCI > > -#ifdef DEBUG_PCI > > -# define PCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) > > -#else > > -# define PCI_DPRINTF(format, ...) do { } while (0) > > -#endif > > - > > -static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); > > -static char *pcibus_get_dev_path(DeviceState *dev); > > -static char *pcibus_get_fw_dev_path(DeviceState *dev); > > -static int pcibus_reset(BusState *qbus); > > - > > -static Property pci_props[] = { > > - DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), > > - DEFINE_PROP_STRING("romfile", PCIDevice, romfile), > > - DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1), > > - DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present, > > - QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false), > > - DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present, > > - QEMU_PCI_CAP_SERR_BITNR, true), > > - DEFINE_PROP_END_OF_LIST() > > -}; > > - > > -static void pci_bus_class_init(ObjectClass *klass, void *data) > > -{ > > - BusClass *k = BUS_CLASS(klass); > > - > > - k->print_dev = pcibus_dev_print; > > - k->get_dev_path = pcibus_get_dev_path; > > - k->get_fw_dev_path = pcibus_get_fw_dev_path; > > - k->reset = pcibus_reset; > > -} > > - > > -static const TypeInfo pci_bus_info = { > > - .name = TYPE_PCI_BUS, > > - .parent = TYPE_BUS, > > - .instance_size = sizeof(PCIBus), > > - .class_init = pci_bus_class_init, > > -}; > > - > > -static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); > > -static void pci_update_mappings(PCIDevice *d); > > -static void pci_set_irq(void *opaque, int irq_num, int level); > > -static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom); > > -static void pci_del_option_rom(PCIDevice *pdev); > > - > > -static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET; > > -static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU; > > - > > -struct PCIHostBus { > > - int domain; > > - struct PCIBus *bus; > > - QLIST_ENTRY(PCIHostBus) next; > > -}; > > -static QLIST_HEAD(, PCIHostBus) host_buses; > > - > > -static const VMStateDescription vmstate_pcibus = { > > - .name = "PCIBUS", > > - .version_id = 1, > > - .minimum_version_id = 1, > > - .minimum_version_id_old = 1, > > - .fields = (VMStateField []) { > > - VMSTATE_INT32_EQUAL(nirq, PCIBus), > > - VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32, int32_t), > > - VMSTATE_END_OF_LIST() > > - } > > -}; > > -static int pci_bar(PCIDevice *d, int reg) > > -{ > > - uint8_t type; > > - > > - if (reg != PCI_ROM_SLOT) > > - return PCI_BASE_ADDRESS_0 + reg * 4; > > - > > - type = d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; > > - return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; > > -} > > - > > -static inline int pci_irq_state(PCIDevice *d, int irq_num) > > -{ > > - return (d->irq_state >> irq_num) & 0x1; > > -} > > - > > -static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level) > > -{ > > - d->irq_state &= ~(0x1 << irq_num); > > - d->irq_state |= level << irq_num; > > -} > > - > > -static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) > > -{ > > - PCIBus *bus; > > - for (;;) { > > - bus = pci_dev->bus; > > - irq_num = bus->map_irq(pci_dev, irq_num); > > - if (bus->set_irq) > > - break; > > - pci_dev = bus->parent_dev; > > - } > > - bus->irq_count[irq_num] += change; > > - bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); > > -} > > - > > -int pci_bus_get_irq_level(PCIBus *bus, int irq_num) > > -{ > > - assert(irq_num >= 0); > > - assert(irq_num < bus->nirq); > > - return !!bus->irq_count[irq_num]; > > -} > > - > > -/* Update interrupt status bit in config space on interrupt > > - * state change. */ > > -static void pci_update_irq_status(PCIDevice *dev) > > -{ > > - if (dev->irq_state) { > > - dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT; > > - } else { > > - dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; > > - } > > -} > > - > > -void pci_device_deassert_intx(PCIDevice *dev) > > -{ > > - int i; > > - for (i = 0; i < PCI_NUM_PINS; ++i) { > > - qemu_set_irq(dev->irq[i], 0); > > - } > > -} > > - > > -/* > > - * This function is called on #RST and FLR. > > - * FLR if PCI_EXP_DEVCTL_BCR_FLR is set > > - */ > > -void pci_device_reset(PCIDevice *dev) > > -{ > > - int r; > > - > > - qdev_reset_all(&dev->qdev); > > - > > - dev->irq_state = 0; > > - pci_update_irq_status(dev); > > - pci_device_deassert_intx(dev); > > - /* Clear all writable bits */ > > - pci_word_test_and_clear_mask(dev->config + PCI_COMMAND, > > - pci_get_word(dev->wmask + PCI_COMMAND) | > > - pci_get_word(dev->w1cmask + PCI_COMMAND)); > > - pci_word_test_and_clear_mask(dev->config + PCI_STATUS, > > - pci_get_word(dev->wmask + PCI_STATUS) | > > - pci_get_word(dev->w1cmask + PCI_STATUS)); > > - dev->config[PCI_CACHE_LINE_SIZE] = 0x0; > > - dev->config[PCI_INTERRUPT_LINE] = 0x0; > > - for (r = 0; r < PCI_NUM_REGIONS; ++r) { > > - PCIIORegion *region = &dev->io_regions[r]; > > - if (!region->size) { > > - continue; > > - } > > - > > - if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) && > > - region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > > - pci_set_quad(dev->config + pci_bar(dev, r), region->type); > > - } else { > > - pci_set_long(dev->config + pci_bar(dev, r), region->type); > > - } > > - } > > - pci_update_mappings(dev); > > - > > - msi_reset(dev); > > - msix_reset(dev); > > -} > > - > > -/* > > - * Trigger pci bus reset under a given bus. > > - * To be called on RST# assert. > > - */ > > -void pci_bus_reset(PCIBus *bus) > > -{ > > - int i; > > - > > - for (i = 0; i < bus->nirq; i++) { > > - bus->irq_count[i] = 0; > > - } > > - for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { > > - if (bus->devices[i]) { > > - pci_device_reset(bus->devices[i]); > > - } > > - } > > -} > > - > > -static int pcibus_reset(BusState *qbus) > > -{ > > - pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus)); > > - > > - /* topology traverse is done by pci_bus_reset(). > > - Tell qbus/qdev walker not to traverse the tree */ > > - return 1; > > -} > > - > > -static void pci_host_bus_register(int domain, PCIBus *bus) > > -{ > > - struct PCIHostBus *host; > > - host = g_malloc0(sizeof(*host)); > > - host->domain = domain; > > - host->bus = bus; > > - QLIST_INSERT_HEAD(&host_buses, host, next); > > -} > > - > > -PCIBus *pci_find_root_bus(int domain) > > -{ > > - struct PCIHostBus *host; > > - > > - QLIST_FOREACH(host, &host_buses, next) { > > - if (host->domain == domain) { > > - return host->bus; > > - } > > - } > > - > > - return NULL; > > -} > > - > > -int pci_find_domain(const PCIBus *bus) > > -{ > > - PCIDevice *d; > > - struct PCIHostBus *host; > > - > > - /* obtain root bus */ > > - while ((d = bus->parent_dev) != NULL) { > > - bus = d->bus; > > - } > > - > > - QLIST_FOREACH(host, &host_buses, next) { > > - if (host->bus == bus) { > > - return host->domain; > > - } > > - } > > - > > - abort(); /* should not be reached */ > > - return -1; > > -} > > - > > -void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, > > - const char *name, > > - MemoryRegion *address_space_mem, > > - MemoryRegion *address_space_io, > > - uint8_t devfn_min) > > -{ > > - qbus_create_inplace(&bus->qbus, TYPE_PCI_BUS, parent, name); > > - assert(PCI_FUNC(devfn_min) == 0); > > - bus->devfn_min = devfn_min; > > - bus->address_space_mem = address_space_mem; > > - bus->address_space_io = address_space_io; > > - > > - /* host bridge */ > > - QLIST_INIT(&bus->child); > > - pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */ > > - > > - vmstate_register(NULL, -1, &vmstate_pcibus, bus); > > -} > > - > > -PCIBus *pci_bus_new(DeviceState *parent, const char *name, > > - MemoryRegion *address_space_mem, > > - MemoryRegion *address_space_io, > > - uint8_t devfn_min) > > -{ > > - PCIBus *bus; > > - > > - bus = g_malloc0(sizeof(*bus)); > > - pci_bus_new_inplace(bus, parent, name, address_space_mem, > > - address_space_io, devfn_min); > > - OBJECT(bus)->free = g_free; > > - return bus; > > -} > > - > > -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > > - void *irq_opaque, int nirq) > > -{ > > - bus->set_irq = set_irq; > > - bus->map_irq = map_irq; > > - bus->irq_opaque = irq_opaque; > > - bus->nirq = nirq; > > - bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0])); > > -} > > - > > -void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev) > > -{ > > - bus->qbus.allow_hotplug = 1; > > - bus->hotplug = hotplug; > > - bus->hotplug_qdev = qdev; > > -} > > - > > -PCIBus *pci_register_bus(DeviceState *parent, const char *name, > > - pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > > - void *irq_opaque, > > - MemoryRegion *address_space_mem, > > - MemoryRegion *address_space_io, > > - uint8_t devfn_min, int nirq) > > -{ > > - PCIBus *bus; > > - > > - bus = pci_bus_new(parent, name, address_space_mem, > > - address_space_io, devfn_min); > > - pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq); > > - return bus; > > -} > > - > > -int pci_bus_num(PCIBus *s) > > -{ > > - if (!s->parent_dev) > > - return 0; /* pci host bridge */ > > - return s->parent_dev->config[PCI_SECONDARY_BUS]; > > -} > > - > > -static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) > > -{ > > - PCIDevice *s = container_of(pv, PCIDevice, config); > > - uint8_t *config; > > - int i; > > - > > - assert(size == pci_config_size(s)); > > - config = g_malloc(size); > > - > > - qemu_get_buffer(f, config, size); > > - for (i = 0; i < size; ++i) { > > - if ((config[i] ^ s->config[i]) & > > - s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) { > > - g_free(config); > > - return -EINVAL; > > - } > > - } > > - memcpy(s->config, config, size); > > - > > - pci_update_mappings(s); > > - > > - memory_region_set_enabled(&s->bus_master_enable_region, > > - pci_get_word(s->config + PCI_COMMAND) > > - & PCI_COMMAND_MASTER); > > - > > - g_free(config); > > - return 0; > > -} > > - > > -/* just put buffer */ > > -static void put_pci_config_device(QEMUFile *f, void *pv, size_t size) > > -{ > > - const uint8_t **v = pv; > > - assert(size == pci_config_size(container_of(pv, PCIDevice, config))); > > - qemu_put_buffer(f, *v, size); > > -} > > - > > -static VMStateInfo vmstate_info_pci_config = { > > - .name = "pci config", > > - .get = get_pci_config_device, > > - .put = put_pci_config_device, > > -}; > > - > > -static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) > > -{ > > - PCIDevice *s = container_of(pv, PCIDevice, irq_state); > > - uint32_t irq_state[PCI_NUM_PINS]; > > - int i; > > - for (i = 0; i < PCI_NUM_PINS; ++i) { > > - irq_state[i] = qemu_get_be32(f); > > - if (irq_state[i] != 0x1 && irq_state[i] != 0) { > > - fprintf(stderr, "irq state %d: must be 0 or 1.\n", > > - irq_state[i]); > > - return -EINVAL; > > - } > > - } > > - > > - for (i = 0; i < PCI_NUM_PINS; ++i) { > > - pci_set_irq_state(s, i, irq_state[i]); > > - } > > - > > - return 0; > > -} > > - > > -static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size) > > -{ > > - int i; > > - PCIDevice *s = container_of(pv, PCIDevice, irq_state); > > - > > - for (i = 0; i < PCI_NUM_PINS; ++i) { > > - qemu_put_be32(f, pci_irq_state(s, i)); > > - } > > -} > > - > > -static VMStateInfo vmstate_info_pci_irq_state = { > > - .name = "pci irq state", > > - .get = get_pci_irq_state, > > - .put = put_pci_irq_state, > > -}; > > - > > -const VMStateDescription vmstate_pci_device = { > > - .name = "PCIDevice", > > - .version_id = 2, > > - .minimum_version_id = 1, > > - .minimum_version_id_old = 1, > > - .fields = (VMStateField []) { > > - VMSTATE_INT32_LE(version_id, PCIDevice), > > - VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, > > - vmstate_info_pci_config, > > - PCI_CONFIG_SPACE_SIZE), > > - VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, > > - vmstate_info_pci_irq_state, > > - PCI_NUM_PINS * sizeof(int32_t)), > > - VMSTATE_END_OF_LIST() > > - } > > -}; > > - > > -const VMStateDescription vmstate_pcie_device = { > > - .name = "PCIEDevice", > > - .version_id = 2, > > - .minimum_version_id = 1, > > - .minimum_version_id_old = 1, > > - .fields = (VMStateField []) { > > - VMSTATE_INT32_LE(version_id, PCIDevice), > > - VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, > > - vmstate_info_pci_config, > > - PCIE_CONFIG_SPACE_SIZE), > > - VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, > > - vmstate_info_pci_irq_state, > > - PCI_NUM_PINS * sizeof(int32_t)), > > - VMSTATE_END_OF_LIST() > > - } > > -}; > > - > > -static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s) > > -{ > > - return pci_is_express(s) ? &vmstate_pcie_device : &vmstate_pci_device; > > -} > > - > > -void pci_device_save(PCIDevice *s, QEMUFile *f) > > -{ > > - /* Clear interrupt status bit: it is implicit > > - * in irq_state which we are saving. > > - * This makes us compatible with old devices > > - * which never set or clear this bit. */ > > - s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; > > - vmstate_save_state(f, pci_get_vmstate(s), s); > > - /* Restore the interrupt status bit. */ > > - pci_update_irq_status(s); > > -} > > - > > -int pci_device_load(PCIDevice *s, QEMUFile *f) > > -{ > > - int ret; > > - ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id); > > - /* Restore the interrupt status bit. */ > > - pci_update_irq_status(s); > > - return ret; > > -} > > - > > -static void pci_set_default_subsystem_id(PCIDevice *pci_dev) > > -{ > > - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, > > - pci_default_sub_vendor_id); > > - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, > > - pci_default_sub_device_id); > > -} > > - > > -/* > > - * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL > > - * [[<domain>:]<bus>:]<slot>.<func>, return -1 on error > > - */ > > -static int pci_parse_devaddr(const char *addr, int *domp, int *busp, > > - unsigned int *slotp, unsigned int *funcp) > > -{ > > - const char *p; > > - char *e; > > - unsigned long val; > > - unsigned long dom = 0, bus = 0; > > - unsigned int slot = 0; > > - unsigned int func = 0; > > - > > - p = addr; > > - val = strtoul(p, &e, 16); > > - if (e == p) > > - return -1; > > - if (*e == ':') { > > - bus = val; > > - p = e + 1; > > - val = strtoul(p, &e, 16); > > - if (e == p) > > - return -1; > > - if (*e == ':') { > > - dom = bus; > > - bus = val; > > - p = e + 1; > > - val = strtoul(p, &e, 16); > > - if (e == p) > > - return -1; > > - } > > - } > > - > > - slot = val; > > - > > - if (funcp != NULL) { > > - if (*e != '.') > > - return -1; > > - > > - p = e + 1; > > - val = strtoul(p, &e, 16); > > - if (e == p) > > - return -1; > > - > > - func = val; > > - } > > - > > - /* if funcp == NULL func is 0 */ > > - if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) > > - return -1; > > - > > - if (*e) > > - return -1; > > - > > - *domp = dom; > > - *busp = bus; > > - *slotp = slot; > > - if (funcp != NULL) > > - *funcp = func; > > - return 0; > > -} > > - > > -int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, > > - unsigned *slotp) > > -{ > > - /* strip legacy tag */ > > - if (!strncmp(addr, "pci_addr=", 9)) { > > - addr += 9; > > - } > > - if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) { > > - monitor_printf(mon, "Invalid pci address\n"); > > - return -1; > > - } > > - return 0; > > -} > > - > > -PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) > > -{ > > - int dom, bus; > > - unsigned slot; > > - > > - if (!devaddr) { > > - *devfnp = -1; > > - return pci_find_bus_nr(pci_find_root_bus(0), 0); > > - } > > - > > - if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) { > > - return NULL; > > - } > > - > > - *devfnp = PCI_DEVFN(slot, 0); > > - return pci_find_bus_nr(pci_find_root_bus(dom), bus); > > -} > > - > > -static void pci_init_cmask(PCIDevice *dev) > > -{ > > - pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff); > > - pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff); > > - dev->cmask[PCI_STATUS] = PCI_STATUS_CAP_LIST; > > - dev->cmask[PCI_REVISION_ID] = 0xff; > > - dev->cmask[PCI_CLASS_PROG] = 0xff; > > - pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff); > > - dev->cmask[PCI_HEADER_TYPE] = 0xff; > > - dev->cmask[PCI_CAPABILITY_LIST] = 0xff; > > -} > > - > > -static void pci_init_wmask(PCIDevice *dev) > > -{ > > - int config_size = pci_config_size(dev); > > - > > - dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff; > > - dev->wmask[PCI_INTERRUPT_LINE] = 0xff; > > - pci_set_word(dev->wmask + PCI_COMMAND, > > - PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | > > - PCI_COMMAND_INTX_DISABLE); > > - if (dev->cap_present & QEMU_PCI_CAP_SERR) { > > - pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR); > > - } > > - > > - memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff, > > - config_size - PCI_CONFIG_HEADER_SIZE); > > -} > > - > > -static void pci_init_w1cmask(PCIDevice *dev) > > -{ > > - /* > > - * Note: It's okay to set w1cmask even for readonly bits as > > - * long as their value is hardwired to 0. > > - */ > > - pci_set_word(dev->w1cmask + PCI_STATUS, > > - PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | > > - PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | > > - PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY); > > -} > > - > > -static void pci_init_mask_bridge(PCIDevice *d) > > -{ > > - /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and > > - PCI_SEC_LETENCY_TIMER */ > > - memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4); > > - > > - /* base and limit */ > > - d->wmask[PCI_IO_BASE] = PCI_IO_RANGE_MASK & 0xff; > > - d->wmask[PCI_IO_LIMIT] = PCI_IO_RANGE_MASK & 0xff; > > - pci_set_word(d->wmask + PCI_MEMORY_BASE, > > - PCI_MEMORY_RANGE_MASK & 0xffff); > > - pci_set_word(d->wmask + PCI_MEMORY_LIMIT, > > - PCI_MEMORY_RANGE_MASK & 0xffff); > > - pci_set_word(d->wmask + PCI_PREF_MEMORY_BASE, > > - PCI_PREF_RANGE_MASK & 0xffff); > > - pci_set_word(d->wmask + PCI_PREF_MEMORY_LIMIT, > > - PCI_PREF_RANGE_MASK & 0xffff); > > - > > - /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */ > > - memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8); > > - > > - /* Supported memory and i/o types */ > > - d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_16; > > - d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_16; > > - pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE, > > - PCI_PREF_RANGE_TYPE_64); > > - pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT, > > - PCI_PREF_RANGE_TYPE_64); > > - > > -/* TODO: add this define to pci_regs.h in linux and then in qemu. */ > > -#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ > > -#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */ > > -#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */ > > -#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ > > -#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ > > - pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, > > - PCI_BRIDGE_CTL_PARITY | > > - PCI_BRIDGE_CTL_SERR | > > - PCI_BRIDGE_CTL_ISA | > > - PCI_BRIDGE_CTL_VGA | > > - PCI_BRIDGE_CTL_VGA_16BIT | > > - PCI_BRIDGE_CTL_MASTER_ABORT | > > - PCI_BRIDGE_CTL_BUS_RESET | > > - PCI_BRIDGE_CTL_FAST_BACK | > > - PCI_BRIDGE_CTL_DISCARD | > > - PCI_BRIDGE_CTL_SEC_DISCARD | > > - PCI_BRIDGE_CTL_DISCARD_SERR); > > - /* Below does not do anything as we never set this bit, put here for > > - * completeness. */ > > - pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL, > > - PCI_BRIDGE_CTL_DISCARD_STATUS); > > - d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK; > > - d->cmask[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_MASK; > > - pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE, > > - PCI_PREF_RANGE_TYPE_MASK); > > - pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_LIMIT, > > - PCI_PREF_RANGE_TYPE_MASK); > > -} > > - > > -static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev) > > -{ > > - uint8_t slot = PCI_SLOT(dev->devfn); > > - uint8_t func; > > - > > - if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { > > - dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; > > - } > > - > > - /* > > - * multifunction bit is interpreted in two ways as follows. > > - * - all functions must set the bit to 1. > > - * Example: Intel X53 > > - * - function 0 must set the bit, but the rest function (> 0) > > - * is allowed to leave the bit to 0. > > - * Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10, > > - * > > - * So OS (at least Linux) checks the bit of only function 0, > > - * and doesn't see the bit of function > 0. > > - * > > - * The below check allows both interpretation. > > - */ > > - if (PCI_FUNC(dev->devfn)) { > > - PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)]; > > - if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) { > > - /* function 0 should set multifunction bit */ > > - error_report("PCI: single function device can't be populated " > > - "in function %x.%x", slot, PCI_FUNC(dev->devfn)); > > - return -1; > > - } > > - return 0; > > - } > > - > > - if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { > > - return 0; > > - } > > - /* function 0 indicates single function, so function > 0 must be NULL */ > > - for (func = 1; func < PCI_FUNC_MAX; ++func) { > > - if (bus->devices[PCI_DEVFN(slot, func)]) { > > - error_report("PCI: %x.0 indicates single function, " > > - "but %x.%x is already populated.", > > - slot, slot, func); > > - return -1; > > - } > > - } > > - return 0; > > -} > > - > > -static void pci_config_alloc(PCIDevice *pci_dev) > > -{ > > - int config_size = pci_config_size(pci_dev); > > - > > - pci_dev->config = g_malloc0(config_size); > > - pci_dev->cmask = g_malloc0(config_size); > > - pci_dev->wmask = g_malloc0(config_size); > > - pci_dev->w1cmask = g_malloc0(config_size); > > - pci_dev->used = g_malloc0(config_size); > > -} > > - > > -static void pci_config_free(PCIDevice *pci_dev) > > -{ > > - g_free(pci_dev->config); > > - g_free(pci_dev->cmask); > > - g_free(pci_dev->wmask); > > - g_free(pci_dev->w1cmask); > > - g_free(pci_dev->used); > > -} > > - > > -/* -1 for devfn means auto assign */ > > -static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, > > - const char *name, int devfn) > > -{ > > - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > > - PCIConfigReadFunc *config_read = pc->config_read; > > - PCIConfigWriteFunc *config_write = pc->config_write; > > - > > - if (devfn < 0) { > > - for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices); > > - devfn += PCI_FUNC_MAX) { > > - if (!bus->devices[devfn]) > > - goto found; > > - } > > - error_report("PCI: no slot/function available for %s, all in use", name); > > - return NULL; > > - found: ; > > - } else if (bus->devices[devfn]) { > > - error_report("PCI: slot %d function %d not available for %s, in use by %s", > > - PCI_SLOT(devfn), PCI_FUNC(devfn), name, bus->devices[devfn]->name); > > - return NULL; > > - } > > - pci_dev->bus = bus; > > - if (bus->dma_context_fn) { > > - pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, devfn); > > - } else { > > - /* FIXME: Make dma_context_fn use MemoryRegions instead, so this path is > > - * taken unconditionally */ > > - /* FIXME: inherit memory region from bus creator */ > > - memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master", > > - get_system_memory(), 0, > > - memory_region_size(get_system_memory())); > > - memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); > > - address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region); > > - pci_dev->dma = g_new(DMAContext, 1); > > - dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL); > > - } > > - pci_dev->devfn = devfn; > > - pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); > > - pci_dev->irq_state = 0; > > - pci_config_alloc(pci_dev); > > - > > - pci_config_set_vendor_id(pci_dev->config, pc->vendor_id); > > - pci_config_set_device_id(pci_dev->config, pc->device_id); > > - pci_config_set_revision(pci_dev->config, pc->revision); > > - pci_config_set_class(pci_dev->config, pc->class_id); > > - > > - if (!pc->is_bridge) { > > - if (pc->subsystem_vendor_id || pc->subsystem_id) { > > - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, > > - pc->subsystem_vendor_id); > > - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, > > - pc->subsystem_id); > > - } else { > > - pci_set_default_subsystem_id(pci_dev); > > - } > > - } else { > > - /* subsystem_vendor_id/subsystem_id are only for header type 0 */ > > - assert(!pc->subsystem_vendor_id); > > - assert(!pc->subsystem_id); > > - } > > - pci_init_cmask(pci_dev); > > - pci_init_wmask(pci_dev); > > - pci_init_w1cmask(pci_dev); > > - if (pc->is_bridge) { > > - pci_init_mask_bridge(pci_dev); > > - } > > - if (pci_init_multifunction(bus, pci_dev)) { > > - pci_config_free(pci_dev); > > - return NULL; > > - } > > - > > - if (!config_read) > > - config_read = pci_default_read_config; > > - if (!config_write) > > - config_write = pci_default_write_config; > > - pci_dev->config_read = config_read; > > - pci_dev->config_write = config_write; > > - bus->devices[devfn] = pci_dev; > > - pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS); > > - pci_dev->version_id = 2; /* Current pci device vmstate version */ > > - return pci_dev; > > -} > > - > > -static void do_pci_unregister_device(PCIDevice *pci_dev) > > -{ > > - qemu_free_irqs(pci_dev->irq); > > - pci_dev->bus->devices[pci_dev->devfn] = NULL; > > - pci_config_free(pci_dev); > > - > > - if (!pci_dev->bus->dma_context_fn) { > > - address_space_destroy(&pci_dev->bus_master_as); > > - memory_region_destroy(&pci_dev->bus_master_enable_region); > > - g_free(pci_dev->dma); > > - pci_dev->dma = NULL; > > - } > > -} > > - > > -static void pci_unregister_io_regions(PCIDevice *pci_dev) > > -{ > > - PCIIORegion *r; > > - int i; > > - > > - for(i = 0; i < PCI_NUM_REGIONS; i++) { > > - r = &pci_dev->io_regions[i]; > > - if (!r->size || r->addr == PCI_BAR_UNMAPPED) > > - continue; > > - memory_region_del_subregion(r->address_space, r->memory); > > - } > > -} > > - > > -static int pci_unregister_device(DeviceState *dev) > > -{ > > - PCIDevice *pci_dev = PCI_DEVICE(dev); > > - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > > - > > - pci_unregister_io_regions(pci_dev); > > - pci_del_option_rom(pci_dev); > > - > > - if (pc->exit) { > > - pc->exit(pci_dev); > > - } > > - > > - do_pci_unregister_device(pci_dev); > > - return 0; > > -} > > - > > -void pci_register_bar(PCIDevice *pci_dev, int region_num, > > - uint8_t type, MemoryRegion *memory) > > -{ > > - PCIIORegion *r; > > - uint32_t addr; > > - uint64_t wmask; > > - pcibus_t size = memory_region_size(memory); > > - > > - assert(region_num >= 0); > > - assert(region_num < PCI_NUM_REGIONS); > > - if (size & (size-1)) { > > - fprintf(stderr, "ERROR: PCI region size must be pow2 " > > - "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size); > > - exit(1); > > - } > > - > > - r = &pci_dev->io_regions[region_num]; > > - r->addr = PCI_BAR_UNMAPPED; > > - r->size = size; > > - r->type = type; > > - r->memory = NULL; > > - > > - wmask = ~(size - 1); > > - addr = pci_bar(pci_dev, region_num); > > - if (region_num == PCI_ROM_SLOT) { > > - /* ROM enable bit is writable */ > > - wmask |= PCI_ROM_ADDRESS_ENABLE; > > - } > > - pci_set_long(pci_dev->config + addr, type); > > - if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) && > > - r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > > - pci_set_quad(pci_dev->wmask + addr, wmask); > > - pci_set_quad(pci_dev->cmask + addr, ~0ULL); > > - } else { > > - pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff); > > - pci_set_long(pci_dev->cmask + addr, 0xffffffff); > > - } > > - pci_dev->io_regions[region_num].memory = memory; > > - pci_dev->io_regions[region_num].address_space > > - = type & PCI_BASE_ADDRESS_SPACE_IO > > - ? pci_dev->bus->address_space_io > > - : pci_dev->bus->address_space_mem; > > -} > > - > > -pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num) > > -{ > > - return pci_dev->io_regions[region_num].addr; > > -} > > - > > -static pcibus_t pci_bar_address(PCIDevice *d, > > - int reg, uint8_t type, pcibus_t size) > > -{ > > - pcibus_t new_addr, last_addr; > > - int bar = pci_bar(d, reg); > > - uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); > > - > > - if (type & PCI_BASE_ADDRESS_SPACE_IO) { > > - if (!(cmd & PCI_COMMAND_IO)) { > > - return PCI_BAR_UNMAPPED; > > - } > > - new_addr = pci_get_long(d->config + bar) & ~(size - 1); > > - last_addr = new_addr + size - 1; > > - /* NOTE: we have only 64K ioports on PC */ > > - if (last_addr <= new_addr || new_addr == 0 || last_addr > UINT16_MAX) { > > - return PCI_BAR_UNMAPPED; > > - } > > - return new_addr; > > - } > > - > > - if (!(cmd & PCI_COMMAND_MEMORY)) { > > - return PCI_BAR_UNMAPPED; > > - } > > - if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > > - new_addr = pci_get_quad(d->config + bar); > > - } else { > > - new_addr = pci_get_long(d->config + bar); > > - } > > - /* the ROM slot has a specific enable bit */ > > - if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) { > > - return PCI_BAR_UNMAPPED; > > - } > > - new_addr &= ~(size - 1); > > - last_addr = new_addr + size - 1; > > - /* NOTE: we do not support wrapping */ > > - /* XXX: as we cannot support really dynamic > > - mappings, we handle specific values as invalid > > - mappings. */ > > - if (last_addr <= new_addr || new_addr == 0 || > > - last_addr == PCI_BAR_UNMAPPED) { > > - return PCI_BAR_UNMAPPED; > > - } > > - > > - /* Now pcibus_t is 64bit. > > - * Check if 32 bit BAR wraps around explicitly. > > - * Without this, PC ide doesn't work well. > > - * TODO: remove this work around. > > - */ > > - if (!(type & PCI_BASE_ADDRESS_MEM_TYPE_64) && last_addr >= UINT32_MAX) { > > - return PCI_BAR_UNMAPPED; > > - } > > - > > - /* > > - * OS is allowed to set BAR beyond its addressable > > - * bits. For example, 32 bit OS can set 64bit bar > > - * to >4G. Check it. TODO: we might need to support > > - * it in the future for e.g. PAE. > > - */ > > - if (last_addr >= HWADDR_MAX) { > > - return PCI_BAR_UNMAPPED; > > - } > > - > > - return new_addr; > > -} > > - > > -static void pci_update_mappings(PCIDevice *d) > > -{ > > - PCIIORegion *r; > > - int i; > > - pcibus_t new_addr; > > - > > - for(i = 0; i < PCI_NUM_REGIONS; i++) { > > - r = &d->io_regions[i]; > > - > > - /* this region isn't registered */ > > - if (!r->size) > > - continue; > > - > > - new_addr = pci_bar_address(d, i, r->type, r->size); > > - > > - /* This bar isn't changed */ > > - if (new_addr == r->addr) > > - continue; > > - > > - /* now do the real mapping */ > > - if (r->addr != PCI_BAR_UNMAPPED) { > > - memory_region_del_subregion(r->address_space, r->memory); > > - } > > - r->addr = new_addr; > > - if (r->addr != PCI_BAR_UNMAPPED) { > > - memory_region_add_subregion_overlap(r->address_space, > > - r->addr, r->memory, 1); > > - } > > - } > > -} > > - > > -static inline int pci_irq_disabled(PCIDevice *d) > > -{ > > - return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE; > > -} > > - > > -/* Called after interrupt disabled field update in config space, > > - * assert/deassert interrupts if necessary. > > - * Gets original interrupt disable bit value (before update). */ > > -static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled) > > -{ > > - int i, disabled = pci_irq_disabled(d); > > - if (disabled == was_irq_disabled) > > - return; > > - for (i = 0; i < PCI_NUM_PINS; ++i) { > > - int state = pci_irq_state(d, i); > > - pci_change_irq_level(d, i, disabled ? -state : state); > > - } > > -} > > - > > -uint32_t pci_default_read_config(PCIDevice *d, > > - uint32_t address, int len) > > -{ > > - uint32_t val = 0; > > - > > - memcpy(&val, d->config + address, len); > > - return le32_to_cpu(val); > > -} > > - > > -void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) > > -{ > > - int i, was_irq_disabled = pci_irq_disabled(d); > > - > > - for (i = 0; i < l; val >>= 8, ++i) { > > - uint8_t wmask = d->wmask[addr + i]; > > - uint8_t w1cmask = d->w1cmask[addr + i]; > > - assert(!(wmask & w1cmask)); > > - d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask); > > - d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ > > - } > > - if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) || > > - ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) || > > - ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) || > > - range_covers_byte(addr, l, PCI_COMMAND)) > > - pci_update_mappings(d); > > - > > - if (range_covers_byte(addr, l, PCI_COMMAND)) { > > - pci_update_irq_disabled(d, was_irq_disabled); > > - memory_region_set_enabled(&d->bus_master_enable_region, > > - pci_get_word(d->config + PCI_COMMAND) > > - & PCI_COMMAND_MASTER); > > - } > > - > > - msi_write_config(d, addr, val, l); > > - msix_write_config(d, addr, val, l); > > -} > > - > > -/***********************************************************/ > > -/* generic PCI irq support */ > > - > > -/* 0 <= irq_num <= 3. level must be 0 or 1 */ > > -static void pci_set_irq(void *opaque, int irq_num, int level) > > -{ > > - PCIDevice *pci_dev = opaque; > > - int change; > > - > > - change = level - pci_irq_state(pci_dev, irq_num); > > - if (!change) > > - return; > > - > > - pci_set_irq_state(pci_dev, irq_num, level); > > - pci_update_irq_status(pci_dev); > > - if (pci_irq_disabled(pci_dev)) > > - return; > > - pci_change_irq_level(pci_dev, irq_num, change); > > -} > > - > > -/* Special hooks used by device assignment */ > > -void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq) > > -{ > > - assert(!bus->parent_dev); > > - bus->route_intx_to_irq = route_intx_to_irq; > > -} > > - > > -PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) > > -{ > > - PCIBus *bus; > > - > > - do { > > - bus = dev->bus; > > - pin = bus->map_irq(dev, pin); > > - dev = bus->parent_dev; > > - } while (dev); > > - > > - if (!bus->route_intx_to_irq) { > > - error_report("PCI: Bug - unimplemented PCI INTx routing (%s)\n", > > - object_get_typename(OBJECT(bus->qbus.parent))); > > - return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 }; > > - } > > - > > - return bus->route_intx_to_irq(bus->irq_opaque, pin); > > -} > > - > > -bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new) > > -{ > > - return old->mode != new->mode || old->irq != new->irq; > > -} > > - > > -void pci_bus_fire_intx_routing_notifier(PCIBus *bus) > > -{ > > - PCIDevice *dev; > > - PCIBus *sec; > > - int i; > > - > > - for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { > > - dev = bus->devices[i]; > > - if (dev && dev->intx_routing_notifier) { > > - dev->intx_routing_notifier(dev); > > - } > > - QLIST_FOREACH(sec, &bus->child, sibling) { > > - pci_bus_fire_intx_routing_notifier(sec); > > - } > > - } > > -} > > - > > -void pci_device_set_intx_routing_notifier(PCIDevice *dev, > > - PCIINTxRoutingNotifier notifier) > > -{ > > - dev->intx_routing_notifier = notifier; > > -} > > - > > -/* > > - * PCI-to-PCI bridge specification > > - * 9.1: Interrupt routing. Table 9-1 > > - * > > - * the PCI Express Base Specification, Revision 2.1 > > - * 2.2.8.1: INTx interrutp signaling - Rules > > - * the Implementation Note > > - * Table 2-20 > > - */ > > -/* > > - * 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD > > - * 0-origin unlike PCI interrupt pin register. > > - */ > > -int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) > > -{ > > - return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; > > -} > > - > > -/***********************************************************/ > > -/* monitor info on PCI */ > > - > > -typedef struct { > > - uint16_t class; > > - const char *desc; > > - const char *fw_name; > > - uint16_t fw_ign_bits; > > -} pci_class_desc; > > - > > -static const pci_class_desc pci_class_descriptions[] = > > -{ > > - { 0x0001, "VGA controller", "display"}, > > - { 0x0100, "SCSI controller", "scsi"}, > > - { 0x0101, "IDE controller", "ide"}, > > - { 0x0102, "Floppy controller", "fdc"}, > > - { 0x0103, "IPI controller", "ipi"}, > > - { 0x0104, "RAID controller", "raid"}, > > - { 0x0106, "SATA controller"}, > > - { 0x0107, "SAS controller"}, > > - { 0x0180, "Storage controller"}, > > - { 0x0200, "Ethernet controller", "ethernet"}, > > - { 0x0201, "Token Ring controller", "token-ring"}, > > - { 0x0202, "FDDI controller", "fddi"}, > > - { 0x0203, "ATM controller", "atm"}, > > - { 0x0280, "Network controller"}, > > - { 0x0300, "VGA controller", "display", 0x00ff}, > > - { 0x0301, "XGA controller"}, > > - { 0x0302, "3D controller"}, > > - { 0x0380, "Display controller"}, > > - { 0x0400, "Video controller", "video"}, > > - { 0x0401, "Audio controller", "sound"}, > > - { 0x0402, "Phone"}, > > - { 0x0403, "Audio controller", "sound"}, > > - { 0x0480, "Multimedia controller"}, > > - { 0x0500, "RAM controller", "memory"}, > > - { 0x0501, "Flash controller", "flash"}, > > - { 0x0580, "Memory controller"}, > > - { 0x0600, "Host bridge", "host"}, > > - { 0x0601, "ISA bridge", "isa"}, > > - { 0x0602, "EISA bridge", "eisa"}, > > - { 0x0603, "MC bridge", "mca"}, > > - { 0x0604, "PCI bridge", "pci"}, > > - { 0x0605, "PCMCIA bridge", "pcmcia"}, > > - { 0x0606, "NUBUS bridge", "nubus"}, > > - { 0x0607, "CARDBUS bridge", "cardbus"}, > > - { 0x0608, "RACEWAY bridge"}, > > - { 0x0680, "Bridge"}, > > - { 0x0700, "Serial port", "serial"}, > > - { 0x0701, "Parallel port", "parallel"}, > > - { 0x0800, "Interrupt controller", "interrupt-controller"}, > > - { 0x0801, "DMA controller", "dma-controller"}, > > - { 0x0802, "Timer", "timer"}, > > - { 0x0803, "RTC", "rtc"}, > > - { 0x0900, "Keyboard", "keyboard"}, > > - { 0x0901, "Pen", "pen"}, > > - { 0x0902, "Mouse", "mouse"}, > > - { 0x0A00, "Dock station", "dock", 0x00ff}, > > - { 0x0B00, "i386 cpu", "cpu", 0x00ff}, > > - { 0x0c00, "Fireware contorller", "fireware"}, > > - { 0x0c01, "Access bus controller", "access-bus"}, > > - { 0x0c02, "SSA controller", "ssa"}, > > - { 0x0c03, "USB controller", "usb"}, > > - { 0x0c04, "Fibre channel controller", "fibre-channel"}, > > - { 0x0c05, "SMBus"}, > > - { 0, NULL} > > -}; > > - > > -static void pci_for_each_device_under_bus(PCIBus *bus, > > - void (*fn)(PCIBus *b, PCIDevice *d, > > - void *opaque), > > - void *opaque) > > -{ > > - PCIDevice *d; > > - int devfn; > > - > > - for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > > - d = bus->devices[devfn]; > > - if (d) { > > - fn(bus, d, opaque); > > - } > > - } > > -} > > - > > -void pci_for_each_device(PCIBus *bus, int bus_num, > > - void (*fn)(PCIBus *b, PCIDevice *d, void *opaque), > > - void *opaque) > > -{ > > - bus = pci_find_bus_nr(bus, bus_num); > > - > > - if (bus) { > > - pci_for_each_device_under_bus(bus, fn, opaque); > > - } > > -} > > - > > -static const pci_class_desc *get_class_desc(int class) > > -{ > > - const pci_class_desc *desc; > > - > > - desc = pci_class_descriptions; > > - while (desc->desc && class != desc->class) { > > - desc++; > > - } > > - > > - return desc; > > -} > > - > > -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num); > > - > > -static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev) > > -{ > > - PciMemoryRegionList *head = NULL, *cur_item = NULL; > > - int i; > > - > > - for (i = 0; i < PCI_NUM_REGIONS; i++) { > > - const PCIIORegion *r = &dev->io_regions[i]; > > - PciMemoryRegionList *region; > > - > > - if (!r->size) { > > - continue; > > - } > > - > > - region = g_malloc0(sizeof(*region)); > > - region->value = g_malloc0(sizeof(*region->value)); > > - > > - if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { > > - region->value->type = g_strdup("io"); > > - } else { > > - region->value->type = g_strdup("memory"); > > - region->value->has_prefetch = true; > > - region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH); > > - region->value->has_mem_type_64 = true; > > - region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64); > > - } > > - > > - region->value->bar = i; > > - region->value->address = r->addr; > > - region->value->size = r->size; > > - > > - /* XXX: waiting for the qapi to support GSList */ > > - if (!cur_item) { > > - head = cur_item = region; > > - } else { > > - cur_item->next = region; > > - cur_item = region; > > - } > > - } > > - > > - return head; > > -} > > - > > -static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus, > > - int bus_num) > > -{ > > - PciBridgeInfo *info; > > - > > - info = g_malloc0(sizeof(*info)); > > - > > - info->bus.number = dev->config[PCI_PRIMARY_BUS]; > > - info->bus.secondary = dev->config[PCI_SECONDARY_BUS]; > > - info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS]; > > - > > - info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range)); > > - info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); > > - info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO); > > - > > - info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range)); > > - info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > > - info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > > - > > - info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range)); > > - info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > > - info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > > - > > - if (dev->config[PCI_SECONDARY_BUS] != 0) { > > - PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]); > > - if (child_bus) { > > - info->has_devices = true; > > - info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]); > > - } > > - } > > - > > - return info; > > -} > > - > > -static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, > > - int bus_num) > > -{ > > - const pci_class_desc *desc; > > - PciDeviceInfo *info; > > - uint8_t type; > > - int class; > > - > > - info = g_malloc0(sizeof(*info)); > > - info->bus = bus_num; > > - info->slot = PCI_SLOT(dev->devfn); > > - info->function = PCI_FUNC(dev->devfn); > > - > > - class = pci_get_word(dev->config + PCI_CLASS_DEVICE); > > - info->class_info.class = class; > > - desc = get_class_desc(class); > > - if (desc->desc) { > > - info->class_info.has_desc = true; > > - info->class_info.desc = g_strdup(desc->desc); > > - } > > - > > - info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID); > > - info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID); > > - info->regions = qmp_query_pci_regions(dev); > > - info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : ""); > > - > > - if (dev->config[PCI_INTERRUPT_PIN] != 0) { > > - info->has_irq = true; > > - info->irq = dev->config[PCI_INTERRUPT_LINE]; > > - } > > - > > - type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; > > - if (type == PCI_HEADER_TYPE_BRIDGE) { > > - info->has_pci_bridge = true; > > - info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num); > > - } > > - > > - return info; > > -} > > - > > -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num) > > -{ > > - PciDeviceInfoList *info, *head = NULL, *cur_item = NULL; > > - PCIDevice *dev; > > - int devfn; > > - > > - for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > > - dev = bus->devices[devfn]; > > - if (dev) { > > - info = g_malloc0(sizeof(*info)); > > - info->value = qmp_query_pci_device(dev, bus, bus_num); > > - > > - /* XXX: waiting for the qapi to support GSList */ > > - if (!cur_item) { > > - head = cur_item = info; > > - } else { > > - cur_item->next = info; > > - cur_item = info; > > - } > > - } > > - } > > - > > - return head; > > -} > > - > > -static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) > > -{ > > - PciInfo *info = NULL; > > - > > - bus = pci_find_bus_nr(bus, bus_num); > > - if (bus) { > > - info = g_malloc0(sizeof(*info)); > > - info->bus = bus_num; > > - info->devices = qmp_query_pci_devices(bus, bus_num); > > - } > > - > > - return info; > > -} > > - > > -PciInfoList *qmp_query_pci(Error **errp) > > -{ > > - PciInfoList *info, *head = NULL, *cur_item = NULL; > > - struct PCIHostBus *host; > > - > > - QLIST_FOREACH(host, &host_buses, next) { > > - info = g_malloc0(sizeof(*info)); > > - info->value = qmp_query_pci_bus(host->bus, 0); > > - > > - /* XXX: waiting for the qapi to support GSList */ > > - if (!cur_item) { > > - head = cur_item = info; > > - } else { > > - cur_item->next = info; > > - cur_item = info; > > - } > > - } > > - > > - return head; > > -} > > - > > -static const char * const pci_nic_models[] = { > > - "ne2k_pci", > > - "i82551", > > - "i82557b", > > - "i82559er", > > - "rtl8139", > > - "e1000", > > - "pcnet", > > - "virtio", > > - NULL > > -}; > > - > > -static const char * const pci_nic_names[] = { > > - "ne2k_pci", > > - "i82551", > > - "i82557b", > > - "i82559er", > > - "rtl8139", > > - "e1000", > > - "pcnet", > > - "virtio-net-pci", > > - NULL > > -}; > > - > > -/* Initialize a PCI NIC. */ > > -/* FIXME callers should check for failure, but don't */ > > -PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, > > - const char *default_devaddr) > > -{ > > - const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr; > > - PCIBus *bus; > > - int devfn; > > - PCIDevice *pci_dev; > > - DeviceState *dev; > > - int i; > > - > > - i = qemu_find_nic_model(nd, pci_nic_models, default_model); > > - if (i < 0) > > - return NULL; > > - > > - bus = pci_get_bus_devfn(&devfn, devaddr); > > - if (!bus) { > > - error_report("Invalid PCI device address %s for device %s", > > - devaddr, pci_nic_names[i]); > > - return NULL; > > - } > > - > > - pci_dev = pci_create(bus, devfn, pci_nic_names[i]); > > - dev = &pci_dev->qdev; > > - qdev_set_nic_properties(dev, nd); > > - if (qdev_init(dev) < 0) > > - return NULL; > > - return pci_dev; > > -} > > - > > -PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, > > - const char *default_devaddr) > > -{ > > - PCIDevice *res; > > - > > - if (qemu_show_nic_models(nd->model, pci_nic_models)) > > - exit(0); > > - > > - res = pci_nic_init(nd, default_model, default_devaddr); > > - if (!res) > > - exit(1); > > - return res; > > -} > > - > > -PCIDevice *pci_vga_init(PCIBus *bus) > > -{ > > - switch (vga_interface_type) { > > - case VGA_CIRRUS: > > - return pci_create_simple(bus, -1, "cirrus-vga"); > > - case VGA_QXL: > > - return pci_create_simple(bus, -1, "qxl-vga"); > > - case VGA_STD: > > - return pci_create_simple(bus, -1, "VGA"); > > - case VGA_VMWARE: > > - return pci_create_simple(bus, -1, "vmware-svga"); > > - case VGA_NONE: > > - default: /* Other non-PCI types. Checking for unsupported types is already > > - done in vl.c. */ > > - return NULL; > > - } > > -} > > - > > -/* Whether a given bus number is in range of the secondary > > - * bus of the given bridge device. */ > > -static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) > > -{ > > - return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) & > > - PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ && > > - dev->config[PCI_SECONDARY_BUS] < bus_num && > > - bus_num <= dev->config[PCI_SUBORDINATE_BUS]; > > -} > > - > > -static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) > > -{ > > - PCIBus *sec; > > - > > - if (!bus) { > > - return NULL; > > - } > > - > > - if (pci_bus_num(bus) == bus_num) { > > - return bus; > > - } > > - > > - /* Consider all bus numbers in range for the host pci bridge. */ > > - if (bus->parent_dev && > > - !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) { > > - return NULL; > > - } > > - > > - /* try child bus */ > > - for (; bus; bus = sec) { > > - QLIST_FOREACH(sec, &bus->child, sibling) { > > - assert(sec->parent_dev); > > - if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) { > > - return sec; > > - } > > - if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) { > > - break; > > - } > > - } > > - } > > - > > - return NULL; > > -} > > - > > -PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn) > > -{ > > - bus = pci_find_bus_nr(bus, bus_num); > > - > > - if (!bus) > > - return NULL; > > - > > - return bus->devices[devfn]; > > -} > > - > > -static int pci_qdev_init(DeviceState *qdev) > > -{ > > - PCIDevice *pci_dev = (PCIDevice *)qdev; > > - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > > - PCIBus *bus; > > - int rc; > > - bool is_default_rom; > > - > > - /* initialize cap_present for pci_is_express() and pci_config_size() */ > > - if (pc->is_express) { > > - pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; > > - } > > - > > - bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); > > - pci_dev = do_pci_register_device(pci_dev, bus, > > - object_get_typename(OBJECT(qdev)), > > - pci_dev->devfn); > > - if (pci_dev == NULL) > > - return -1; > > - if (qdev->hotplugged && pc->no_hotplug) { > > - qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev))); > > - do_pci_unregister_device(pci_dev); > > - return -1; > > - } > > - if (pc->init) { > > - rc = pc->init(pci_dev); > > - if (rc != 0) { > > - do_pci_unregister_device(pci_dev); > > - return rc; > > - } > > - } > > - > > - /* rom loading */ > > - is_default_rom = false; > > - if (pci_dev->romfile == NULL && pc->romfile != NULL) { > > - pci_dev->romfile = g_strdup(pc->romfile); > > - is_default_rom = true; > > - } > > - pci_add_option_rom(pci_dev, is_default_rom); > > - > > - if (bus->hotplug) { > > - /* Let buses differentiate between hotplug and when device is > > - * enabled during qemu machine creation. */ > > - rc = bus->hotplug(bus->hotplug_qdev, pci_dev, > > - qdev->hotplugged ? PCI_HOTPLUG_ENABLED: > > - PCI_COLDPLUG_ENABLED); > > - if (rc != 0) { > > - int r = pci_unregister_device(&pci_dev->qdev); > > - assert(!r); > > - return rc; > > - } > > - } > > - return 0; > > -} > > - > > -static int pci_unplug_device(DeviceState *qdev) > > -{ > > - PCIDevice *dev = PCI_DEVICE(qdev); > > - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); > > - > > - if (pc->no_hotplug) { > > - qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev))); > > - return -1; > > - } > > - return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, > > - PCI_HOTPLUG_DISABLED); > > -} > > - > > -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, > > - const char *name) > > -{ > > - DeviceState *dev; > > - > > - dev = qdev_create(&bus->qbus, name); > > - qdev_prop_set_int32(dev, "addr", devfn); > > - qdev_prop_set_bit(dev, "multifunction", multifunction); > > - return PCI_DEVICE(dev); > > -} > > - > > -PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, > > - bool multifunction, > > - const char *name) > > -{ > > - PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction, name); > > - qdev_init_nofail(&dev->qdev); > > - return dev; > > -} > > - > > -PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name) > > -{ > > - return pci_create_multifunction(bus, devfn, false, name); > > -} > > - > > -PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) > > -{ > > - return pci_create_simple_multifunction(bus, devfn, false, name); > > -} > > - > > -static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size) > > -{ > > - int offset = PCI_CONFIG_HEADER_SIZE; > > - int i; > > - for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) { > > - if (pdev->used[i]) > > - offset = i + 1; > > - else if (i - offset + 1 == size) > > - return offset; > > - } > > - return 0; > > -} > > - > > -static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id, > > - uint8_t *prev_p) > > -{ > > - uint8_t next, prev; > > - > > - if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST)) > > - return 0; > > - > > - for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); > > - prev = next + PCI_CAP_LIST_NEXT) > > - if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id) > > - break; > > - > > - if (prev_p) > > - *prev_p = prev; > > - return next; > > -} > > - > > -static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset) > > -{ > > - uint8_t next, prev, found = 0; > > - > > - if (!(pdev->used[offset])) { > > - return 0; > > - } > > - > > - assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST); > > - > > - for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); > > - prev = next + PCI_CAP_LIST_NEXT) { > > - if (next <= offset && next > found) { > > - found = next; > > - } > > - } > > - return found; > > -} > > - > > -/* Patch the PCI vendor and device ids in a PCI rom image if necessary. > > - This is needed for an option rom which is used for more than one device. */ > > -static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size) > > -{ > > - uint16_t vendor_id; > > - uint16_t device_id; > > - uint16_t rom_vendor_id; > > - uint16_t rom_device_id; > > - uint16_t rom_magic; > > - uint16_t pcir_offset; > > - uint8_t checksum; > > - > > - /* Words in rom data are little endian (like in PCI configuration), > > - so they can be read / written with pci_get_word / pci_set_word. */ > > - > > - /* Only a valid rom will be patched. */ > > - rom_magic = pci_get_word(ptr); > > - if (rom_magic != 0xaa55) { > > - PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic); > > - return; > > - } > > - pcir_offset = pci_get_word(ptr + 0x18); > > - if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) { > > - PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset); > > - return; > > - } > > - > > - vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); > > - device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); > > - rom_vendor_id = pci_get_word(ptr + pcir_offset + 4); > > - rom_device_id = pci_get_word(ptr + pcir_offset + 6); > > - > > - PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile, > > - vendor_id, device_id, rom_vendor_id, rom_device_id); > > - > > - checksum = ptr[6]; > > - > > - if (vendor_id != rom_vendor_id) { > > - /* Patch vendor id and checksum (at offset 6 for etherboot roms). */ > > - checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8); > > - checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8); > > - PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > > - ptr[6] = checksum; > > - pci_set_word(ptr + pcir_offset + 4, vendor_id); > > - } > > - > > - if (device_id != rom_device_id) { > > - /* Patch device id and checksum (at offset 6 for etherboot roms). */ > > - checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8); > > - checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8); > > - PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > > - ptr[6] = checksum; > > - pci_set_word(ptr + pcir_offset + 6, device_id); > > - } > > -} > > - > > -/* Add an option rom for the device */ > > -static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) > > -{ > > - int size; > > - char *path; > > - void *ptr; > > - char name[32]; > > - const VMStateDescription *vmsd; > > - > > - if (!pdev->romfile) > > - return 0; > > - if (strlen(pdev->romfile) == 0) > > - return 0; > > - > > - if (!pdev->rom_bar) { > > - /* > > - * Load rom via fw_cfg instead of creating a rom bar, > > - * for 0.11 compatibility. > > - */ > > - int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE); > > - if (class == 0x0300) { > > - rom_add_vga(pdev->romfile); > > - } else { > > - rom_add_option(pdev->romfile, -1); > > - } > > - return 0; > > - } > > - > > - path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); > > - if (path == NULL) { > > - path = g_strdup(pdev->romfile); > > - } > > - > > - size = get_image_size(path); > > - if (size < 0) { > > - error_report("%s: failed to find romfile \"%s\"", > > - __FUNCTION__, pdev->romfile); > > - g_free(path); > > - return -1; > > - } > > - if (size & (size - 1)) { > > - size = 1 << qemu_fls(size); > > - } > > - > > - vmsd = qdev_get_vmsd(DEVICE(pdev)); > > - > > - if (vmsd) { > > - snprintf(name, sizeof(name), "%s.rom", vmsd->name); > > - } else { > > - snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev))); > > - } > > - pdev->has_rom = true; > > - memory_region_init_ram(&pdev->rom, name, size); > > - vmstate_register_ram(&pdev->rom, &pdev->qdev); > > - ptr = memory_region_get_ram_ptr(&pdev->rom); > > - load_image(path, ptr); > > - g_free(path); > > - > > - if (is_default_rom) { > > - /* Only the default rom images will be patched (if needed). */ > > - pci_patch_ids(pdev, ptr, size); > > - } > > - > > - qemu_put_ram_ptr(ptr); > > - > > - pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom); > > - > > - return 0; > > -} > > - > > -static void pci_del_option_rom(PCIDevice *pdev) > > -{ > > - if (!pdev->has_rom) > > - return; > > - > > - vmstate_unregister_ram(&pdev->rom, &pdev->qdev); > > - memory_region_destroy(&pdev->rom); > > - pdev->has_rom = false; > > -} > > - > > -/* > > - * if !offset > > - * Reserve space and add capability to the linked list in pci config space > > - * > > - * if offset = 0, > > - * Find and reserve space and add capability to the linked list > > - * in pci config space */ > > -int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, > > - uint8_t offset, uint8_t size) > > -{ > > - uint8_t *config; > > - int i, overlapping_cap; > > - > > - if (!offset) { > > - offset = pci_find_space(pdev, size); > > - if (!offset) { > > - return -ENOSPC; > > - } > > - } else { > > - /* Verify that capabilities don't overlap. Note: device assignment > > - * depends on this check to verify that the device is not broken. > > - * Should never trigger for emulated devices, but it's helpful > > - * for debugging these. */ > > - for (i = offset; i < offset + size; i++) { > > - overlapping_cap = pci_find_capability_at_offset(pdev, i); > > - if (overlapping_cap) { > > - fprintf(stderr, "ERROR: %04x:%02x:%02x.%x " > > - "Attempt to add PCI capability %x at offset " > > - "%x overlaps existing capability %x at offset %x\n", > > - pci_find_domain(pdev->bus), pci_bus_num(pdev->bus), > > - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), > > - cap_id, offset, overlapping_cap, i); > > - return -EINVAL; > > - } > > - } > > - } > > - > > - config = pdev->config + offset; > > - config[PCI_CAP_LIST_ID] = cap_id; > > - config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST]; > > - pdev->config[PCI_CAPABILITY_LIST] = offset; > > - pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST; > > - memset(pdev->used + offset, 0xFF, QEMU_ALIGN_UP(size, 4)); > > - /* Make capability read-only by default */ > > - memset(pdev->wmask + offset, 0, size); > > - /* Check capability by default */ > > - memset(pdev->cmask + offset, 0xFF, size); > > - return offset; > > -} > > - > > -/* Unlink capability from the pci config space. */ > > -void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) > > -{ > > - uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev); > > - if (!offset) > > - return; > > - pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT]; > > - /* Make capability writable again */ > > - memset(pdev->wmask + offset, 0xff, size); > > - memset(pdev->w1cmask + offset, 0, size); > > - /* Clear cmask as device-specific registers can't be checked */ > > - memset(pdev->cmask + offset, 0, size); > > - memset(pdev->used + offset, 0, QEMU_ALIGN_UP(size, 4)); > > - > > - if (!pdev->config[PCI_CAPABILITY_LIST]) > > - pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST; > > -} > > - > > -uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id) > > -{ > > - return pci_find_capability_list(pdev, cap_id, NULL); > > -} > > - > > -static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) > > -{ > > - PCIDevice *d = (PCIDevice *)dev; > > - const pci_class_desc *desc; > > - char ctxt[64]; > > - PCIIORegion *r; > > - int i, class; > > - > > - class = pci_get_word(d->config + PCI_CLASS_DEVICE); > > - desc = pci_class_descriptions; > > - while (desc->desc && class != desc->class) > > - desc++; > > - if (desc->desc) { > > - snprintf(ctxt, sizeof(ctxt), "%s", desc->desc); > > - } else { > > - snprintf(ctxt, sizeof(ctxt), "Class %04x", class); > > - } > > - > > - monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " > > - "pci id %04x:%04x (sub %04x:%04x)\n", > > - indent, "", ctxt, pci_bus_num(d->bus), > > - PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), > > - pci_get_word(d->config + PCI_VENDOR_ID), > > - pci_get_word(d->config + PCI_DEVICE_ID), > > - pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID), > > - pci_get_word(d->config + PCI_SUBSYSTEM_ID)); > > - for (i = 0; i < PCI_NUM_REGIONS; i++) { > > - r = &d->io_regions[i]; > > - if (!r->size) > > - continue; > > - monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS > > - " [0x%"FMT_PCIBUS"]\n", > > - indent, "", > > - i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem", > > - r->addr, r->addr + r->size - 1); > > - } > > -} > > - > > -static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len) > > -{ > > - PCIDevice *d = (PCIDevice *)dev; > > - const char *name = NULL; > > - const pci_class_desc *desc = pci_class_descriptions; > > - int class = pci_get_word(d->config + PCI_CLASS_DEVICE); > > - > > - while (desc->desc && > > - (class & ~desc->fw_ign_bits) != > > - (desc->class & ~desc->fw_ign_bits)) { > > - desc++; > > - } > > - > > - if (desc->desc) { > > - name = desc->fw_name; > > - } > > - > > - if (name) { > > - pstrcpy(buf, len, name); > > - } else { > > - snprintf(buf, len, "pci%04x,%04x", > > - pci_get_word(d->config + PCI_VENDOR_ID), > > - pci_get_word(d->config + PCI_DEVICE_ID)); > > - } > > - > > - return buf; > > -} > > - > > -static char *pcibus_get_fw_dev_path(DeviceState *dev) > > -{ > > - PCIDevice *d = (PCIDevice *)dev; > > - char path[50], name[33]; > > - int off; > > - > > - off = snprintf(path, sizeof(path), "%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 = container_of(dev, PCIDevice, qdev); > > - PCIDevice *t; > > - int slot_depth; > > - /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function. > > - * 00 is added here to make this format compatible with > > - * domain:Bus:Slot.Func for systems without nested PCI bridges. > > - * Slot.Function list specifies the slot and function numbers for all > > - * devices on the path from root to the specific device. */ > > - char domain[] = "DDDD:00"; > > - char slot[] = ":SS.F"; > > - int domain_len = sizeof domain - 1 /* For '\0' */; > > - int slot_len = sizeof slot - 1 /* For '\0' */; > > - int path_len; > > - char *path, *p; > > - int s; > > - > > - /* Calculate # of slots on path between device and root. */; > > - slot_depth = 0; > > - for (t = d; t; t = t->bus->parent_dev) { > > - ++slot_depth; > > - } > > - > > - path_len = domain_len + slot_len * slot_depth; > > - > > - /* Allocate memory, fill in the terminating null byte. */ > > - path = g_malloc(path_len + 1 /* For '\0' */); > > - path[path_len] = '\0'; > > - > > - /* First field is the domain. */ > > - s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus)); > > - assert(s == domain_len); > > - memcpy(path, domain, domain_len); > > - > > - /* Fill in slot numbers. We walk up from device to root, so need to print > > - * them in the reverse order, last to first. */ > > - p = path + path_len; > > - for (t = d; t; t = t->bus->parent_dev) { > > - p -= slot_len; > > - s = snprintf(slot, sizeof slot, ":%02x.%x", > > - PCI_SLOT(t->devfn), PCI_FUNC(t->devfn)); > > - assert(s == slot_len); > > - memcpy(p, slot, slot_len); > > - } > > - > > - return path; > > -} > > - > > -static int pci_qdev_find_recursive(PCIBus *bus, > > - const char *id, PCIDevice **pdev) > > -{ > > - DeviceState *qdev = qdev_find_recursive(&bus->qbus, id); > > - if (!qdev) { > > - return -ENODEV; > > - } > > - > > - /* roughly check if given qdev is pci device */ > > - if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) { > > - *pdev = PCI_DEVICE(qdev); > > - return 0; > > - } > > - return -EINVAL; > > -} > > - > > -int pci_qdev_find_device(const char *id, PCIDevice **pdev) > > -{ > > - struct PCIHostBus *host; > > - int rc = -ENODEV; > > - > > - QLIST_FOREACH(host, &host_buses, next) { > > - int tmp = pci_qdev_find_recursive(host->bus, id, pdev); > > - if (!tmp) { > > - rc = 0; > > - break; > > - } > > - if (tmp != -ENODEV) { > > - rc = tmp; > > - } > > - } > > - > > - return rc; > > -} > > - > > -MemoryRegion *pci_address_space(PCIDevice *dev) > > -{ > > - return dev->bus->address_space_mem; > > -} > > - > > -MemoryRegion *pci_address_space_io(PCIDevice *dev) > > -{ > > - return dev->bus->address_space_io; > > -} > > - > > -static void pci_device_class_init(ObjectClass *klass, void *data) > > -{ > > - DeviceClass *k = DEVICE_CLASS(klass); > > - k->init = pci_qdev_init; > > - k->unplug = pci_unplug_device; > > - k->exit = pci_unregister_device; > > - k->bus_type = TYPE_PCI_BUS; > > - k->props = pci_props; > > -} > > - > > -void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque) > > -{ > > - bus->dma_context_fn = fn; > > - bus->dma_context_opaque = opaque; > > -} > > - > > -static TypeInfo pci_device_type_info = { > > - .name = TYPE_PCI_DEVICE, > > - .parent = TYPE_DEVICE, > > - .instance_size = sizeof(PCIDevice), > > - .abstract = true, > > - .class_size = sizeof(PCIDeviceClass), > > - .class_init = pci_device_class_init, > > -}; > > - > > -static void pci_register_types(void) > > -{ > > - type_register_static(&pci_bus_info); > > - type_register_static(&pci_device_type_info); > > -} > > - > > -type_init(pci_register_types) > > diff --git a/hw/pci.h b/hw/pci.h > > deleted file mode 100644 > > index 4da0c2a..0000000 > > --- a/hw/pci.h > > +++ /dev/null > > @@ -1,684 +0,0 @@ > > -#ifndef QEMU_PCI_H > > -#define QEMU_PCI_H > > - > > -#include "qemu-common.h" > > - > > -#include "qdev.h" > > -#include "memory.h" > > -#include "dma.h" > > - > > -/* PCI includes legacy ISA access. */ > > -#include "isa.h" > > - > > -#include "pcie.h" > > - > > -/* PCI bus */ > > - > > -#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) > > -#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) > > -#define PCI_FUNC(devfn) ((devfn) & 0x07) > > -#define PCI_SLOT_MAX 32 > > -#define PCI_FUNC_MAX 8 > > - > > -/* Class, Vendor and Device IDs from Linux's pci_ids.h */ > > -#include "pci_ids.h" > > - > > -/* QEMU-specific Vendor and Device ID definitions */ > > - > > -/* IBM (0x1014) */ > > -#define PCI_DEVICE_ID_IBM_440GX 0x027f > > -#define PCI_DEVICE_ID_IBM_OPENPIC2 0xffff > > - > > -/* Hitachi (0x1054) */ > > -#define PCI_VENDOR_ID_HITACHI 0x1054 > > -#define PCI_DEVICE_ID_HITACHI_SH7751R 0x350e > > - > > -/* Apple (0x106b) */ > > -#define PCI_DEVICE_ID_APPLE_343S1201 0x0010 > > -#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI 0x001e > > -#define PCI_DEVICE_ID_APPLE_UNI_N_PCI 0x001f > > -#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL 0x0022 > > -#define PCI_DEVICE_ID_APPLE_IPID_USB 0x003f > > - > > -/* Realtek (0x10ec) */ > > -#define PCI_DEVICE_ID_REALTEK_8029 0x8029 > > - > > -/* Xilinx (0x10ee) */ > > -#define PCI_DEVICE_ID_XILINX_XC2VP30 0x0300 > > - > > -/* Marvell (0x11ab) */ > > -#define PCI_DEVICE_ID_MARVELL_GT6412X 0x4620 > > - > > -/* QEMU/Bochs VGA (0x1234) */ > > -#define PCI_VENDOR_ID_QEMU 0x1234 > > -#define PCI_DEVICE_ID_QEMU_VGA 0x1111 > > - > > -/* VMWare (0x15ad) */ > > -#define PCI_VENDOR_ID_VMWARE 0x15ad > > -#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 > > -#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 > > -#define PCI_DEVICE_ID_VMWARE_NET 0x0720 > > -#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 > > -#define PCI_DEVICE_ID_VMWARE_IDE 0x1729 > > - > > -/* Intel (0x8086) */ > > -#define PCI_DEVICE_ID_INTEL_82551IT 0x1209 > > -#define PCI_DEVICE_ID_INTEL_82557 0x1229 > > -#define PCI_DEVICE_ID_INTEL_82801IR 0x2922 > > - > > -/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */ > > -#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 > > -#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4 > > -#define PCI_SUBDEVICE_ID_QEMU 0x1100 > > - > > -#define PCI_DEVICE_ID_VIRTIO_NET 0x1000 > > -#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 > > -#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 > > -#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 > > -#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 > > -#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 > > - > > -#define FMT_PCIBUS PRIx64 > > - > > -typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, > > - uint32_t address, uint32_t data, int len); > > -typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, > > - uint32_t address, int len); > > -typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, > > - pcibus_t addr, pcibus_t size, int type); > > -typedef void PCIUnregisterFunc(PCIDevice *pci_dev); > > - > > -typedef struct PCIIORegion { > > - pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ > > -#define PCI_BAR_UNMAPPED (~(pcibus_t)0) > > - pcibus_t size; > > - uint8_t type; > > - MemoryRegion *memory; > > - MemoryRegion *address_space; > > -} PCIIORegion; > > - > > -#define PCI_ROM_SLOT 6 > > -#define PCI_NUM_REGIONS 7 > > - > > -#include "pci_regs.h" > > - > > -/* PCI HEADER_TYPE */ > > -#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 > > - > > -/* Size of the standard PCI config header */ > > -#define PCI_CONFIG_HEADER_SIZE 0x40 > > -/* Size of the standard PCI config space */ > > -#define PCI_CONFIG_SPACE_SIZE 0x100 > > -/* Size of the standart PCIe config space: 4KB */ > > -#define PCIE_CONFIG_SPACE_SIZE 0x1000 > > - > > -#define PCI_NUM_PINS 4 /* A-D */ > > - > > -/* Bits in cap_present field. */ > > -enum { > > - QEMU_PCI_CAP_MSI = 0x1, > > - QEMU_PCI_CAP_MSIX = 0x2, > > - QEMU_PCI_CAP_EXPRESS = 0x4, > > - > > - /* multifunction capable device */ > > -#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3 > > - QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR), > > - > > - /* command register SERR bit enabled */ > > -#define QEMU_PCI_CAP_SERR_BITNR 4 > > - QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR), > > - /* Standard hot plug controller. */ > > -#define QEMU_PCI_SHPC_BITNR 5 > > - QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR), > > -#define QEMU_PCI_SLOTID_BITNR 6 > > - QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_BITNR), > > -}; > > - > > -#define TYPE_PCI_DEVICE "pci-device" > > -#define PCI_DEVICE(obj) \ > > - OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE) > > -#define PCI_DEVICE_CLASS(klass) \ > > - OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE) > > -#define PCI_DEVICE_GET_CLASS(obj) \ > > - OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE) > > - > > -typedef struct PCIINTxRoute { > > - enum { > > - PCI_INTX_ENABLED, > > - PCI_INTX_INVERTED, > > - PCI_INTX_DISABLED, > > - } mode; > > - int irq; > > -} PCIINTxRoute; > > - > > -typedef struct PCIDeviceClass { > > - DeviceClass parent_class; > > - > > - int (*init)(PCIDevice *dev); > > - PCIUnregisterFunc *exit; > > - PCIConfigReadFunc *config_read; > > - PCIConfigWriteFunc *config_write; > > - > > - uint16_t vendor_id; > > - uint16_t device_id; > > - uint8_t revision; > > - uint16_t class_id; > > - uint16_t subsystem_vendor_id; /* only for header type = 0 */ > > - uint16_t subsystem_id; /* only for header type = 0 */ > > - > > - /* > > - * pci-to-pci bridge or normal device. > > - * This doesn't mean pci host switch. > > - * When card bus bridge is supported, this would be enhanced. > > - */ > > - int is_bridge; > > - > > - /* pcie stuff */ > > - int is_express; /* is this device pci express? */ > > - > > - /* device isn't hot-pluggable */ > > - int no_hotplug; > > - > > - /* rom bar */ > > - const char *romfile; > > -} PCIDeviceClass; > > - > > -typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev); > > -typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector, > > - MSIMessage msg); > > -typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector); > > - > > -struct PCIDevice { > > - DeviceState qdev; > > - > > - /* PCI config space */ > > - uint8_t *config; > > - > > - /* Used to enable config checks on load. Note that writable bits are > > - * never checked even if set in cmask. */ > > - uint8_t *cmask; > > - > > - /* Used to implement R/W bytes */ > > - uint8_t *wmask; > > - > > - /* Used to implement RW1C(Write 1 to Clear) bytes */ > > - uint8_t *w1cmask; > > - > > - /* Used to allocate config space for capabilities. */ > > - uint8_t *used; > > - > > - /* the following fields are read only */ > > - PCIBus *bus; > > - int32_t devfn; > > - char name[64]; > > - PCIIORegion io_regions[PCI_NUM_REGIONS]; > > - AddressSpace bus_master_as; > > - MemoryRegion bus_master_enable_region; > > - DMAContext *dma; > > - > > - /* do not access the following fields */ > > - PCIConfigReadFunc *config_read; > > - PCIConfigWriteFunc *config_write; > > - > > - /* IRQ objects for the INTA-INTD pins. */ > > - qemu_irq *irq; > > - > > - /* Current IRQ levels. Used internally by the generic PCI code. */ > > - uint8_t irq_state; > > - > > - /* Capability bits */ > > - uint32_t cap_present; > > - > > - /* Offset of MSI-X capability in config space */ > > - uint8_t msix_cap; > > - > > - /* MSI-X entries */ > > - int msix_entries_nr; > > - > > - /* Space to store MSIX table & pending bit array */ > > - uint8_t *msix_table; > > - uint8_t *msix_pba; > > - /* MemoryRegion container for msix exclusive BAR setup */ > > - MemoryRegion msix_exclusive_bar; > > - /* Memory Regions for MSIX table and pending bit entries. */ > > - MemoryRegion msix_table_mmio; > > - MemoryRegion msix_pba_mmio; > > - /* Reference-count for entries actually in use by driver. */ > > - unsigned *msix_entry_used; > > - /* MSIX function mask set or MSIX disabled */ > > - bool msix_function_masked; > > - /* Version id needed for VMState */ > > - int32_t version_id; > > - > > - /* Offset of MSI capability in config space */ > > - uint8_t msi_cap; > > - > > - /* PCI Express */ > > - PCIExpressDevice exp; > > - > > - /* SHPC */ > > - SHPCDevice *shpc; > > - > > - /* Location of option rom */ > > - char *romfile; > > - bool has_rom; > > - MemoryRegion rom; > > - uint32_t rom_bar; > > - > > - /* INTx routing notifier */ > > - PCIINTxRoutingNotifier intx_routing_notifier; > > - > > - /* MSI-X notifiers */ > > - MSIVectorUseNotifier msix_vector_use_notifier; > > - MSIVectorReleaseNotifier msix_vector_release_notifier; > > -}; > > - > > -void pci_register_bar(PCIDevice *pci_dev, int region_num, > > - uint8_t attr, MemoryRegion *memory); > > -pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num); > > - > > -int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, > > - uint8_t offset, uint8_t size); > > - > > -void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); > > - > > -uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id); > > - > > - > > -uint32_t pci_default_read_config(PCIDevice *d, > > - uint32_t address, int len); > > -void pci_default_write_config(PCIDevice *d, > > - uint32_t address, uint32_t val, int len); > > -void pci_device_save(PCIDevice *s, QEMUFile *f); > > -int pci_device_load(PCIDevice *s, QEMUFile *f); > > -MemoryRegion *pci_address_space(PCIDevice *dev); > > -MemoryRegion *pci_address_space_io(PCIDevice *dev); > > - > > -typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); > > -typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); > > -typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin); > > - > > -typedef enum { > > - PCI_HOTPLUG_DISABLED, > > - PCI_HOTPLUG_ENABLED, > > - PCI_COLDPLUG_ENABLED, > > -} PCIHotplugState; > > - > > -typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, > > - PCIHotplugState state); > > -void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, > > - const char *name, > > - MemoryRegion *address_space_mem, > > - MemoryRegion *address_space_io, > > - uint8_t devfn_min); > > -PCIBus *pci_bus_new(DeviceState *parent, const char *name, > > - MemoryRegion *address_space_mem, > > - MemoryRegion *address_space_io, > > - uint8_t devfn_min); > > -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > > - void *irq_opaque, int nirq); > > -int pci_bus_get_irq_level(PCIBus *bus, int irq_num); > > -void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev); > > -/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */ > > -int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin); > > -PCIBus *pci_register_bus(DeviceState *parent, const char *name, > > - pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > > - void *irq_opaque, > > - MemoryRegion *address_space_mem, > > - MemoryRegion *address_space_io, > > - uint8_t devfn_min, int nirq); > > -void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn); > > -PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin); > > -bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new); > > -void pci_bus_fire_intx_routing_notifier(PCIBus *bus); > > -void pci_device_set_intx_routing_notifier(PCIDevice *dev, > > - PCIINTxRoutingNotifier notifier); > > -void pci_device_reset(PCIDevice *dev); > > -void pci_bus_reset(PCIBus *bus); > > - > > -PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, > > - const char *default_devaddr); > > -PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, > > - const char *default_devaddr); > > - > > -PCIDevice *pci_vga_init(PCIBus *bus); > > - > > -int pci_bus_num(PCIBus *s); > > -void pci_for_each_device(PCIBus *bus, int bus_num, > > - void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque), > > - void *opaque); > > -PCIBus *pci_find_root_bus(int domain); > > -int pci_find_domain(const PCIBus *bus); > > -PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn); > > -int pci_qdev_find_device(const char *id, PCIDevice **pdev); > > -PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr); > > - > > -int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, > > - unsigned *slotp); > > - > > -void pci_device_deassert_intx(PCIDevice *dev); > > - > > -typedef DMAContext *(*PCIDMAContextFunc)(PCIBus *, void *, int); > > - > > -void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque); > > - > > -static inline void > > -pci_set_byte(uint8_t *config, uint8_t val) > > -{ > > - *config = val; > > -} > > - > > -static inline uint8_t > > -pci_get_byte(const uint8_t *config) > > -{ > > - return *config; > > -} > > - > > -static inline void > > -pci_set_word(uint8_t *config, uint16_t val) > > -{ > > - cpu_to_le16wu((uint16_t *)config, val); > > -} > > - > > -static inline uint16_t > > -pci_get_word(const uint8_t *config) > > -{ > > - return le16_to_cpupu((const uint16_t *)config); > > -} > > - > > -static inline void > > -pci_set_long(uint8_t *config, uint32_t val) > > -{ > > - cpu_to_le32wu((uint32_t *)config, val); > > -} > > - > > -static inline uint32_t > > -pci_get_long(const uint8_t *config) > > -{ > > - return le32_to_cpupu((const uint32_t *)config); > > -} > > - > > -static inline void > > -pci_set_quad(uint8_t *config, uint64_t val) > > -{ > > - cpu_to_le64w((uint64_t *)config, val); > > -} > > - > > -static inline uint64_t > > -pci_get_quad(const uint8_t *config) > > -{ > > - return le64_to_cpup((const uint64_t *)config); > > -} > > - > > -static inline void > > -pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val) > > -{ > > - pci_set_word(&pci_config[PCI_VENDOR_ID], val); > > -} > > - > > -static inline void > > -pci_config_set_device_id(uint8_t *pci_config, uint16_t val) > > -{ > > - pci_set_word(&pci_config[PCI_DEVICE_ID], val); > > -} > > - > > -static inline void > > -pci_config_set_revision(uint8_t *pci_config, uint8_t val) > > -{ > > - pci_set_byte(&pci_config[PCI_REVISION_ID], val); > > -} > > - > > -static inline void > > -pci_config_set_class(uint8_t *pci_config, uint16_t val) > > -{ > > - pci_set_word(&pci_config[PCI_CLASS_DEVICE], val); > > -} > > - > > -static inline void > > -pci_config_set_prog_interface(uint8_t *pci_config, uint8_t val) > > -{ > > - pci_set_byte(&pci_config[PCI_CLASS_PROG], val); > > -} > > - > > -static inline void > > -pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val) > > -{ > > - pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val); > > -} > > - > > -/* > > - * helper functions to do bit mask operation on configuration space. > > - * Just to set bit, use test-and-set and discard returned value. > > - * Just to clear bit, use test-and-clear and discard returned value. > > - * NOTE: They aren't atomic. > > - */ > > -static inline uint8_t > > -pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask) > > -{ > > - uint8_t val = pci_get_byte(config); > > - pci_set_byte(config, val & ~mask); > > - return val & mask; > > -} > > - > > -static inline uint8_t > > -pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask) > > -{ > > - uint8_t val = pci_get_byte(config); > > - pci_set_byte(config, val | mask); > > - return val & mask; > > -} > > - > > -static inline uint16_t > > -pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask) > > -{ > > - uint16_t val = pci_get_word(config); > > - pci_set_word(config, val & ~mask); > > - return val & mask; > > -} > > - > > -static inline uint16_t > > -pci_word_test_and_set_mask(uint8_t *config, uint16_t mask) > > -{ > > - uint16_t val = pci_get_word(config); > > - pci_set_word(config, val | mask); > > - return val & mask; > > -} > > - > > -static inline uint32_t > > -pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask) > > -{ > > - uint32_t val = pci_get_long(config); > > - pci_set_long(config, val & ~mask); > > - return val & mask; > > -} > > - > > -static inline uint32_t > > -pci_long_test_and_set_mask(uint8_t *config, uint32_t mask) > > -{ > > - uint32_t val = pci_get_long(config); > > - pci_set_long(config, val | mask); > > - return val & mask; > > -} > > - > > -static inline uint64_t > > -pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask) > > -{ > > - uint64_t val = pci_get_quad(config); > > - pci_set_quad(config, val & ~mask); > > - return val & mask; > > -} > > - > > -static inline uint64_t > > -pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask) > > -{ > > - uint64_t val = pci_get_quad(config); > > - pci_set_quad(config, val | mask); > > - return val & mask; > > -} > > - > > -/* Access a register specified by a mask */ > > -static inline void > > -pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg) > > -{ > > - uint8_t val = pci_get_byte(config); > > - uint8_t rval = reg << (ffs(mask) - 1); > > - pci_set_byte(config, (~mask & val) | (mask & rval)); > > -} > > - > > -static inline uint8_t > > -pci_get_byte_by_mask(uint8_t *config, uint8_t mask) > > -{ > > - uint8_t val = pci_get_byte(config); > > - return (val & mask) >> (ffs(mask) - 1); > > -} > > - > > -static inline void > > -pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg) > > -{ > > - uint16_t val = pci_get_word(config); > > - uint16_t rval = reg << (ffs(mask) - 1); > > - pci_set_word(config, (~mask & val) | (mask & rval)); > > -} > > - > > -static inline uint16_t > > -pci_get_word_by_mask(uint8_t *config, uint16_t mask) > > -{ > > - uint16_t val = pci_get_word(config); > > - return (val & mask) >> (ffs(mask) - 1); > > -} > > - > > -static inline void > > -pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg) > > -{ > > - uint32_t val = pci_get_long(config); > > - uint32_t rval = reg << (ffs(mask) - 1); > > - pci_set_long(config, (~mask & val) | (mask & rval)); > > -} > > - > > -static inline uint32_t > > -pci_get_long_by_mask(uint8_t *config, uint32_t mask) > > -{ > > - uint32_t val = pci_get_long(config); > > - return (val & mask) >> (ffs(mask) - 1); > > -} > > - > > -static inline void > > -pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg) > > -{ > > - uint64_t val = pci_get_quad(config); > > - uint64_t rval = reg << (ffs(mask) - 1); > > - pci_set_quad(config, (~mask & val) | (mask & rval)); > > -} > > - > > -static inline uint64_t > > -pci_get_quad_by_mask(uint8_t *config, uint64_t mask) > > -{ > > - uint64_t val = pci_get_quad(config); > > - return (val & mask) >> (ffs(mask) - 1); > > -} > > - > > -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, > > - const char *name); > > -PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, > > - bool multifunction, > > - const char *name); > > -PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); > > -PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name); > > - > > -static inline int pci_is_express(const PCIDevice *d) > > -{ > > - return d->cap_present & QEMU_PCI_CAP_EXPRESS; > > -} > > - > > -static inline uint32_t pci_config_size(const PCIDevice *d) > > -{ > > - return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; > > -} > > - > > -/* DMA access functions */ > > -static inline DMAContext *pci_dma_context(PCIDevice *dev) > > -{ > > - return dev->dma; > > -} > > - > > -static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, > > - void *buf, dma_addr_t len, DMADirection dir) > > -{ > > - dma_memory_rw(pci_dma_context(dev), addr, buf, len, dir); > > - return 0; > > -} > > - > > -static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr, > > - void *buf, dma_addr_t len) > > -{ > > - return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE); > > -} > > - > > -static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr, > > - const void *buf, dma_addr_t len) > > -{ > > - return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE); > > -} > > - > > -#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ > > - static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \ > > - dma_addr_t addr) \ > > - { \ > > - return ld##_l##_dma(pci_dma_context(dev), addr); \ > > - } \ > > - static inline void st##_s##_pci_dma(PCIDevice *dev, \ > > - dma_addr_t addr, uint##_bits##_t val) \ > > - { \ > > - st##_s##_dma(pci_dma_context(dev), addr, val); \ > > - } > > - > > -PCI_DMA_DEFINE_LDST(ub, b, 8); > > -PCI_DMA_DEFINE_LDST(uw_le, w_le, 16) > > -PCI_DMA_DEFINE_LDST(l_le, l_le, 32); > > -PCI_DMA_DEFINE_LDST(q_le, q_le, 64); > > -PCI_DMA_DEFINE_LDST(uw_be, w_be, 16) > > -PCI_DMA_DEFINE_LDST(l_be, l_be, 32); > > -PCI_DMA_DEFINE_LDST(q_be, q_be, 64); > > - > > -#undef PCI_DMA_DEFINE_LDST > > - > > -static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, > > - dma_addr_t *plen, DMADirection dir) > > -{ > > - void *buf; > > - > > - buf = dma_memory_map(pci_dma_context(dev), addr, plen, dir); > > - return buf; > > -} > > - > > -static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len, > > - DMADirection dir, dma_addr_t access_len) > > -{ > > - dma_memory_unmap(pci_dma_context(dev), buffer, len, dir, access_len); > > -} > > - > > -static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev, > > - int alloc_hint) > > -{ > > - qemu_sglist_init(qsg, alloc_hint, pci_dma_context(dev)); > > -} > > - > > -extern const VMStateDescription vmstate_pci_device; > > - > > -#define VMSTATE_PCI_DEVICE(_field, _state) { \ > > - .name = (stringify(_field)), \ > > - .size = sizeof(PCIDevice), \ > > - .vmsd = &vmstate_pci_device, \ > > - .flags = VMS_STRUCT, \ > > - .offset = vmstate_offset_value(_state, _field, PCIDevice), \ > > -} > > - > > -#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { \ > > - .name = (stringify(_field)), \ > > - .size = sizeof(PCIDevice), \ > > - .vmsd = &vmstate_pci_device, \ > > - .flags = VMS_STRUCT|VMS_POINTER, \ > > - .offset = vmstate_offset_pointer(_state, _field, PCIDevice), \ > > -} > > - > > -#endif > > diff --git a/hw/pci/Makefile.objs b/hw/pci/Makefile.objs > > new file mode 100644 > > index 0000000..9d21952 > > --- /dev/null > > +++ b/hw/pci/Makefile.objs > > @@ -0,0 +1,6 @@ > > +common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o > > +common-obj-$(CONFIG_PCI) += msix.o msi.o > > +common-obj-$(CONFIG_PCI) += shpc.o > > +common-obj-$(CONFIG_PCI) += slotid_cap.o > > +common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o > > +common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o > > diff --git a/hw/pci/msi.c b/hw/pci/msi.c > > new file mode 100644 > > index 0000000..33037a8 > > --- /dev/null > > +++ b/hw/pci/msi.c > > @@ -0,0 +1,395 @@ > > +/* > > + * msi.c > > + * > > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#include "msi.h" > > +#include "range.h" > > + > > +/* Eventually those constants should go to Linux pci_regs.h */ > > +#define PCI_MSI_PENDING_32 0x10 > > +#define PCI_MSI_PENDING_64 0x14 > > + > > +/* PCI_MSI_ADDRESS_LO */ > > +#define PCI_MSI_ADDRESS_LO_MASK (~0x3) > > + > > +/* If we get rid of cap allocator, we won't need those. */ > > +#define PCI_MSI_32_SIZEOF 0x0a > > +#define PCI_MSI_64_SIZEOF 0x0e > > +#define PCI_MSI_32M_SIZEOF 0x14 > > +#define PCI_MSI_64M_SIZEOF 0x18 > > + > > +#define PCI_MSI_VECTORS_MAX 32 > > + > > +/* Flag for interrupt controller to declare MSI/MSI-X support */ > > +bool msi_supported; > > + > > +/* If we get rid of cap allocator, we won't need this. */ > > +static inline uint8_t msi_cap_sizeof(uint16_t flags) > > +{ > > + switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) { > > + case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT: > > + return PCI_MSI_64M_SIZEOF; > > + case PCI_MSI_FLAGS_64BIT: > > + return PCI_MSI_64_SIZEOF; > > + case PCI_MSI_FLAGS_MASKBIT: > > + return PCI_MSI_32M_SIZEOF; > > + case 0: > > + return PCI_MSI_32_SIZEOF; > > + default: > > + abort(); > > + break; > > + } > > + return 0; > > +} > > + > > +//#define MSI_DEBUG > > + > > +#ifdef MSI_DEBUG > > +# define MSI_DPRINTF(fmt, ...) \ > > + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > > +#else > > +# define MSI_DPRINTF(fmt, ...) do { } while (0) > > +#endif > > +#define MSI_DEV_PRINTF(dev, fmt, ...) \ > > + MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > > + > > +static inline unsigned int msi_nr_vectors(uint16_t flags) > > +{ > > + return 1U << > > + ((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1)); > > +} > > + > > +static inline uint8_t msi_flags_off(const PCIDevice* dev) > > +{ > > + return dev->msi_cap + PCI_MSI_FLAGS; > > +} > > + > > +static inline uint8_t msi_address_lo_off(const PCIDevice* dev) > > +{ > > + return dev->msi_cap + PCI_MSI_ADDRESS_LO; > > +} > > + > > +static inline uint8_t msi_address_hi_off(const PCIDevice* dev) > > +{ > > + return dev->msi_cap + PCI_MSI_ADDRESS_HI; > > +} > > + > > +static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit) > > +{ > > + return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32); > > +} > > + > > +static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit) > > +{ > > + return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32); > > +} > > + > > +static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit) > > +{ > > + return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_PENDING_32); > > +} > > + > > +/* > > + * Special API for POWER to configure the vectors through > > + * a side channel. Should never be used by devices. > > + */ > > +void msi_set_message(PCIDevice *dev, MSIMessage msg) > > +{ > > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > > + > > + if (msi64bit) { > > + pci_set_quad(dev->config + msi_address_lo_off(dev), msg.address); > > + } else { > > + pci_set_long(dev->config + msi_address_lo_off(dev), msg.address); > > + } > > + pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data); > > +} > > + > > +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) > > +{ > > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > > + unsigned int nr_vectors = msi_nr_vectors(flags); > > + MSIMessage msg; > > + > > + assert(vector < nr_vectors); > > + > > + if (msi64bit) { > > + msg.address = pci_get_quad(dev->config + msi_address_lo_off(dev)); > > + } else { > > + msg.address = pci_get_long(dev->config + msi_address_lo_off(dev)); > > + } > > + > > + /* upper bit 31:16 is zero */ > > + msg.data = pci_get_word(dev->config + msi_data_off(dev, msi64bit)); > > + if (nr_vectors > 1) { > > + msg.data &= ~(nr_vectors - 1); > > + msg.data |= vector; > > + } > > + > > + return msg; > > +} > > + > > +bool msi_enabled(const PCIDevice *dev) > > +{ > > + return msi_present(dev) && > > + (pci_get_word(dev->config + msi_flags_off(dev)) & > > + PCI_MSI_FLAGS_ENABLE); > > +} > > + > > +int msi_init(struct PCIDevice *dev, uint8_t offset, > > + unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask) > > +{ > > + unsigned int vectors_order; > > + uint16_t flags; > > + uint8_t cap_size; > > + int config_offset; > > + > > + if (!msi_supported) { > > + return -ENOTSUP; > > + } > > + > > + MSI_DEV_PRINTF(dev, > > + "init offset: 0x%"PRIx8" vector: %"PRId8 > > + " 64bit %d mask %d\n", > > + offset, nr_vectors, msi64bit, msi_per_vector_mask); > > + > > + assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */ > > + assert(nr_vectors > 0); > > + assert(nr_vectors <= PCI_MSI_VECTORS_MAX); > > + /* the nr of MSI vectors is up to 32 */ > > + vectors_order = ffs(nr_vectors) - 1; > > + > > + flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1); > > + if (msi64bit) { > > + flags |= PCI_MSI_FLAGS_64BIT; > > + } > > + if (msi_per_vector_mask) { > > + flags |= PCI_MSI_FLAGS_MASKBIT; > > + } > > + > > + cap_size = msi_cap_sizeof(flags); > > + config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size); > > + if (config_offset < 0) { > > + return config_offset; > > + } > > + > > + dev->msi_cap = config_offset; > > + dev->cap_present |= QEMU_PCI_CAP_MSI; > > + > > + pci_set_word(dev->config + msi_flags_off(dev), flags); > > + pci_set_word(dev->wmask + msi_flags_off(dev), > > + PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); > > + pci_set_long(dev->wmask + msi_address_lo_off(dev), > > + PCI_MSI_ADDRESS_LO_MASK); > > + if (msi64bit) { > > + pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff); > > + } > > + pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff); > > + > > + if (msi_per_vector_mask) { > > + /* Make mask bits 0 to nr_vectors - 1 writable. */ > > + pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit), > > + 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors)); > > + } > > + return config_offset; > > +} > > + > > +void msi_uninit(struct PCIDevice *dev) > > +{ > > + uint16_t flags; > > + uint8_t cap_size; > > + > > + if (!msi_present(dev)) { > > + return; > > + } > > + flags = pci_get_word(dev->config + msi_flags_off(dev)); > > + cap_size = msi_cap_sizeof(flags); > > + pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size); > > + dev->cap_present &= ~QEMU_PCI_CAP_MSI; > > + > > + MSI_DEV_PRINTF(dev, "uninit\n"); > > +} > > + > > +void msi_reset(PCIDevice *dev) > > +{ > > + uint16_t flags; > > + bool msi64bit; > > + > > + if (!msi_present(dev)) { > > + return; > > + } > > + > > + flags = pci_get_word(dev->config + msi_flags_off(dev)); > > + flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); > > + msi64bit = flags & PCI_MSI_FLAGS_64BIT; > > + > > + pci_set_word(dev->config + msi_flags_off(dev), flags); > > + pci_set_long(dev->config + msi_address_lo_off(dev), 0); > > + if (msi64bit) { > > + pci_set_long(dev->config + msi_address_hi_off(dev), 0); > > + } > > + pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0); > > + if (flags & PCI_MSI_FLAGS_MASKBIT) { > > + pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0); > > + pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0); > > + } > > + MSI_DEV_PRINTF(dev, "reset\n"); > > +} > > + > > +static bool msi_is_masked(const PCIDevice *dev, unsigned int vector) > > +{ > > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > + uint32_t mask; > > + assert(vector < PCI_MSI_VECTORS_MAX); > > + > > + if (!(flags & PCI_MSI_FLAGS_MASKBIT)) { > > + return false; > > + } > > + > > + mask = pci_get_long(dev->config + > > + msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT)); > > + return mask & (1U << vector); > > +} > > + > > +void msi_notify(PCIDevice *dev, unsigned int vector) > > +{ > > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > > + unsigned int nr_vectors = msi_nr_vectors(flags); > > + MSIMessage msg; > > + > > + assert(vector < nr_vectors); > > + if (msi_is_masked(dev, vector)) { > > + assert(flags & PCI_MSI_FLAGS_MASKBIT); > > + pci_long_test_and_set_mask( > > + dev->config + msi_pending_off(dev, msi64bit), 1U << vector); > > + MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector); > > + return; > > + } > > + > > + msg = msi_get_message(dev, vector); > > + > > + MSI_DEV_PRINTF(dev, > > + "notify vector 0x%x" > > + " address: 0x%"PRIx64" data: 0x%"PRIx32"\n", > > + vector, msg.address, msg.data); > > + stl_le_phys(msg.address, msg.data); > > +} > > + > > +/* Normally called by pci_default_write_config(). */ > > +void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len) > > +{ > > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; > > + bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT; > > + unsigned int nr_vectors; > > + uint8_t log_num_vecs; > > + uint8_t log_max_vecs; > > + unsigned int vector; > > + uint32_t pending; > > + > > + if (!msi_present(dev) || > > + !ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) { > > + return; > > + } > > + > > +#ifdef MSI_DEBUG > > + MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n", > > + addr, val, len); > > + MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32, > > + flags, > > + pci_get_long(dev->config + msi_address_lo_off(dev))); > > + if (msi64bit) { > > + fprintf(stderr, " address-hi: 0x%"PRIx32, > > + pci_get_long(dev->config + msi_address_hi_off(dev))); > > + } > > + fprintf(stderr, " data: 0x%"PRIx16, > > + pci_get_word(dev->config + msi_data_off(dev, msi64bit))); > > + if (flags & PCI_MSI_FLAGS_MASKBIT) { > > + fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32, > > + pci_get_long(dev->config + msi_mask_off(dev, msi64bit)), > > + pci_get_long(dev->config + msi_pending_off(dev, msi64bit))); > > + } > > + fprintf(stderr, "\n"); > > +#endif > > + > > + if (!(flags & PCI_MSI_FLAGS_ENABLE)) { > > + return; > > + } > > + > > + /* > > + * Now MSI is enabled, clear INTx# interrupts. > > + * the driver is prohibited from writing enable bit to mask > > + * a service request. But the guest OS could do this. > > + * So we just discard the interrupts as moderate fallback. > > + * > > + * 6.8.3.3. Enabling Operation > > + * While enabled for MSI or MSI-X operation, a function is prohibited > > + * from using its INTx# pin (if implemented) to request > > + * service (MSI, MSI-X, and INTx# are mutually exclusive). > > + */ > > + pci_device_deassert_intx(dev); > > + > > + /* > > + * nr_vectors might be set bigger than capable. So clamp it. > > + * This is not legal by spec, so we can do anything we like, > > + * just don't crash the host > > + */ > > + log_num_vecs = > > + (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1); > > + log_max_vecs = > > + (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1); > > + if (log_num_vecs > log_max_vecs) { > > + flags &= ~PCI_MSI_FLAGS_QSIZE; > > + flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1); > > + pci_set_word(dev->config + msi_flags_off(dev), flags); > > + } > > + > > + if (!msi_per_vector_mask) { > > + /* if per vector masking isn't supported, > > + there is no pending interrupt. */ > > + return; > > + } > > + > > + nr_vectors = msi_nr_vectors(flags); > > + > > + /* This will discard pending interrupts, if any. */ > > + pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit)); > > + pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors); > > + pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending); > > + > > + /* deliver pending interrupts which are unmasked */ > > + for (vector = 0; vector < nr_vectors; ++vector) { > > + if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) { > > + continue; > > + } > > + > > + pci_long_test_and_clear_mask( > > + dev->config + msi_pending_off(dev, msi64bit), 1U << vector); > > + msi_notify(dev, vector); > > + } > > +} > > + > > +unsigned int msi_nr_vectors_allocated(const PCIDevice *dev) > > +{ > > + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); > > + return msi_nr_vectors(flags); > > +} > > diff --git a/hw/pci/msi.h b/hw/pci/msi.h > > new file mode 100644 > > index 0000000..150b09a > > --- /dev/null > > +++ b/hw/pci/msi.h > > @@ -0,0 +1,50 @@ > > +/* > > + * msi.h > > + * > > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#ifndef QEMU_MSI_H > > +#define QEMU_MSI_H > > + > > +#include "qemu-common.h" > > +#include "pci.h" > > + > > +struct MSIMessage { > > + uint64_t address; > > + uint32_t data; > > +}; > > + > > +extern bool msi_supported; > > + > > +void msi_set_message(PCIDevice *dev, MSIMessage msg); > > +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector); > > +bool msi_enabled(const PCIDevice *dev); > > +int msi_init(struct PCIDevice *dev, uint8_t offset, > > + unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask); > > +void msi_uninit(struct PCIDevice *dev); > > +void msi_reset(PCIDevice *dev); > > +void msi_notify(PCIDevice *dev, unsigned int vector); > > +void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); > > +unsigned int msi_nr_vectors_allocated(const PCIDevice *dev); > > + > > +static inline bool msi_present(const PCIDevice *dev) > > +{ > > + return dev->cap_present & QEMU_PCI_CAP_MSI; > > +} > > + > > +#endif /* QEMU_MSI_H */ > > diff --git a/hw/pci/msix.c b/hw/pci/msix.c > > new file mode 100644 > > index 0000000..136ef09 > > --- /dev/null > > +++ b/hw/pci/msix.c > > @@ -0,0 +1,562 @@ > > +/* > > + * MSI-X device support > > + * > > + * This module includes support for MSI-X in pci devices. > > + * > > + * Author: Michael S. Tsirkin <mst@redhat.com> > > + * > > + * 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 the > > + * GNU GPL, version 2 or (at your option) any later version. > > + */ > > + > > +#include "hw.h" > > +#include "msi.h" > > +#include "msix.h" > > +#include "pci.h" > > +#include "range.h" > > + > > +#define MSIX_CAP_LENGTH 12 > > + > > +/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */ > > +#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1) > > +#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8) > > +#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8) > > + > > +static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) > > +{ > > + uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; > > + MSIMessage msg; > > + > > + msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); > > + msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); > > + return msg; > > +} > > + > > +/* > > + * Special API for POWER to configure the vectors through > > + * a side channel. Should never be used by devices. > > + */ > > +void msix_set_message(PCIDevice *dev, int vector, struct MSIMessage msg) > > +{ > > + uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; > > + > > + pci_set_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR, msg.address); > > + pci_set_long(table_entry + PCI_MSIX_ENTRY_DATA, msg.data); > > + table_entry[PCI_MSIX_ENTRY_VECTOR_CTRL] &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; > > +} > > + > > +static uint8_t msix_pending_mask(int vector) > > +{ > > + return 1 << (vector % 8); > > +} > > + > > +static uint8_t *msix_pending_byte(PCIDevice *dev, int vector) > > +{ > > + return dev->msix_pba + vector / 8; > > +} > > + > > +static int msix_is_pending(PCIDevice *dev, int vector) > > +{ > > + return *msix_pending_byte(dev, vector) & msix_pending_mask(vector); > > +} > > + > > +static void msix_set_pending(PCIDevice *dev, int vector) > > +{ > > + *msix_pending_byte(dev, vector) |= msix_pending_mask(vector); > > +} > > + > > +static void msix_clr_pending(PCIDevice *dev, int vector) > > +{ > > + *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector); > > +} > > + > > +static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask) > > +{ > > + unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; > > + return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT; > > +} > > + > > +static bool msix_is_masked(PCIDevice *dev, int vector) > > +{ > > + return msix_vector_masked(dev, vector, dev->msix_function_masked); > > +} > > + > > +static void msix_fire_vector_notifier(PCIDevice *dev, > > + unsigned int vector, bool is_masked) > > +{ > > + MSIMessage msg; > > + int ret; > > + > > + if (!dev->msix_vector_use_notifier) { > > + return; > > + } > > + if (is_masked) { > > + dev->msix_vector_release_notifier(dev, vector); > > + } else { > > + msg = msix_get_message(dev, vector); > > + ret = dev->msix_vector_use_notifier(dev, vector, msg); > > + assert(ret >= 0); > > + } > > +} > > + > > +static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked) > > +{ > > + bool is_masked = msix_is_masked(dev, vector); > > + > > + if (is_masked == was_masked) { > > + return; > > + } > > + > > + msix_fire_vector_notifier(dev, vector, is_masked); > > + > > + if (!is_masked && msix_is_pending(dev, vector)) { > > + msix_clr_pending(dev, vector); > > + msix_notify(dev, vector); > > + } > > +} > > + > > +static void msix_update_function_masked(PCIDevice *dev) > > +{ > > + dev->msix_function_masked = !msix_enabled(dev) || > > + (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK); > > +} > > + > > +/* Handle MSI-X capability config write. */ > > +void msix_write_config(PCIDevice *dev, uint32_t addr, > > + uint32_t val, int len) > > +{ > > + unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET; > > + int vector; > > + bool was_masked; > > + > > + if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) { > > + return; > > + } > > + > > + was_masked = dev->msix_function_masked; > > + msix_update_function_masked(dev); > > + > > + if (!msix_enabled(dev)) { > > + return; > > + } > > + > > + pci_device_deassert_intx(dev); > > + > > + if (dev->msix_function_masked == was_masked) { > > + return; > > + } > > + > > + for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > > + msix_handle_mask_update(dev, vector, > > + msix_vector_masked(dev, vector, was_masked)); > > + } > > +} > > + > > +static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr, > > + unsigned size) > > +{ > > + PCIDevice *dev = opaque; > > + > > + return pci_get_long(dev->msix_table + addr); > > +} > > + > > +static void msix_table_mmio_write(void *opaque, hwaddr addr, > > + uint64_t val, unsigned size) > > +{ > > + PCIDevice *dev = opaque; > > + int vector = addr / PCI_MSIX_ENTRY_SIZE; > > + bool was_masked; > > + > > + was_masked = msix_is_masked(dev, vector); > > + pci_set_long(dev->msix_table + addr, val); > > + msix_handle_mask_update(dev, vector, was_masked); > > +} > > + > > +static const MemoryRegionOps msix_table_mmio_ops = { > > + .read = msix_table_mmio_read, > > + .write = msix_table_mmio_write, > > + /* TODO: MSIX should be LITTLE_ENDIAN. */ > > + .endianness = DEVICE_NATIVE_ENDIAN, > > + .valid = { > > + .min_access_size = 4, > > + .max_access_size = 4, > > + }, > > +}; > > + > > +static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, > > + unsigned size) > > +{ > > + PCIDevice *dev = opaque; > > + > > + return pci_get_long(dev->msix_pba + addr); > > +} > > + > > +static const MemoryRegionOps msix_pba_mmio_ops = { > > + .read = msix_pba_mmio_read, > > + /* TODO: MSIX should be LITTLE_ENDIAN. */ > > + .endianness = DEVICE_NATIVE_ENDIAN, > > + .valid = { > > + .min_access_size = 4, > > + .max_access_size = 4, > > + }, > > +}; > > + > > +static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) > > +{ > > + int vector; > > + > > + for (vector = 0; vector < nentries; ++vector) { > > + unsigned offset = > > + vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; > > + bool was_masked = msix_is_masked(dev, vector); > > + > > + dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT; > > + msix_handle_mask_update(dev, vector, was_masked); > > + } > > +} > > + > > +/* Initialize the MSI-X structures */ > > +int msix_init(struct PCIDevice *dev, unsigned short nentries, > > + MemoryRegion *table_bar, uint8_t table_bar_nr, > > + unsigned table_offset, MemoryRegion *pba_bar, > > + uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos) > > +{ > > + int cap; > > + unsigned table_size, pba_size; > > + uint8_t *config; > > + > > + /* Nothing to do if MSI is not supported by interrupt controller */ > > + if (!msi_supported) { > > + return -ENOTSUP; > > + } > > + > > + if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) { > > + return -EINVAL; > > + } > > + > > + table_size = nentries * PCI_MSIX_ENTRY_SIZE; > > + pba_size = QEMU_ALIGN_UP(nentries, 64) / 8; > > + > > + /* Sanity test: table & pba don't overlap, fit within BARs, min aligned */ > > + if ((table_bar_nr == pba_bar_nr && > > + ranges_overlap(table_offset, table_size, pba_offset, pba_size)) || > > + table_offset + table_size > memory_region_size(table_bar) || > > + pba_offset + pba_size > memory_region_size(pba_bar) || > > + (table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) { > > + return -EINVAL; > > + } > > + > > + cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH); > > + if (cap < 0) { > > + return cap; > > + } > > + > > + dev->msix_cap = cap; > > + dev->cap_present |= QEMU_PCI_CAP_MSIX; > > + config = dev->config + cap; > > + > > + pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1); > > + dev->msix_entries_nr = nentries; > > + dev->msix_function_masked = true; > > + > > + pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_nr); > > + pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr); > > + > > + /* Make flags bit writable. */ > > + dev->wmask[cap + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK | > > + MSIX_MASKALL_MASK; > > + > > + dev->msix_table = g_malloc0(table_size); > > + dev->msix_pba = g_malloc0(pba_size); > > + dev->msix_entry_used = g_malloc0(nentries * sizeof *dev->msix_entry_used); > > + > > + msix_mask_all(dev, nentries); > > + > > + memory_region_init_io(&dev->msix_table_mmio, &msix_table_mmio_ops, dev, > > + "msix-table", table_size); > > + memory_region_add_subregion(table_bar, table_offset, &dev->msix_table_mmio); > > + memory_region_init_io(&dev->msix_pba_mmio, &msix_pba_mmio_ops, dev, > > + "msix-pba", pba_size); > > + memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio); > > + > > + return 0; > > +} > > + > > +int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, > > + uint8_t bar_nr) > > +{ > > + int ret; > > + char *name; > > + > > + /* > > + * Migration compatibility dictates that this remains a 4k > > + * BAR with the vector table in the lower half and PBA in > > + * the upper half. Do not use these elsewhere! > > + */ > > +#define MSIX_EXCLUSIVE_BAR_SIZE 4096 > > +#define MSIX_EXCLUSIVE_BAR_TABLE_OFFSET 0 > > +#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2) > > +#define MSIX_EXCLUSIVE_CAP_OFFSET 0 > > + > > + if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) { > > + return -EINVAL; > > + } > > + > > + name = g_strdup_printf("%s-msix", dev->name); > > + memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE); > > + g_free(name); > > + > > + ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr, > > + MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar, > > + bar_nr, MSIX_EXCLUSIVE_BAR_PBA_OFFSET, > > + MSIX_EXCLUSIVE_CAP_OFFSET); > > + if (ret) { > > + memory_region_destroy(&dev->msix_exclusive_bar); > > + return ret; > > + } > > + > > + pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY, > > + &dev->msix_exclusive_bar); > > + > > + return 0; > > +} > > + > > +static void msix_free_irq_entries(PCIDevice *dev) > > +{ > > + int vector; > > + > > + for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > > + dev->msix_entry_used[vector] = 0; > > + msix_clr_pending(dev, vector); > > + } > > +} > > + > > +static void msix_clear_all_vectors(PCIDevice *dev) > > +{ > > + int vector; > > + > > + for (vector = 0; vector < dev->msix_entries_nr; ++vector) { > > + msix_clr_pending(dev, vector); > > + } > > +} > > + > > +/* Clean up resources for the device. */ > > +void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar) > > +{ > > + if (!msix_present(dev)) { > > + return; > > + } > > + pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH); > > + dev->msix_cap = 0; > > + msix_free_irq_entries(dev); > > + dev->msix_entries_nr = 0; > > + memory_region_del_subregion(pba_bar, &dev->msix_pba_mmio); > > + memory_region_destroy(&dev->msix_pba_mmio); > > + g_free(dev->msix_pba); > > + dev->msix_pba = NULL; > > + memory_region_del_subregion(table_bar, &dev->msix_table_mmio); > > + memory_region_destroy(&dev->msix_table_mmio); > > + g_free(dev->msix_table); > > + dev->msix_table = NULL; > > + g_free(dev->msix_entry_used); > > + dev->msix_entry_used = NULL; > > + dev->cap_present &= ~QEMU_PCI_CAP_MSIX; > > +} > > + > > +void msix_uninit_exclusive_bar(PCIDevice *dev) > > +{ > > + if (msix_present(dev)) { > > + msix_uninit(dev, &dev->msix_exclusive_bar, &dev->msix_exclusive_bar); > > + memory_region_destroy(&dev->msix_exclusive_bar); > > + } > > +} > > + > > +void msix_save(PCIDevice *dev, QEMUFile *f) > > +{ > > + unsigned n = dev->msix_entries_nr; > > + > > + if (!msix_present(dev)) { > > + return; > > + } > > + > > + qemu_put_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); > > + qemu_put_buffer(f, dev->msix_pba, (n + 7) / 8); > > +} > > + > > +/* Should be called after restoring the config space. */ > > +void msix_load(PCIDevice *dev, QEMUFile *f) > > +{ > > + unsigned n = dev->msix_entries_nr; > > + unsigned int vector; > > + > > + if (!msix_present(dev)) { > > + return; > > + } > > + > > + msix_clear_all_vectors(dev); > > + qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); > > + qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8); > > + msix_update_function_masked(dev); > > + > > + for (vector = 0; vector < n; vector++) { > > + msix_handle_mask_update(dev, vector, true); > > + } > > +} > > + > > +/* Does device support MSI-X? */ > > +int msix_present(PCIDevice *dev) > > +{ > > + return dev->cap_present & QEMU_PCI_CAP_MSIX; > > +} > > + > > +/* Is MSI-X enabled? */ > > +int msix_enabled(PCIDevice *dev) > > +{ > > + return (dev->cap_present & QEMU_PCI_CAP_MSIX) && > > + (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > > + MSIX_ENABLE_MASK); > > +} > > + > > +/* Send an MSI-X message */ > > +void msix_notify(PCIDevice *dev, unsigned vector) > > +{ > > + MSIMessage msg; > > + > > + if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) > > + return; > > + if (msix_is_masked(dev, vector)) { > > + msix_set_pending(dev, vector); > > + return; > > + } > > + > > + msg = msix_get_message(dev, vector); > > + > > + stl_le_phys(msg.address, msg.data); > > +} > > + > > +void msix_reset(PCIDevice *dev) > > +{ > > + if (!msix_present(dev)) { > > + return; > > + } > > + msix_clear_all_vectors(dev); > > + dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &= > > + ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET]; > > + memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE); > > + memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8); > > + msix_mask_all(dev, dev->msix_entries_nr); > > +} > > + > > +/* PCI spec suggests that devices make it possible for software to configure > > + * less vectors than supported by the device, but does not specify a standard > > + * mechanism for devices to do so. > > + * > > + * We support this by asking devices to declare vectors software is going to > > + * actually use, and checking this on the notification path. Devices that > > + * don't want to follow the spec suggestion can declare all vectors as used. */ > > + > > +/* Mark vector as used. */ > > +int msix_vector_use(PCIDevice *dev, unsigned vector) > > +{ > > + if (vector >= dev->msix_entries_nr) > > + return -EINVAL; > > + dev->msix_entry_used[vector]++; > > + return 0; > > +} > > + > > +/* Mark vector as unused. */ > > +void msix_vector_unuse(PCIDevice *dev, unsigned vector) > > +{ > > + if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) { > > + return; > > + } > > + if (--dev->msix_entry_used[vector]) { > > + return; > > + } > > + msix_clr_pending(dev, vector); > > +} > > + > > +void msix_unuse_all_vectors(PCIDevice *dev) > > +{ > > + if (!msix_present(dev)) { > > + return; > > + } > > + msix_free_irq_entries(dev); > > +} > > + > > +unsigned int msix_nr_vectors_allocated(const PCIDevice *dev) > > +{ > > + return dev->msix_entries_nr; > > +} > > + > > +static int msix_set_notifier_for_vector(PCIDevice *dev, unsigned int vector) > > +{ > > + MSIMessage msg; > > + > > + if (msix_is_masked(dev, vector)) { > > + return 0; > > + } > > + msg = msix_get_message(dev, vector); > > + return dev->msix_vector_use_notifier(dev, vector, msg); > > +} > > + > > +static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector) > > +{ > > + if (msix_is_masked(dev, vector)) { > > + return; > > + } > > + dev->msix_vector_release_notifier(dev, vector); > > +} > > + > > +int msix_set_vector_notifiers(PCIDevice *dev, > > + MSIVectorUseNotifier use_notifier, > > + MSIVectorReleaseNotifier release_notifier) > > +{ > > + int vector, ret; > > + > > + assert(use_notifier && release_notifier); > > + > > + dev->msix_vector_use_notifier = use_notifier; > > + dev->msix_vector_release_notifier = release_notifier; > > + > > + if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > > + (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { > > + for (vector = 0; vector < dev->msix_entries_nr; vector++) { > > + ret = msix_set_notifier_for_vector(dev, vector); > > + if (ret < 0) { > > + goto undo; > > + } > > + } > > + } > > + return 0; > > + > > +undo: > > + while (--vector >= 0) { > > + msix_unset_notifier_for_vector(dev, vector); > > + } > > + dev->msix_vector_use_notifier = NULL; > > + dev->msix_vector_release_notifier = NULL; > > + return ret; > > +} > > + > > +void msix_unset_vector_notifiers(PCIDevice *dev) > > +{ > > + int vector; > > + > > + assert(dev->msix_vector_use_notifier && > > + dev->msix_vector_release_notifier); > > + > > + if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > > + (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { > > + for (vector = 0; vector < dev->msix_entries_nr; vector++) { > > + msix_unset_notifier_for_vector(dev, vector); > > + } > > + } > > + dev->msix_vector_use_notifier = NULL; > > + dev->msix_vector_release_notifier = NULL; > > +} > > diff --git a/hw/pci/msix.h b/hw/pci/msix.h > > new file mode 100644 > > index 0000000..15211cb > > --- /dev/null > > +++ b/hw/pci/msix.h > > @@ -0,0 +1,41 @@ > > +#ifndef QEMU_MSIX_H > > +#define QEMU_MSIX_H > > + > > +#include "qemu-common.h" > > +#include "pci.h" > > + > > +void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg); > > +int msix_init(PCIDevice *dev, unsigned short nentries, > > + MemoryRegion *table_bar, uint8_t table_bar_nr, > > + unsigned table_offset, MemoryRegion *pba_bar, > > + uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos); > > +int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, > > + uint8_t bar_nr); > > + > > +void msix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len); > > + > > +void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, > > + MemoryRegion *pba_bar); > > +void msix_uninit_exclusive_bar(PCIDevice *dev); > > + > > +unsigned int msix_nr_vectors_allocated(const PCIDevice *dev); > > + > > +void msix_save(PCIDevice *dev, QEMUFile *f); > > +void msix_load(PCIDevice *dev, QEMUFile *f); > > + > > +int msix_enabled(PCIDevice *dev); > > +int msix_present(PCIDevice *dev); > > + > > +int msix_vector_use(PCIDevice *dev, unsigned vector); > > +void msix_vector_unuse(PCIDevice *dev, unsigned vector); > > +void msix_unuse_all_vectors(PCIDevice *dev); > > + > > +void msix_notify(PCIDevice *dev, unsigned vector); > > + > > +void msix_reset(PCIDevice *dev); > > + > > +int msix_set_vector_notifiers(PCIDevice *dev, > > + MSIVectorUseNotifier use_notifier, > > + MSIVectorReleaseNotifier release_notifier); > > +void msix_unset_vector_notifiers(PCIDevice *dev); > > +#endif > > diff --git a/hw/pci/pci-hotplug.c b/hw/pci/pci-hotplug.c > > new file mode 100644 > > index 0000000..0ca5546 > > --- /dev/null > > +++ b/hw/pci/pci-hotplug.c > > @@ -0,0 +1,293 @@ > > +/* > > + * QEMU PCI hotplug support > > + * > > + * Copyright (c) 2004 Fabrice Bellard > > + * > > + * Permission is hereby granted, free of charge, to any person obtaining a copy > > + * of this software and associated documentation files (the "Software"), to deal > > + * in the Software without restriction, including without limitation the rights > > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > > + * copies of the Software, and to permit persons to whom the Software is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be included in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > > + * THE SOFTWARE. > > + */ > > + > > +#include "hw.h" > > +#include "boards.h" > > +#include "pci.h" > > +#include "net.h" > > +#include "pc.h" > > +#include "monitor.h" > > +#include "scsi.h" > > +#include "virtio-blk.h" > > +#include "qemu-config.h" > > +#include "blockdev.h" > > +#include "error.h" > > + > > +#if defined(TARGET_I386) > > +static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, > > + const char *devaddr, > > + const char *opts_str) > > +{ > > + Error *local_err = NULL; > > + QemuOpts *opts; > > + PCIBus *bus; > > + int ret, devfn; > > + > > + bus = pci_get_bus_devfn(&devfn, devaddr); > > + if (!bus) { > > + monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); > > + return NULL; > > + } > > + if (!((BusState*)bus)->allow_hotplug) { > > + monitor_printf(mon, "PCI bus doesn't support hotplug\n"); > > + return NULL; > > + } > > + > > + opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0); > > + if (!opts) { > > + return NULL; > > + } > > + > > + qemu_opt_set(opts, "type", "nic"); > > + > > + ret = net_client_init(opts, 0, &local_err); > > + if (error_is_set(&local_err)) { > > + qerror_report_err(local_err); > > + error_free(local_err); > > + return NULL; > > + } > > + if (nd_table[ret].devaddr) { > > + monitor_printf(mon, "Parameter addr not supported\n"); > > + return NULL; > > + } > > + return pci_nic_init(&nd_table[ret], "rtl8139", devaddr); > > +} > > + > > +static int scsi_hot_add(Monitor *mon, DeviceState *adapter, > > + DriveInfo *dinfo, int printinfo) > > +{ > > + SCSIBus *scsibus; > > + SCSIDevice *scsidev; > > + > > + scsibus = (SCSIBus *) > > + object_dynamic_cast(OBJECT(QLIST_FIRST(&adapter->child_bus)), > > + TYPE_SCSI_BUS); > > + if (!scsibus) { > > + error_report("Device is not a SCSI adapter"); > > + return -1; > > + } > > + > > + /* > > + * drive_init() tries to find a default for dinfo->unit. Doesn't > > + * work at all for hotplug though as we assign the device to a > > + * specific bus instead of the first bus with spare scsi ids. > > + * > > + * Ditch the calculated value and reload from option string (if > > + * specified). > > + */ > > + dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1); > > + dinfo->bus = scsibus->busnr; > > + scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, > > + false, -1); > > + if (!scsidev) { > > + return -1; > > + } > > + dinfo->unit = scsidev->id; > > + > > + if (printinfo) > > + monitor_printf(mon, "OK bus %d, unit %d\n", > > + scsibus->busnr, scsidev->id); > > + return 0; > > +} > > + > > +int pci_drive_hot_add(Monitor *mon, const QDict *qdict, > > + DriveInfo *dinfo, int type) > > +{ > > + int dom, pci_bus; > > + unsigned slot; > > + PCIDevice *dev; > > + const char *pci_addr = qdict_get_str(qdict, "pci_addr"); > > + > > + switch (type) { > > + case IF_SCSI: > > + if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) { > > + goto err; > > + } > > + dev = pci_find_device(pci_find_root_bus(dom), pci_bus, > > + PCI_DEVFN(slot, 0)); > > + if (!dev) { > > + monitor_printf(mon, "no pci device with address %s\n", pci_addr); > > + goto err; > > + } > > + if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) != 0) { > > + goto err; > > + } > > + break; > > + default: > > + monitor_printf(mon, "Can't hot-add drive to type %d\n", type); > > + goto err; > > + } > > + > > + return 0; > > +err: > > + return -1; > > +} > > + > > +static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, > > + const char *devaddr, > > + const char *opts) > > +{ > > + PCIDevice *dev; > > + DriveInfo *dinfo = NULL; > > + int type = -1; > > + char buf[128]; > > + PCIBus *bus; > > + int devfn; > > + > > + if (get_param_value(buf, sizeof(buf), "if", opts)) { > > + if (!strcmp(buf, "scsi")) > > + type = IF_SCSI; > > + else if (!strcmp(buf, "virtio")) { > > + type = IF_VIRTIO; > > + } else { > > + monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf); > > + return NULL; > > + } > > + } else { > > + monitor_printf(mon, "no if= specified\n"); > > + return NULL; > > + } > > + > > + if (get_param_value(buf, sizeof(buf), "file", opts)) { > > + dinfo = add_init_drive(opts); > > + if (!dinfo) > > + return NULL; > > + if (dinfo->devaddr) { > > + monitor_printf(mon, "Parameter addr not supported\n"); > > + return NULL; > > + } > > + } else { > > + dinfo = NULL; > > + } > > + > > + bus = pci_get_bus_devfn(&devfn, devaddr); > > + if (!bus) { > > + monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); > > + return NULL; > > + } > > + if (!((BusState*)bus)->allow_hotplug) { > > + monitor_printf(mon, "PCI bus doesn't support hotplug\n"); > > + return NULL; > > + } > > + > > + switch (type) { > > + case IF_SCSI: > > + dev = pci_create(bus, devfn, "lsi53c895a"); > > + if (qdev_init(&dev->qdev) < 0) > > + dev = NULL; > > + if (dev && dinfo) { > > + if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) { > > + qdev_unplug(&dev->qdev, NULL); > > + dev = NULL; > > + } > > + } > > + break; > > + case IF_VIRTIO: > > + if (!dinfo) { > > + monitor_printf(mon, "virtio requires a backing file/device.\n"); > > + return NULL; > > + } > > + dev = pci_create(bus, devfn, "virtio-blk-pci"); > > + if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) { > > + qdev_free(&dev->qdev); > > + dev = NULL; > > + break; > > + } > > + if (qdev_init(&dev->qdev) < 0) > > + dev = NULL; > > + break; > > + default: > > + dev = NULL; > > + } > > + return dev; > > +} > > + > > +void pci_device_hot_add(Monitor *mon, const QDict *qdict) > > +{ > > + PCIDevice *dev = NULL; > > + const char *pci_addr = qdict_get_str(qdict, "pci_addr"); > > + const char *type = qdict_get_str(qdict, "type"); > > + const char *opts = qdict_get_try_str(qdict, "opts"); > > + > > + /* strip legacy tag */ > > + if (!strncmp(pci_addr, "pci_addr=", 9)) { > > + pci_addr += 9; > > + } > > + > > + if (!opts) { > > + opts = ""; > > + } > > + > > + if (!strcmp(pci_addr, "auto")) > > + pci_addr = NULL; > > + > > + if (strcmp(type, "nic") == 0) { > > + dev = qemu_pci_hot_add_nic(mon, pci_addr, opts); > > + } else if (strcmp(type, "storage") == 0) { > > + dev = qemu_pci_hot_add_storage(mon, pci_addr, opts); > > + } else { > > + monitor_printf(mon, "invalid type: %s\n", type); > > + } > > + > > + if (dev) { > > + monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n", > > + pci_find_domain(dev->bus), > > + pci_bus_num(dev->bus), PCI_SLOT(dev->devfn), > > + PCI_FUNC(dev->devfn)); > > + } else > > + monitor_printf(mon, "failed to add %s\n", opts); > > +} > > +#endif > > + > > +static int pci_device_hot_remove(Monitor *mon, const char *pci_addr) > > +{ > > + PCIDevice *d; > > + int dom, bus; > > + unsigned slot; > > + Error *local_err = NULL; > > + > > + if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) { > > + return -1; > > + } > > + > > + d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0)); > > + if (!d) { > > + monitor_printf(mon, "slot %d empty\n", slot); > > + return -1; > > + } > > + > > + qdev_unplug(&d->qdev, &local_err); > > + if (error_is_set(&local_err)) { > > + monitor_printf(mon, "%s\n", error_get_pretty(local_err)); > > + error_free(local_err); > > + return -1; > > + } > > + > > + return 0; > > +} > > + > > +void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict) > > +{ > > + pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr")); > > +} > > diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c > > new file mode 100644 > > index 0000000..134c448 > > --- /dev/null > > +++ b/hw/pci/pci-stub.c > > @@ -0,0 +1,47 @@ > > +/* > > + * PCI stubs for platforms that don't support pci bus. > > + * > > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#include "sysemu.h" > > +#include "monitor.h" > > +#include "pci.h" > > +#include "qmp-commands.h" > > + > > +PciInfoList *qmp_query_pci(Error **errp) > > +{ > > + error_set(errp, QERR_UNSUPPORTED); > > + return NULL; > > +} > > + > > +static void pci_error_message(Monitor *mon) > > +{ > > + monitor_printf(mon, "PCI devices not supported\n"); > > +} > > + > > +int do_pcie_aer_inject_error(Monitor *mon, > > + const QDict *qdict, QObject **ret_data) > > +{ > > + pci_error_message(mon); > > + return -ENOSYS; > > +} > > + > > +void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) > > +{ > > + pci_error_message(mon); > > +} > > diff --git a/hw/pci/pci.c b/hw/pci/pci.c > > new file mode 100644 > > index 0000000..97a0cd7 > > --- /dev/null > > +++ b/hw/pci/pci.c > > @@ -0,0 +1,2168 @@ > > +/* > > + * QEMU PCI bus manager > > + * > > + * Copyright (c) 2004 Fabrice Bellard > > + * > > + * Permission is hereby granted, free of charge, to any person obtaining a copy > > + * of this software and associated documentation files (the "Software"), to deal > > + * in the Software without restriction, including without limitation the rights > > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > > + * copies of the Software, and to permit persons to whom the Software is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be included in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > > + * THE SOFTWARE. > > + */ > > +#include "hw.h" > > +#include "pci.h" > > +#include "pci_bridge.h" > > +#include "pci_internals.h" > > +#include "monitor.h" > > +#include "net.h" > > +#include "sysemu.h" > > +#include "loader.h" > > +#include "range.h" > > +#include "qmp-commands.h" > > +#include "msi.h" > > +#include "msix.h" > > +#include "exec-memory.h" > > + > > +//#define DEBUG_PCI > > +#ifdef DEBUG_PCI > > +# define PCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) > > +#else > > +# define PCI_DPRINTF(format, ...) do { } while (0) > > +#endif > > + > > +static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); > > +static char *pcibus_get_dev_path(DeviceState *dev); > > +static char *pcibus_get_fw_dev_path(DeviceState *dev); > > +static int pcibus_reset(BusState *qbus); > > + > > +static Property pci_props[] = { > > + DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), > > + DEFINE_PROP_STRING("romfile", PCIDevice, romfile), > > + DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1), > > + DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present, > > + QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false), > > + DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present, > > + QEMU_PCI_CAP_SERR_BITNR, true), > > + DEFINE_PROP_END_OF_LIST() > > +}; > > + > > +static void pci_bus_class_init(ObjectClass *klass, void *data) > > +{ > > + BusClass *k = BUS_CLASS(klass); > > + > > + k->print_dev = pcibus_dev_print; > > + k->get_dev_path = pcibus_get_dev_path; > > + k->get_fw_dev_path = pcibus_get_fw_dev_path; > > + k->reset = pcibus_reset; > > +} > > + > > +static const TypeInfo pci_bus_info = { > > + .name = TYPE_PCI_BUS, > > + .parent = TYPE_BUS, > > + .instance_size = sizeof(PCIBus), > > + .class_init = pci_bus_class_init, > > +}; > > + > > +static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); > > +static void pci_update_mappings(PCIDevice *d); > > +static void pci_set_irq(void *opaque, int irq_num, int level); > > +static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom); > > +static void pci_del_option_rom(PCIDevice *pdev); > > + > > +static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET; > > +static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU; > > + > > +struct PCIHostBus { > > + int domain; > > + struct PCIBus *bus; > > + QLIST_ENTRY(PCIHostBus) next; > > +}; > > +static QLIST_HEAD(, PCIHostBus) host_buses; > > + > > +static const VMStateDescription vmstate_pcibus = { > > + .name = "PCIBUS", > > + .version_id = 1, > > + .minimum_version_id = 1, > > + .minimum_version_id_old = 1, > > + .fields = (VMStateField []) { > > + VMSTATE_INT32_EQUAL(nirq, PCIBus), > > + VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32, int32_t), > > + VMSTATE_END_OF_LIST() > > + } > > +}; > > +static int pci_bar(PCIDevice *d, int reg) > > +{ > > + uint8_t type; > > + > > + if (reg != PCI_ROM_SLOT) > > + return PCI_BASE_ADDRESS_0 + reg * 4; > > + > > + type = d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; > > + return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; > > +} > > + > > +static inline int pci_irq_state(PCIDevice *d, int irq_num) > > +{ > > + return (d->irq_state >> irq_num) & 0x1; > > +} > > + > > +static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level) > > +{ > > + d->irq_state &= ~(0x1 << irq_num); > > + d->irq_state |= level << irq_num; > > +} > > + > > +static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) > > +{ > > + PCIBus *bus; > > + for (;;) { > > + bus = pci_dev->bus; > > + irq_num = bus->map_irq(pci_dev, irq_num); > > + if (bus->set_irq) > > + break; > > + pci_dev = bus->parent_dev; > > + } > > + bus->irq_count[irq_num] += change; > > + bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); > > +} > > + > > +int pci_bus_get_irq_level(PCIBus *bus, int irq_num) > > +{ > > + assert(irq_num >= 0); > > + assert(irq_num < bus->nirq); > > + return !!bus->irq_count[irq_num]; > > +} > > + > > +/* Update interrupt status bit in config space on interrupt > > + * state change. */ > > +static void pci_update_irq_status(PCIDevice *dev) > > +{ > > + if (dev->irq_state) { > > + dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT; > > + } else { > > + dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; > > + } > > +} > > + > > +void pci_device_deassert_intx(PCIDevice *dev) > > +{ > > + int i; > > + for (i = 0; i < PCI_NUM_PINS; ++i) { > > + qemu_set_irq(dev->irq[i], 0); > > + } > > +} > > + > > +/* > > + * This function is called on #RST and FLR. > > + * FLR if PCI_EXP_DEVCTL_BCR_FLR is set > > + */ > > +void pci_device_reset(PCIDevice *dev) > > +{ > > + int r; > > + > > + qdev_reset_all(&dev->qdev); > > + > > + dev->irq_state = 0; > > + pci_update_irq_status(dev); > > + pci_device_deassert_intx(dev); > > + /* Clear all writable bits */ > > + pci_word_test_and_clear_mask(dev->config + PCI_COMMAND, > > + pci_get_word(dev->wmask + PCI_COMMAND) | > > + pci_get_word(dev->w1cmask + PCI_COMMAND)); > > + pci_word_test_and_clear_mask(dev->config + PCI_STATUS, > > + pci_get_word(dev->wmask + PCI_STATUS) | > > + pci_get_word(dev->w1cmask + PCI_STATUS)); > > + dev->config[PCI_CACHE_LINE_SIZE] = 0x0; > > + dev->config[PCI_INTERRUPT_LINE] = 0x0; > > + for (r = 0; r < PCI_NUM_REGIONS; ++r) { > > + PCIIORegion *region = &dev->io_regions[r]; > > + if (!region->size) { > > + continue; > > + } > > + > > + if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) && > > + region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > > + pci_set_quad(dev->config + pci_bar(dev, r), region->type); > > + } else { > > + pci_set_long(dev->config + pci_bar(dev, r), region->type); > > + } > > + } > > + pci_update_mappings(dev); > > + > > + msi_reset(dev); > > + msix_reset(dev); > > +} > > + > > +/* > > + * Trigger pci bus reset under a given bus. > > + * To be called on RST# assert. > > + */ > > +void pci_bus_reset(PCIBus *bus) > > +{ > > + int i; > > + > > + for (i = 0; i < bus->nirq; i++) { > > + bus->irq_count[i] = 0; > > + } > > + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { > > + if (bus->devices[i]) { > > + pci_device_reset(bus->devices[i]); > > + } > > + } > > +} > > + > > +static int pcibus_reset(BusState *qbus) > > +{ > > + pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus)); > > + > > + /* topology traverse is done by pci_bus_reset(). > > + Tell qbus/qdev walker not to traverse the tree */ > > + return 1; > > +} > > + > > +static void pci_host_bus_register(int domain, PCIBus *bus) > > +{ > > + struct PCIHostBus *host; > > + host = g_malloc0(sizeof(*host)); > > + host->domain = domain; > > + host->bus = bus; > > + QLIST_INSERT_HEAD(&host_buses, host, next); > > +} > > + > > +PCIBus *pci_find_root_bus(int domain) > > +{ > > + struct PCIHostBus *host; > > + > > + QLIST_FOREACH(host, &host_buses, next) { > > + if (host->domain == domain) { > > + return host->bus; > > + } > > + } > > + > > + return NULL; > > +} > > + > > +int pci_find_domain(const PCIBus *bus) > > +{ > > + PCIDevice *d; > > + struct PCIHostBus *host; > > + > > + /* obtain root bus */ > > + while ((d = bus->parent_dev) != NULL) { > > + bus = d->bus; > > + } > > + > > + QLIST_FOREACH(host, &host_buses, next) { > > + if (host->bus == bus) { > > + return host->domain; > > + } > > + } > > + > > + abort(); /* should not be reached */ > > + return -1; > > +} > > + > > +void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, > > + const char *name, > > + MemoryRegion *address_space_mem, > > + MemoryRegion *address_space_io, > > + uint8_t devfn_min) > > +{ > > + qbus_create_inplace(&bus->qbus, TYPE_PCI_BUS, parent, name); > > + assert(PCI_FUNC(devfn_min) == 0); > > + bus->devfn_min = devfn_min; > > + bus->address_space_mem = address_space_mem; > > + bus->address_space_io = address_space_io; > > + > > + /* host bridge */ > > + QLIST_INIT(&bus->child); > > + pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */ > > + > > + vmstate_register(NULL, -1, &vmstate_pcibus, bus); > > +} > > + > > +PCIBus *pci_bus_new(DeviceState *parent, const char *name, > > + MemoryRegion *address_space_mem, > > + MemoryRegion *address_space_io, > > + uint8_t devfn_min) > > +{ > > + PCIBus *bus; > > + > > + bus = g_malloc0(sizeof(*bus)); > > + pci_bus_new_inplace(bus, parent, name, address_space_mem, > > + address_space_io, devfn_min); > > + OBJECT(bus)->free = g_free; > > + return bus; > > +} > > + > > +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > > + void *irq_opaque, int nirq) > > +{ > > + bus->set_irq = set_irq; > > + bus->map_irq = map_irq; > > + bus->irq_opaque = irq_opaque; > > + bus->nirq = nirq; > > + bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0])); > > +} > > + > > +void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev) > > +{ > > + bus->qbus.allow_hotplug = 1; > > + bus->hotplug = hotplug; > > + bus->hotplug_qdev = qdev; > > +} > > + > > +PCIBus *pci_register_bus(DeviceState *parent, const char *name, > > + pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > > + void *irq_opaque, > > + MemoryRegion *address_space_mem, > > + MemoryRegion *address_space_io, > > + uint8_t devfn_min, int nirq) > > +{ > > + PCIBus *bus; > > + > > + bus = pci_bus_new(parent, name, address_space_mem, > > + address_space_io, devfn_min); > > + pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq); > > + return bus; > > +} > > + > > +int pci_bus_num(PCIBus *s) > > +{ > > + if (!s->parent_dev) > > + return 0; /* pci host bridge */ > > + return s->parent_dev->config[PCI_SECONDARY_BUS]; > > +} > > + > > +static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) > > +{ > > + PCIDevice *s = container_of(pv, PCIDevice, config); > > + uint8_t *config; > > + int i; > > + > > + assert(size == pci_config_size(s)); > > + config = g_malloc(size); > > + > > + qemu_get_buffer(f, config, size); > > + for (i = 0; i < size; ++i) { > > + if ((config[i] ^ s->config[i]) & > > + s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) { > > + g_free(config); > > + return -EINVAL; > > + } > > + } > > + memcpy(s->config, config, size); > > + > > + pci_update_mappings(s); > > + > > + memory_region_set_enabled(&s->bus_master_enable_region, > > + pci_get_word(s->config + PCI_COMMAND) > > + & PCI_COMMAND_MASTER); > > + > > + g_free(config); > > + return 0; > > +} > > + > > +/* just put buffer */ > > +static void put_pci_config_device(QEMUFile *f, void *pv, size_t size) > > +{ > > + const uint8_t **v = pv; > > + assert(size == pci_config_size(container_of(pv, PCIDevice, config))); > > + qemu_put_buffer(f, *v, size); > > +} > > + > > +static VMStateInfo vmstate_info_pci_config = { > > + .name = "pci config", > > + .get = get_pci_config_device, > > + .put = put_pci_config_device, > > +}; > > + > > +static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) > > +{ > > + PCIDevice *s = container_of(pv, PCIDevice, irq_state); > > + uint32_t irq_state[PCI_NUM_PINS]; > > + int i; > > + for (i = 0; i < PCI_NUM_PINS; ++i) { > > + irq_state[i] = qemu_get_be32(f); > > + if (irq_state[i] != 0x1 && irq_state[i] != 0) { > > + fprintf(stderr, "irq state %d: must be 0 or 1.\n", > > + irq_state[i]); > > + return -EINVAL; > > + } > > + } > > + > > + for (i = 0; i < PCI_NUM_PINS; ++i) { > > + pci_set_irq_state(s, i, irq_state[i]); > > + } > > + > > + return 0; > > +} > > + > > +static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size) > > +{ > > + int i; > > + PCIDevice *s = container_of(pv, PCIDevice, irq_state); > > + > > + for (i = 0; i < PCI_NUM_PINS; ++i) { > > + qemu_put_be32(f, pci_irq_state(s, i)); > > + } > > +} > > + > > +static VMStateInfo vmstate_info_pci_irq_state = { > > + .name = "pci irq state", > > + .get = get_pci_irq_state, > > + .put = put_pci_irq_state, > > +}; > > + > > +const VMStateDescription vmstate_pci_device = { > > + .name = "PCIDevice", > > + .version_id = 2, > > + .minimum_version_id = 1, > > + .minimum_version_id_old = 1, > > + .fields = (VMStateField []) { > > + VMSTATE_INT32_LE(version_id, PCIDevice), > > + VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, > > + vmstate_info_pci_config, > > + PCI_CONFIG_SPACE_SIZE), > > + VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, > > + vmstate_info_pci_irq_state, > > + PCI_NUM_PINS * sizeof(int32_t)), > > + VMSTATE_END_OF_LIST() > > + } > > +}; > > + > > +const VMStateDescription vmstate_pcie_device = { > > + .name = "PCIEDevice", > > + .version_id = 2, > > + .minimum_version_id = 1, > > + .minimum_version_id_old = 1, > > + .fields = (VMStateField []) { > > + VMSTATE_INT32_LE(version_id, PCIDevice), > > + VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, > > + vmstate_info_pci_config, > > + PCIE_CONFIG_SPACE_SIZE), > > + VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, > > + vmstate_info_pci_irq_state, > > + PCI_NUM_PINS * sizeof(int32_t)), > > + VMSTATE_END_OF_LIST() > > + } > > +}; > > + > > +static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s) > > +{ > > + return pci_is_express(s) ? &vmstate_pcie_device : &vmstate_pci_device; > > +} > > + > > +void pci_device_save(PCIDevice *s, QEMUFile *f) > > +{ > > + /* Clear interrupt status bit: it is implicit > > + * in irq_state which we are saving. > > + * This makes us compatible with old devices > > + * which never set or clear this bit. */ > > + s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; > > + vmstate_save_state(f, pci_get_vmstate(s), s); > > + /* Restore the interrupt status bit. */ > > + pci_update_irq_status(s); > > +} > > + > > +int pci_device_load(PCIDevice *s, QEMUFile *f) > > +{ > > + int ret; > > + ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id); > > + /* Restore the interrupt status bit. */ > > + pci_update_irq_status(s); > > + return ret; > > +} > > + > > +static void pci_set_default_subsystem_id(PCIDevice *pci_dev) > > +{ > > + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, > > + pci_default_sub_vendor_id); > > + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, > > + pci_default_sub_device_id); > > +} > > + > > +/* > > + * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL > > + * [[<domain>:]<bus>:]<slot>.<func>, return -1 on error > > + */ > > +static int pci_parse_devaddr(const char *addr, int *domp, int *busp, > > + unsigned int *slotp, unsigned int *funcp) > > +{ > > + const char *p; > > + char *e; > > + unsigned long val; > > + unsigned long dom = 0, bus = 0; > > + unsigned int slot = 0; > > + unsigned int func = 0; > > + > > + p = addr; > > + val = strtoul(p, &e, 16); > > + if (e == p) > > + return -1; > > + if (*e == ':') { > > + bus = val; > > + p = e + 1; > > + val = strtoul(p, &e, 16); > > + if (e == p) > > + return -1; > > + if (*e == ':') { > > + dom = bus; > > + bus = val; > > + p = e + 1; > > + val = strtoul(p, &e, 16); > > + if (e == p) > > + return -1; > > + } > > + } > > + > > + slot = val; > > + > > + if (funcp != NULL) { > > + if (*e != '.') > > + return -1; > > + > > + p = e + 1; > > + val = strtoul(p, &e, 16); > > + if (e == p) > > + return -1; > > + > > + func = val; > > + } > > + > > + /* if funcp == NULL func is 0 */ > > + if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) > > + return -1; > > + > > + if (*e) > > + return -1; > > + > > + *domp = dom; > > + *busp = bus; > > + *slotp = slot; > > + if (funcp != NULL) > > + *funcp = func; > > + return 0; > > +} > > + > > +int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, > > + unsigned *slotp) > > +{ > > + /* strip legacy tag */ > > + if (!strncmp(addr, "pci_addr=", 9)) { > > + addr += 9; > > + } > > + if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) { > > + monitor_printf(mon, "Invalid pci address\n"); > > + return -1; > > + } > > + return 0; > > +} > > + > > +PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) > > +{ > > + int dom, bus; > > + unsigned slot; > > + > > + if (!devaddr) { > > + *devfnp = -1; > > + return pci_find_bus_nr(pci_find_root_bus(0), 0); > > + } > > + > > + if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) { > > + return NULL; > > + } > > + > > + *devfnp = PCI_DEVFN(slot, 0); > > + return pci_find_bus_nr(pci_find_root_bus(dom), bus); > > +} > > + > > +static void pci_init_cmask(PCIDevice *dev) > > +{ > > + pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff); > > + pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff); > > + dev->cmask[PCI_STATUS] = PCI_STATUS_CAP_LIST; > > + dev->cmask[PCI_REVISION_ID] = 0xff; > > + dev->cmask[PCI_CLASS_PROG] = 0xff; > > + pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff); > > + dev->cmask[PCI_HEADER_TYPE] = 0xff; > > + dev->cmask[PCI_CAPABILITY_LIST] = 0xff; > > +} > > + > > +static void pci_init_wmask(PCIDevice *dev) > > +{ > > + int config_size = pci_config_size(dev); > > + > > + dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff; > > + dev->wmask[PCI_INTERRUPT_LINE] = 0xff; > > + pci_set_word(dev->wmask + PCI_COMMAND, > > + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | > > + PCI_COMMAND_INTX_DISABLE); > > + if (dev->cap_present & QEMU_PCI_CAP_SERR) { > > + pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR); > > + } > > + > > + memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff, > > + config_size - PCI_CONFIG_HEADER_SIZE); > > +} > > + > > +static void pci_init_w1cmask(PCIDevice *dev) > > +{ > > + /* > > + * Note: It's okay to set w1cmask even for readonly bits as > > + * long as their value is hardwired to 0. > > + */ > > + pci_set_word(dev->w1cmask + PCI_STATUS, > > + PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | > > + PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | > > + PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY); > > +} > > + > > +static void pci_init_mask_bridge(PCIDevice *d) > > +{ > > + /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and > > + PCI_SEC_LETENCY_TIMER */ > > + memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4); > > + > > + /* base and limit */ > > + d->wmask[PCI_IO_BASE] = PCI_IO_RANGE_MASK & 0xff; > > + d->wmask[PCI_IO_LIMIT] = PCI_IO_RANGE_MASK & 0xff; > > + pci_set_word(d->wmask + PCI_MEMORY_BASE, > > + PCI_MEMORY_RANGE_MASK & 0xffff); > > + pci_set_word(d->wmask + PCI_MEMORY_LIMIT, > > + PCI_MEMORY_RANGE_MASK & 0xffff); > > + pci_set_word(d->wmask + PCI_PREF_MEMORY_BASE, > > + PCI_PREF_RANGE_MASK & 0xffff); > > + pci_set_word(d->wmask + PCI_PREF_MEMORY_LIMIT, > > + PCI_PREF_RANGE_MASK & 0xffff); > > + > > + /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */ > > + memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8); > > + > > + /* Supported memory and i/o types */ > > + d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_16; > > + d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_16; > > + pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE, > > + PCI_PREF_RANGE_TYPE_64); > > + pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT, > > + PCI_PREF_RANGE_TYPE_64); > > + > > +/* TODO: add this define to pci_regs.h in linux and then in qemu. */ > > +#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ > > +#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */ > > +#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */ > > +#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ > > +#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ > > + pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, > > + PCI_BRIDGE_CTL_PARITY | > > + PCI_BRIDGE_CTL_SERR | > > + PCI_BRIDGE_CTL_ISA | > > + PCI_BRIDGE_CTL_VGA | > > + PCI_BRIDGE_CTL_VGA_16BIT | > > + PCI_BRIDGE_CTL_MASTER_ABORT | > > + PCI_BRIDGE_CTL_BUS_RESET | > > + PCI_BRIDGE_CTL_FAST_BACK | > > + PCI_BRIDGE_CTL_DISCARD | > > + PCI_BRIDGE_CTL_SEC_DISCARD | > > + PCI_BRIDGE_CTL_DISCARD_SERR); > > + /* Below does not do anything as we never set this bit, put here for > > + * completeness. */ > > + pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL, > > + PCI_BRIDGE_CTL_DISCARD_STATUS); > > + d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK; > > + d->cmask[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_MASK; > > + pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE, > > + PCI_PREF_RANGE_TYPE_MASK); > > + pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_LIMIT, > > + PCI_PREF_RANGE_TYPE_MASK); > > +} > > + > > +static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev) > > +{ > > + uint8_t slot = PCI_SLOT(dev->devfn); > > + uint8_t func; > > + > > + if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { > > + dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; > > + } > > + > > + /* > > + * multifunction bit is interpreted in two ways as follows. > > + * - all functions must set the bit to 1. > > + * Example: Intel X53 > > + * - function 0 must set the bit, but the rest function (> 0) > > + * is allowed to leave the bit to 0. > > + * Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10, > > + * > > + * So OS (at least Linux) checks the bit of only function 0, > > + * and doesn't see the bit of function > 0. > > + * > > + * The below check allows both interpretation. > > + */ > > + if (PCI_FUNC(dev->devfn)) { > > + PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)]; > > + if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) { > > + /* function 0 should set multifunction bit */ > > + error_report("PCI: single function device can't be populated " > > + "in function %x.%x", slot, PCI_FUNC(dev->devfn)); > > + return -1; > > + } > > + return 0; > > + } > > + > > + if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { > > + return 0; > > + } > > + /* function 0 indicates single function, so function > 0 must be NULL */ > > + for (func = 1; func < PCI_FUNC_MAX; ++func) { > > + if (bus->devices[PCI_DEVFN(slot, func)]) { > > + error_report("PCI: %x.0 indicates single function, " > > + "but %x.%x is already populated.", > > + slot, slot, func); > > + return -1; > > + } > > + } > > + return 0; > > +} > > + > > +static void pci_config_alloc(PCIDevice *pci_dev) > > +{ > > + int config_size = pci_config_size(pci_dev); > > + > > + pci_dev->config = g_malloc0(config_size); > > + pci_dev->cmask = g_malloc0(config_size); > > + pci_dev->wmask = g_malloc0(config_size); > > + pci_dev->w1cmask = g_malloc0(config_size); > > + pci_dev->used = g_malloc0(config_size); > > +} > > + > > +static void pci_config_free(PCIDevice *pci_dev) > > +{ > > + g_free(pci_dev->config); > > + g_free(pci_dev->cmask); > > + g_free(pci_dev->wmask); > > + g_free(pci_dev->w1cmask); > > + g_free(pci_dev->used); > > +} > > + > > +/* -1 for devfn means auto assign */ > > +static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, > > + const char *name, int devfn) > > +{ > > + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > > + PCIConfigReadFunc *config_read = pc->config_read; > > + PCIConfigWriteFunc *config_write = pc->config_write; > > + > > + if (devfn < 0) { > > + for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices); > > + devfn += PCI_FUNC_MAX) { > > + if (!bus->devices[devfn]) > > + goto found; > > + } > > + error_report("PCI: no slot/function available for %s, all in use", name); > > + return NULL; > > + found: ; > > + } else if (bus->devices[devfn]) { > > + error_report("PCI: slot %d function %d not available for %s, in use by %s", > > + PCI_SLOT(devfn), PCI_FUNC(devfn), name, bus->devices[devfn]->name); > > + return NULL; > > + } > > + pci_dev->bus = bus; > > + if (bus->dma_context_fn) { > > + pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, devfn); > > + } else { > > + /* FIXME: Make dma_context_fn use MemoryRegions instead, so this path is > > + * taken unconditionally */ > > + /* FIXME: inherit memory region from bus creator */ > > + memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master", > > + get_system_memory(), 0, > > + memory_region_size(get_system_memory())); > > + memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); > > + address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region); > > + pci_dev->dma = g_new(DMAContext, 1); > > + dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL); > > + } > > + pci_dev->devfn = devfn; > > + pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); > > + pci_dev->irq_state = 0; > > + pci_config_alloc(pci_dev); > > + > > + pci_config_set_vendor_id(pci_dev->config, pc->vendor_id); > > + pci_config_set_device_id(pci_dev->config, pc->device_id); > > + pci_config_set_revision(pci_dev->config, pc->revision); > > + pci_config_set_class(pci_dev->config, pc->class_id); > > + > > + if (!pc->is_bridge) { > > + if (pc->subsystem_vendor_id || pc->subsystem_id) { > > + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, > > + pc->subsystem_vendor_id); > > + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, > > + pc->subsystem_id); > > + } else { > > + pci_set_default_subsystem_id(pci_dev); > > + } > > + } else { > > + /* subsystem_vendor_id/subsystem_id are only for header type 0 */ > > + assert(!pc->subsystem_vendor_id); > > + assert(!pc->subsystem_id); > > + } > > + pci_init_cmask(pci_dev); > > + pci_init_wmask(pci_dev); > > + pci_init_w1cmask(pci_dev); > > + if (pc->is_bridge) { > > + pci_init_mask_bridge(pci_dev); > > + } > > + if (pci_init_multifunction(bus, pci_dev)) { > > + pci_config_free(pci_dev); > > + return NULL; > > + } > > + > > + if (!config_read) > > + config_read = pci_default_read_config; > > + if (!config_write) > > + config_write = pci_default_write_config; > > + pci_dev->config_read = config_read; > > + pci_dev->config_write = config_write; > > + bus->devices[devfn] = pci_dev; > > + pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS); > > + pci_dev->version_id = 2; /* Current pci device vmstate version */ > > + return pci_dev; > > +} > > + > > +static void do_pci_unregister_device(PCIDevice *pci_dev) > > +{ > > + qemu_free_irqs(pci_dev->irq); > > + pci_dev->bus->devices[pci_dev->devfn] = NULL; > > + pci_config_free(pci_dev); > > + > > + if (!pci_dev->bus->dma_context_fn) { > > + address_space_destroy(&pci_dev->bus_master_as); > > + memory_region_destroy(&pci_dev->bus_master_enable_region); > > + g_free(pci_dev->dma); > > + pci_dev->dma = NULL; > > + } > > +} > > + > > +static void pci_unregister_io_regions(PCIDevice *pci_dev) > > +{ > > + PCIIORegion *r; > > + int i; > > + > > + for(i = 0; i < PCI_NUM_REGIONS; i++) { > > + r = &pci_dev->io_regions[i]; > > + if (!r->size || r->addr == PCI_BAR_UNMAPPED) > > + continue; > > + memory_region_del_subregion(r->address_space, r->memory); > > + } > > +} > > + > > +static int pci_unregister_device(DeviceState *dev) > > +{ > > + PCIDevice *pci_dev = PCI_DEVICE(dev); > > + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > > + > > + pci_unregister_io_regions(pci_dev); > > + pci_del_option_rom(pci_dev); > > + > > + if (pc->exit) { > > + pc->exit(pci_dev); > > + } > > + > > + do_pci_unregister_device(pci_dev); > > + return 0; > > +} > > + > > +void pci_register_bar(PCIDevice *pci_dev, int region_num, > > + uint8_t type, MemoryRegion *memory) > > +{ > > + PCIIORegion *r; > > + uint32_t addr; > > + uint64_t wmask; > > + pcibus_t size = memory_region_size(memory); > > + > > + assert(region_num >= 0); > > + assert(region_num < PCI_NUM_REGIONS); > > + if (size & (size-1)) { > > + fprintf(stderr, "ERROR: PCI region size must be pow2 " > > + "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size); > > + exit(1); > > + } > > + > > + r = &pci_dev->io_regions[region_num]; > > + r->addr = PCI_BAR_UNMAPPED; > > + r->size = size; > > + r->type = type; > > + r->memory = NULL; > > + > > + wmask = ~(size - 1); > > + addr = pci_bar(pci_dev, region_num); > > + if (region_num == PCI_ROM_SLOT) { > > + /* ROM enable bit is writable */ > > + wmask |= PCI_ROM_ADDRESS_ENABLE; > > + } > > + pci_set_long(pci_dev->config + addr, type); > > + if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) && > > + r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > > + pci_set_quad(pci_dev->wmask + addr, wmask); > > + pci_set_quad(pci_dev->cmask + addr, ~0ULL); > > + } else { > > + pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff); > > + pci_set_long(pci_dev->cmask + addr, 0xffffffff); > > + } > > + pci_dev->io_regions[region_num].memory = memory; > > + pci_dev->io_regions[region_num].address_space > > + = type & PCI_BASE_ADDRESS_SPACE_IO > > + ? pci_dev->bus->address_space_io > > + : pci_dev->bus->address_space_mem; > > +} > > + > > +pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num) > > +{ > > + return pci_dev->io_regions[region_num].addr; > > +} > > + > > +static pcibus_t pci_bar_address(PCIDevice *d, > > + int reg, uint8_t type, pcibus_t size) > > +{ > > + pcibus_t new_addr, last_addr; > > + int bar = pci_bar(d, reg); > > + uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); > > + > > + if (type & PCI_BASE_ADDRESS_SPACE_IO) { > > + if (!(cmd & PCI_COMMAND_IO)) { > > + return PCI_BAR_UNMAPPED; > > + } > > + new_addr = pci_get_long(d->config + bar) & ~(size - 1); > > + last_addr = new_addr + size - 1; > > + /* NOTE: we have only 64K ioports on PC */ > > + if (last_addr <= new_addr || new_addr == 0 || last_addr > UINT16_MAX) { > > + return PCI_BAR_UNMAPPED; > > + } > > + return new_addr; > > + } > > + > > + if (!(cmd & PCI_COMMAND_MEMORY)) { > > + return PCI_BAR_UNMAPPED; > > + } > > + if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > > + new_addr = pci_get_quad(d->config + bar); > > + } else { > > + new_addr = pci_get_long(d->config + bar); > > + } > > + /* the ROM slot has a specific enable bit */ > > + if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) { > > + return PCI_BAR_UNMAPPED; > > + } > > + new_addr &= ~(size - 1); > > + last_addr = new_addr + size - 1; > > + /* NOTE: we do not support wrapping */ > > + /* XXX: as we cannot support really dynamic > > + mappings, we handle specific values as invalid > > + mappings. */ > > + if (last_addr <= new_addr || new_addr == 0 || > > + last_addr == PCI_BAR_UNMAPPED) { > > + return PCI_BAR_UNMAPPED; > > + } > > + > > + /* Now pcibus_t is 64bit. > > + * Check if 32 bit BAR wraps around explicitly. > > + * Without this, PC ide doesn't work well. > > + * TODO: remove this work around. > > + */ > > + if (!(type & PCI_BASE_ADDRESS_MEM_TYPE_64) && last_addr >= UINT32_MAX) { > > + return PCI_BAR_UNMAPPED; > > + } > > + > > + /* > > + * OS is allowed to set BAR beyond its addressable > > + * bits. For example, 32 bit OS can set 64bit bar > > + * to >4G. Check it. TODO: we might need to support > > + * it in the future for e.g. PAE. > > + */ > > + if (last_addr >= HWADDR_MAX) { > > + return PCI_BAR_UNMAPPED; > > + } > > + > > + return new_addr; > > +} > > + > > +static void pci_update_mappings(PCIDevice *d) > > +{ > > + PCIIORegion *r; > > + int i; > > + pcibus_t new_addr; > > + > > + for(i = 0; i < PCI_NUM_REGIONS; i++) { > > + r = &d->io_regions[i]; > > + > > + /* this region isn't registered */ > > + if (!r->size) > > + continue; > > + > > + new_addr = pci_bar_address(d, i, r->type, r->size); > > + > > + /* This bar isn't changed */ > > + if (new_addr == r->addr) > > + continue; > > + > > + /* now do the real mapping */ > > + if (r->addr != PCI_BAR_UNMAPPED) { > > + memory_region_del_subregion(r->address_space, r->memory); > > + } > > + r->addr = new_addr; > > + if (r->addr != PCI_BAR_UNMAPPED) { > > + memory_region_add_subregion_overlap(r->address_space, > > + r->addr, r->memory, 1); > > + } > > + } > > +} > > + > > +static inline int pci_irq_disabled(PCIDevice *d) > > +{ > > + return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE; > > +} > > + > > +/* Called after interrupt disabled field update in config space, > > + * assert/deassert interrupts if necessary. > > + * Gets original interrupt disable bit value (before update). */ > > +static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled) > > +{ > > + int i, disabled = pci_irq_disabled(d); > > + if (disabled == was_irq_disabled) > > + return; > > + for (i = 0; i < PCI_NUM_PINS; ++i) { > > + int state = pci_irq_state(d, i); > > + pci_change_irq_level(d, i, disabled ? -state : state); > > + } > > +} > > + > > +uint32_t pci_default_read_config(PCIDevice *d, > > + uint32_t address, int len) > > +{ > > + uint32_t val = 0; > > + > > + memcpy(&val, d->config + address, len); > > + return le32_to_cpu(val); > > +} > > + > > +void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) > > +{ > > + int i, was_irq_disabled = pci_irq_disabled(d); > > + > > + for (i = 0; i < l; val >>= 8, ++i) { > > + uint8_t wmask = d->wmask[addr + i]; > > + uint8_t w1cmask = d->w1cmask[addr + i]; > > + assert(!(wmask & w1cmask)); > > + d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask); > > + d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ > > + } > > + if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) || > > + ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) || > > + ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) || > > + range_covers_byte(addr, l, PCI_COMMAND)) > > + pci_update_mappings(d); > > + > > + if (range_covers_byte(addr, l, PCI_COMMAND)) { > > + pci_update_irq_disabled(d, was_irq_disabled); > > + memory_region_set_enabled(&d->bus_master_enable_region, > > + pci_get_word(d->config + PCI_COMMAND) > > + & PCI_COMMAND_MASTER); > > + } > > + > > + msi_write_config(d, addr, val, l); > > + msix_write_config(d, addr, val, l); > > +} > > + > > +/***********************************************************/ > > +/* generic PCI irq support */ > > + > > +/* 0 <= irq_num <= 3. level must be 0 or 1 */ > > +static void pci_set_irq(void *opaque, int irq_num, int level) > > +{ > > + PCIDevice *pci_dev = opaque; > > + int change; > > + > > + change = level - pci_irq_state(pci_dev, irq_num); > > + if (!change) > > + return; > > + > > + pci_set_irq_state(pci_dev, irq_num, level); > > + pci_update_irq_status(pci_dev); > > + if (pci_irq_disabled(pci_dev)) > > + return; > > + pci_change_irq_level(pci_dev, irq_num, change); > > +} > > + > > +/* Special hooks used by device assignment */ > > +void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq) > > +{ > > + assert(!bus->parent_dev); > > + bus->route_intx_to_irq = route_intx_to_irq; > > +} > > + > > +PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) > > +{ > > + PCIBus *bus; > > + > > + do { > > + bus = dev->bus; > > + pin = bus->map_irq(dev, pin); > > + dev = bus->parent_dev; > > + } while (dev); > > + > > + if (!bus->route_intx_to_irq) { > > + error_report("PCI: Bug - unimplemented PCI INTx routing (%s)\n", > > + object_get_typename(OBJECT(bus->qbus.parent))); > > + return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 }; > > + } > > + > > + return bus->route_intx_to_irq(bus->irq_opaque, pin); > > +} > > + > > +bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new) > > +{ > > + return old->mode != new->mode || old->irq != new->irq; > > +} > > + > > +void pci_bus_fire_intx_routing_notifier(PCIBus *bus) > > +{ > > + PCIDevice *dev; > > + PCIBus *sec; > > + int i; > > + > > + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { > > + dev = bus->devices[i]; > > + if (dev && dev->intx_routing_notifier) { > > + dev->intx_routing_notifier(dev); > > + } > > + QLIST_FOREACH(sec, &bus->child, sibling) { > > + pci_bus_fire_intx_routing_notifier(sec); > > + } > > + } > > +} > > + > > +void pci_device_set_intx_routing_notifier(PCIDevice *dev, > > + PCIINTxRoutingNotifier notifier) > > +{ > > + dev->intx_routing_notifier = notifier; > > +} > > + > > +/* > > + * PCI-to-PCI bridge specification > > + * 9.1: Interrupt routing. Table 9-1 > > + * > > + * the PCI Express Base Specification, Revision 2.1 > > + * 2.2.8.1: INTx interrutp signaling - Rules > > + * the Implementation Note > > + * Table 2-20 > > + */ > > +/* > > + * 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD > > + * 0-origin unlike PCI interrupt pin register. > > + */ > > +int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) > > +{ > > + return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; > > +} > > + > > +/***********************************************************/ > > +/* monitor info on PCI */ > > + > > +typedef struct { > > + uint16_t class; > > + const char *desc; > > + const char *fw_name; > > + uint16_t fw_ign_bits; > > +} pci_class_desc; > > + > > +static const pci_class_desc pci_class_descriptions[] = > > +{ > > + { 0x0001, "VGA controller", "display"}, > > + { 0x0100, "SCSI controller", "scsi"}, > > + { 0x0101, "IDE controller", "ide"}, > > + { 0x0102, "Floppy controller", "fdc"}, > > + { 0x0103, "IPI controller", "ipi"}, > > + { 0x0104, "RAID controller", "raid"}, > > + { 0x0106, "SATA controller"}, > > + { 0x0107, "SAS controller"}, > > + { 0x0180, "Storage controller"}, > > + { 0x0200, "Ethernet controller", "ethernet"}, > > + { 0x0201, "Token Ring controller", "token-ring"}, > > + { 0x0202, "FDDI controller", "fddi"}, > > + { 0x0203, "ATM controller", "atm"}, > > + { 0x0280, "Network controller"}, > > + { 0x0300, "VGA controller", "display", 0x00ff}, > > + { 0x0301, "XGA controller"}, > > + { 0x0302, "3D controller"}, > > + { 0x0380, "Display controller"}, > > + { 0x0400, "Video controller", "video"}, > > + { 0x0401, "Audio controller", "sound"}, > > + { 0x0402, "Phone"}, > > + { 0x0403, "Audio controller", "sound"}, > > + { 0x0480, "Multimedia controller"}, > > + { 0x0500, "RAM controller", "memory"}, > > + { 0x0501, "Flash controller", "flash"}, > > + { 0x0580, "Memory controller"}, > > + { 0x0600, "Host bridge", "host"}, > > + { 0x0601, "ISA bridge", "isa"}, > > + { 0x0602, "EISA bridge", "eisa"}, > > + { 0x0603, "MC bridge", "mca"}, > > + { 0x0604, "PCI bridge", "pci"}, > > + { 0x0605, "PCMCIA bridge", "pcmcia"}, > > + { 0x0606, "NUBUS bridge", "nubus"}, > > + { 0x0607, "CARDBUS bridge", "cardbus"}, > > + { 0x0608, "RACEWAY bridge"}, > > + { 0x0680, "Bridge"}, > > + { 0x0700, "Serial port", "serial"}, > > + { 0x0701, "Parallel port", "parallel"}, > > + { 0x0800, "Interrupt controller", "interrupt-controller"}, > > + { 0x0801, "DMA controller", "dma-controller"}, > > + { 0x0802, "Timer", "timer"}, > > + { 0x0803, "RTC", "rtc"}, > > + { 0x0900, "Keyboard", "keyboard"}, > > + { 0x0901, "Pen", "pen"}, > > + { 0x0902, "Mouse", "mouse"}, > > + { 0x0A00, "Dock station", "dock", 0x00ff}, > > + { 0x0B00, "i386 cpu", "cpu", 0x00ff}, > > + { 0x0c00, "Fireware contorller", "fireware"}, > > + { 0x0c01, "Access bus controller", "access-bus"}, > > + { 0x0c02, "SSA controller", "ssa"}, > > + { 0x0c03, "USB controller", "usb"}, > > + { 0x0c04, "Fibre channel controller", "fibre-channel"}, > > + { 0x0c05, "SMBus"}, > > + { 0, NULL} > > +}; > > + > > +static void pci_for_each_device_under_bus(PCIBus *bus, > > + void (*fn)(PCIBus *b, PCIDevice *d, > > + void *opaque), > > + void *opaque) > > +{ > > + PCIDevice *d; > > + int devfn; > > + > > + for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > > + d = bus->devices[devfn]; > > + if (d) { > > + fn(bus, d, opaque); > > + } > > + } > > +} > > + > > +void pci_for_each_device(PCIBus *bus, int bus_num, > > + void (*fn)(PCIBus *b, PCIDevice *d, void *opaque), > > + void *opaque) > > +{ > > + bus = pci_find_bus_nr(bus, bus_num); > > + > > + if (bus) { > > + pci_for_each_device_under_bus(bus, fn, opaque); > > + } > > +} > > + > > +static const pci_class_desc *get_class_desc(int class) > > +{ > > + const pci_class_desc *desc; > > + > > + desc = pci_class_descriptions; > > + while (desc->desc && class != desc->class) { > > + desc++; > > + } > > + > > + return desc; > > +} > > + > > +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num); > > + > > +static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev) > > +{ > > + PciMemoryRegionList *head = NULL, *cur_item = NULL; > > + int i; > > + > > + for (i = 0; i < PCI_NUM_REGIONS; i++) { > > + const PCIIORegion *r = &dev->io_regions[i]; > > + PciMemoryRegionList *region; > > + > > + if (!r->size) { > > + continue; > > + } > > + > > + region = g_malloc0(sizeof(*region)); > > + region->value = g_malloc0(sizeof(*region->value)); > > + > > + if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { > > + region->value->type = g_strdup("io"); > > + } else { > > + region->value->type = g_strdup("memory"); > > + region->value->has_prefetch = true; > > + region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH); > > + region->value->has_mem_type_64 = true; > > + region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64); > > + } > > + > > + region->value->bar = i; > > + region->value->address = r->addr; > > + region->value->size = r->size; > > + > > + /* XXX: waiting for the qapi to support GSList */ > > + if (!cur_item) { > > + head = cur_item = region; > > + } else { > > + cur_item->next = region; > > + cur_item = region; > > + } > > + } > > + > > + return head; > > +} > > + > > +static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus, > > + int bus_num) > > +{ > > + PciBridgeInfo *info; > > + > > + info = g_malloc0(sizeof(*info)); > > + > > + info->bus.number = dev->config[PCI_PRIMARY_BUS]; > > + info->bus.secondary = dev->config[PCI_SECONDARY_BUS]; > > + info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS]; > > + > > + info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range)); > > + info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); > > + info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO); > > + > > + info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range)); > > + info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > > + info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > > + > > + info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range)); > > + info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > > + info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > > + > > + if (dev->config[PCI_SECONDARY_BUS] != 0) { > > + PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]); > > + if (child_bus) { > > + info->has_devices = true; > > + info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]); > > + } > > + } > > + > > + return info; > > +} > > + > > +static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, > > + int bus_num) > > +{ > > + const pci_class_desc *desc; > > + PciDeviceInfo *info; > > + uint8_t type; > > + int class; > > + > > + info = g_malloc0(sizeof(*info)); > > + info->bus = bus_num; > > + info->slot = PCI_SLOT(dev->devfn); > > + info->function = PCI_FUNC(dev->devfn); > > + > > + class = pci_get_word(dev->config + PCI_CLASS_DEVICE); > > + info->class_info.class = class; > > + desc = get_class_desc(class); > > + if (desc->desc) { > > + info->class_info.has_desc = true; > > + info->class_info.desc = g_strdup(desc->desc); > > + } > > + > > + info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID); > > + info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID); > > + info->regions = qmp_query_pci_regions(dev); > > + info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : ""); > > + > > + if (dev->config[PCI_INTERRUPT_PIN] != 0) { > > + info->has_irq = true; > > + info->irq = dev->config[PCI_INTERRUPT_LINE]; > > + } > > + > > + type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; > > + if (type == PCI_HEADER_TYPE_BRIDGE) { > > + info->has_pci_bridge = true; > > + info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num); > > + } > > + > > + return info; > > +} > > + > > +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num) > > +{ > > + PciDeviceInfoList *info, *head = NULL, *cur_item = NULL; > > + PCIDevice *dev; > > + int devfn; > > + > > + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > > + dev = bus->devices[devfn]; > > + if (dev) { > > + info = g_malloc0(sizeof(*info)); > > + info->value = qmp_query_pci_device(dev, bus, bus_num); > > + > > + /* XXX: waiting for the qapi to support GSList */ > > + if (!cur_item) { > > + head = cur_item = info; > > + } else { > > + cur_item->next = info; > > + cur_item = info; > > + } > > + } > > + } > > + > > + return head; > > +} > > + > > +static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) > > +{ > > + PciInfo *info = NULL; > > + > > + bus = pci_find_bus_nr(bus, bus_num); > > + if (bus) { > > + info = g_malloc0(sizeof(*info)); > > + info->bus = bus_num; > > + info->devices = qmp_query_pci_devices(bus, bus_num); > > + } > > + > > + return info; > > +} > > + > > +PciInfoList *qmp_query_pci(Error **errp) > > +{ > > + PciInfoList *info, *head = NULL, *cur_item = NULL; > > + struct PCIHostBus *host; > > + > > + QLIST_FOREACH(host, &host_buses, next) { > > + info = g_malloc0(sizeof(*info)); > > + info->value = qmp_query_pci_bus(host->bus, 0); > > + > > + /* XXX: waiting for the qapi to support GSList */ > > + if (!cur_item) { > > + head = cur_item = info; > > + } else { > > + cur_item->next = info; > > + cur_item = info; > > + } > > + } > > + > > + return head; > > +} > > + > > +static const char * const pci_nic_models[] = { > > + "ne2k_pci", > > + "i82551", > > + "i82557b", > > + "i82559er", > > + "rtl8139", > > + "e1000", > > + "pcnet", > > + "virtio", > > + NULL > > +}; > > + > > +static const char * const pci_nic_names[] = { > > + "ne2k_pci", > > + "i82551", > > + "i82557b", > > + "i82559er", > > + "rtl8139", > > + "e1000", > > + "pcnet", > > + "virtio-net-pci", > > + NULL > > +}; > > + > > +/* Initialize a PCI NIC. */ > > +/* FIXME callers should check for failure, but don't */ > > +PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, > > + const char *default_devaddr) > > +{ > > + const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr; > > + PCIBus *bus; > > + int devfn; > > + PCIDevice *pci_dev; > > + DeviceState *dev; > > + int i; > > + > > + i = qemu_find_nic_model(nd, pci_nic_models, default_model); > > + if (i < 0) > > + return NULL; > > + > > + bus = pci_get_bus_devfn(&devfn, devaddr); > > + if (!bus) { > > + error_report("Invalid PCI device address %s for device %s", > > + devaddr, pci_nic_names[i]); > > + return NULL; > > + } > > + > > + pci_dev = pci_create(bus, devfn, pci_nic_names[i]); > > + dev = &pci_dev->qdev; > > + qdev_set_nic_properties(dev, nd); > > + if (qdev_init(dev) < 0) > > + return NULL; > > + return pci_dev; > > +} > > + > > +PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, > > + const char *default_devaddr) > > +{ > > + PCIDevice *res; > > + > > + if (qemu_show_nic_models(nd->model, pci_nic_models)) > > + exit(0); > > + > > + res = pci_nic_init(nd, default_model, default_devaddr); > > + if (!res) > > + exit(1); > > + return res; > > +} > > + > > +PCIDevice *pci_vga_init(PCIBus *bus) > > +{ > > + switch (vga_interface_type) { > > + case VGA_CIRRUS: > > + return pci_create_simple(bus, -1, "cirrus-vga"); > > + case VGA_QXL: > > + return pci_create_simple(bus, -1, "qxl-vga"); > > + case VGA_STD: > > + return pci_create_simple(bus, -1, "VGA"); > > + case VGA_VMWARE: > > + return pci_create_simple(bus, -1, "vmware-svga"); > > + case VGA_NONE: > > + default: /* Other non-PCI types. Checking for unsupported types is already > > + done in vl.c. */ > > + return NULL; > > + } > > +} > > + > > +/* Whether a given bus number is in range of the secondary > > + * bus of the given bridge device. */ > > +static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) > > +{ > > + return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) & > > + PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ && > > + dev->config[PCI_SECONDARY_BUS] < bus_num && > > + bus_num <= dev->config[PCI_SUBORDINATE_BUS]; > > +} > > + > > +static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) > > +{ > > + PCIBus *sec; > > + > > + if (!bus) { > > + return NULL; > > + } > > + > > + if (pci_bus_num(bus) == bus_num) { > > + return bus; > > + } > > + > > + /* Consider all bus numbers in range for the host pci bridge. */ > > + if (bus->parent_dev && > > + !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) { > > + return NULL; > > + } > > + > > + /* try child bus */ > > + for (; bus; bus = sec) { > > + QLIST_FOREACH(sec, &bus->child, sibling) { > > + assert(sec->parent_dev); > > + if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) { > > + return sec; > > + } > > + if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) { > > + break; > > + } > > + } > > + } > > + > > + return NULL; > > +} > > + > > +PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn) > > +{ > > + bus = pci_find_bus_nr(bus, bus_num); > > + > > + if (!bus) > > + return NULL; > > + > > + return bus->devices[devfn]; > > +} > > + > > +static int pci_qdev_init(DeviceState *qdev) > > +{ > > + PCIDevice *pci_dev = (PCIDevice *)qdev; > > + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); > > + PCIBus *bus; > > + int rc; > > + bool is_default_rom; > > + > > + /* initialize cap_present for pci_is_express() and pci_config_size() */ > > + if (pc->is_express) { > > + pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; > > + } > > + > > + bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); > > + pci_dev = do_pci_register_device(pci_dev, bus, > > + object_get_typename(OBJECT(qdev)), > > + pci_dev->devfn); > > + if (pci_dev == NULL) > > + return -1; > > + if (qdev->hotplugged && pc->no_hotplug) { > > + qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev))); > > + do_pci_unregister_device(pci_dev); > > + return -1; > > + } > > + if (pc->init) { > > + rc = pc->init(pci_dev); > > + if (rc != 0) { > > + do_pci_unregister_device(pci_dev); > > + return rc; > > + } > > + } > > + > > + /* rom loading */ > > + is_default_rom = false; > > + if (pci_dev->romfile == NULL && pc->romfile != NULL) { > > + pci_dev->romfile = g_strdup(pc->romfile); > > + is_default_rom = true; > > + } > > + pci_add_option_rom(pci_dev, is_default_rom); > > + > > + if (bus->hotplug) { > > + /* Let buses differentiate between hotplug and when device is > > + * enabled during qemu machine creation. */ > > + rc = bus->hotplug(bus->hotplug_qdev, pci_dev, > > + qdev->hotplugged ? PCI_HOTPLUG_ENABLED: > > + PCI_COLDPLUG_ENABLED); > > + if (rc != 0) { > > + int r = pci_unregister_device(&pci_dev->qdev); > > + assert(!r); > > + return rc; > > + } > > + } > > + return 0; > > +} > > + > > +static int pci_unplug_device(DeviceState *qdev) > > +{ > > + PCIDevice *dev = PCI_DEVICE(qdev); > > + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); > > + > > + if (pc->no_hotplug) { > > + qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev))); > > + return -1; > > + } > > + return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, > > + PCI_HOTPLUG_DISABLED); > > +} > > + > > +PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, > > + const char *name) > > +{ > > + DeviceState *dev; > > + > > + dev = qdev_create(&bus->qbus, name); > > + qdev_prop_set_int32(dev, "addr", devfn); > > + qdev_prop_set_bit(dev, "multifunction", multifunction); > > + return PCI_DEVICE(dev); > > +} > > + > > +PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, > > + bool multifunction, > > + const char *name) > > +{ > > + PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction, name); > > + qdev_init_nofail(&dev->qdev); > > + return dev; > > +} > > + > > +PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name) > > +{ > > + return pci_create_multifunction(bus, devfn, false, name); > > +} > > + > > +PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) > > +{ > > + return pci_create_simple_multifunction(bus, devfn, false, name); > > +} > > + > > +static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size) > > +{ > > + int offset = PCI_CONFIG_HEADER_SIZE; > > + int i; > > + for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) { > > + if (pdev->used[i]) > > + offset = i + 1; > > + else if (i - offset + 1 == size) > > + return offset; > > + } > > + return 0; > > +} > > + > > +static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id, > > + uint8_t *prev_p) > > +{ > > + uint8_t next, prev; > > + > > + if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST)) > > + return 0; > > + > > + for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); > > + prev = next + PCI_CAP_LIST_NEXT) > > + if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id) > > + break; > > + > > + if (prev_p) > > + *prev_p = prev; > > + return next; > > +} > > + > > +static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset) > > +{ > > + uint8_t next, prev, found = 0; > > + > > + if (!(pdev->used[offset])) { > > + return 0; > > + } > > + > > + assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST); > > + > > + for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); > > + prev = next + PCI_CAP_LIST_NEXT) { > > + if (next <= offset && next > found) { > > + found = next; > > + } > > + } > > + return found; > > +} > > + > > +/* Patch the PCI vendor and device ids in a PCI rom image if necessary. > > + This is needed for an option rom which is used for more than one device. */ > > +static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size) > > +{ > > + uint16_t vendor_id; > > + uint16_t device_id; > > + uint16_t rom_vendor_id; > > + uint16_t rom_device_id; > > + uint16_t rom_magic; > > + uint16_t pcir_offset; > > + uint8_t checksum; > > + > > + /* Words in rom data are little endian (like in PCI configuration), > > + so they can be read / written with pci_get_word / pci_set_word. */ > > + > > + /* Only a valid rom will be patched. */ > > + rom_magic = pci_get_word(ptr); > > + if (rom_magic != 0xaa55) { > > + PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic); > > + return; > > + } > > + pcir_offset = pci_get_word(ptr + 0x18); > > + if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) { > > + PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset); > > + return; > > + } > > + > > + vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); > > + device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); > > + rom_vendor_id = pci_get_word(ptr + pcir_offset + 4); > > + rom_device_id = pci_get_word(ptr + pcir_offset + 6); > > + > > + PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile, > > + vendor_id, device_id, rom_vendor_id, rom_device_id); > > + > > + checksum = ptr[6]; > > + > > + if (vendor_id != rom_vendor_id) { > > + /* Patch vendor id and checksum (at offset 6 for etherboot roms). */ > > + checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8); > > + checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8); > > + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > > + ptr[6] = checksum; > > + pci_set_word(ptr + pcir_offset + 4, vendor_id); > > + } > > + > > + if (device_id != rom_device_id) { > > + /* Patch device id and checksum (at offset 6 for etherboot roms). */ > > + checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8); > > + checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8); > > + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > > + ptr[6] = checksum; > > + pci_set_word(ptr + pcir_offset + 6, device_id); > > + } > > +} > > + > > +/* Add an option rom for the device */ > > +static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) > > +{ > > + int size; > > + char *path; > > + void *ptr; > > + char name[32]; > > + const VMStateDescription *vmsd; > > + > > + if (!pdev->romfile) > > + return 0; > > + if (strlen(pdev->romfile) == 0) > > + return 0; > > + > > + if (!pdev->rom_bar) { > > + /* > > + * Load rom via fw_cfg instead of creating a rom bar, > > + * for 0.11 compatibility. > > + */ > > + int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE); > > + if (class == 0x0300) { > > + rom_add_vga(pdev->romfile); > > + } else { > > + rom_add_option(pdev->romfile, -1); > > + } > > + return 0; > > + } > > + > > + path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); > > + if (path == NULL) { > > + path = g_strdup(pdev->romfile); > > + } > > + > > + size = get_image_size(path); > > + if (size < 0) { > > + error_report("%s: failed to find romfile \"%s\"", > > + __FUNCTION__, pdev->romfile); > > + g_free(path); > > + return -1; > > + } > > + if (size & (size - 1)) { > > + size = 1 << qemu_fls(size); > > + } > > + > > + vmsd = qdev_get_vmsd(DEVICE(pdev)); > > + > > + if (vmsd) { > > + snprintf(name, sizeof(name), "%s.rom", vmsd->name); > > + } else { > > + snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev))); > > + } > > + pdev->has_rom = true; > > + memory_region_init_ram(&pdev->rom, name, size); > > + vmstate_register_ram(&pdev->rom, &pdev->qdev); > > + ptr = memory_region_get_ram_ptr(&pdev->rom); > > + load_image(path, ptr); > > + g_free(path); > > + > > + if (is_default_rom) { > > + /* Only the default rom images will be patched (if needed). */ > > + pci_patch_ids(pdev, ptr, size); > > + } > > + > > + qemu_put_ram_ptr(ptr); > > + > > + pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom); > > + > > + return 0; > > +} > > + > > +static void pci_del_option_rom(PCIDevice *pdev) > > +{ > > + if (!pdev->has_rom) > > + return; > > + > > + vmstate_unregister_ram(&pdev->rom, &pdev->qdev); > > + memory_region_destroy(&pdev->rom); > > + pdev->has_rom = false; > > +} > > + > > +/* > > + * if !offset > > + * Reserve space and add capability to the linked list in pci config space > > + * > > + * if offset = 0, > > + * Find and reserve space and add capability to the linked list > > + * in pci config space */ > > +int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, > > + uint8_t offset, uint8_t size) > > +{ > > + uint8_t *config; > > + int i, overlapping_cap; > > + > > + if (!offset) { > > + offset = pci_find_space(pdev, size); > > + if (!offset) { > > + return -ENOSPC; > > + } > > + } else { > > + /* Verify that capabilities don't overlap. Note: device assignment > > + * depends on this check to verify that the device is not broken. > > + * Should never trigger for emulated devices, but it's helpful > > + * for debugging these. */ > > + for (i = offset; i < offset + size; i++) { > > + overlapping_cap = pci_find_capability_at_offset(pdev, i); > > + if (overlapping_cap) { > > + fprintf(stderr, "ERROR: %04x:%02x:%02x.%x " > > + "Attempt to add PCI capability %x at offset " > > + "%x overlaps existing capability %x at offset %x\n", > > + pci_find_domain(pdev->bus), pci_bus_num(pdev->bus), > > + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), > > + cap_id, offset, overlapping_cap, i); > > + return -EINVAL; > > + } > > + } > > + } > > + > > + config = pdev->config + offset; > > + config[PCI_CAP_LIST_ID] = cap_id; > > + config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST]; > > + pdev->config[PCI_CAPABILITY_LIST] = offset; > > + pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST; > > + memset(pdev->used + offset, 0xFF, QEMU_ALIGN_UP(size, 4)); > > + /* Make capability read-only by default */ > > + memset(pdev->wmask + offset, 0, size); > > + /* Check capability by default */ > > + memset(pdev->cmask + offset, 0xFF, size); > > + return offset; > > +} > > + > > +/* Unlink capability from the pci config space. */ > > +void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) > > +{ > > + uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev); > > + if (!offset) > > + return; > > + pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT]; > > + /* Make capability writable again */ > > + memset(pdev->wmask + offset, 0xff, size); > > + memset(pdev->w1cmask + offset, 0, size); > > + /* Clear cmask as device-specific registers can't be checked */ > > + memset(pdev->cmask + offset, 0, size); > > + memset(pdev->used + offset, 0, QEMU_ALIGN_UP(size, 4)); > > + > > + if (!pdev->config[PCI_CAPABILITY_LIST]) > > + pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST; > > +} > > + > > +uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id) > > +{ > > + return pci_find_capability_list(pdev, cap_id, NULL); > > +} > > + > > +static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) > > +{ > > + PCIDevice *d = (PCIDevice *)dev; > > + const pci_class_desc *desc; > > + char ctxt[64]; > > + PCIIORegion *r; > > + int i, class; > > + > > + class = pci_get_word(d->config + PCI_CLASS_DEVICE); > > + desc = pci_class_descriptions; > > + while (desc->desc && class != desc->class) > > + desc++; > > + if (desc->desc) { > > + snprintf(ctxt, sizeof(ctxt), "%s", desc->desc); > > + } else { > > + snprintf(ctxt, sizeof(ctxt), "Class %04x", class); > > + } > > + > > + monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " > > + "pci id %04x:%04x (sub %04x:%04x)\n", > > + indent, "", ctxt, pci_bus_num(d->bus), > > + PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), > > + pci_get_word(d->config + PCI_VENDOR_ID), > > + pci_get_word(d->config + PCI_DEVICE_ID), > > + pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID), > > + pci_get_word(d->config + PCI_SUBSYSTEM_ID)); > > + for (i = 0; i < PCI_NUM_REGIONS; i++) { > > + r = &d->io_regions[i]; > > + if (!r->size) > > + continue; > > + monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS > > + " [0x%"FMT_PCIBUS"]\n", > > + indent, "", > > + i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem", > > + r->addr, r->addr + r->size - 1); > > + } > > +} > > + > > +static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len) > > +{ > > + PCIDevice *d = (PCIDevice *)dev; > > + const char *name = NULL; > > + const pci_class_desc *desc = pci_class_descriptions; > > + int class = pci_get_word(d->config + PCI_CLASS_DEVICE); > > + > > + while (desc->desc && > > + (class & ~desc->fw_ign_bits) != > > + (desc->class & ~desc->fw_ign_bits)) { > > + desc++; > > + } > > + > > + if (desc->desc) { > > + name = desc->fw_name; > > + } > > + > > + if (name) { > > + pstrcpy(buf, len, name); > > + } else { > > + snprintf(buf, len, "pci%04x,%04x", > > + pci_get_word(d->config + PCI_VENDOR_ID), > > + pci_get_word(d->config + PCI_DEVICE_ID)); > > + } > > + > > + return buf; > > +} > > + > > +static char *pcibus_get_fw_dev_path(DeviceState *dev) > > +{ > > + PCIDevice *d = (PCIDevice *)dev; > > + char path[50], name[33]; > > + int off; > > + > > + off = snprintf(path, sizeof(path), "%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 = container_of(dev, PCIDevice, qdev); > > + PCIDevice *t; > > + int slot_depth; > > + /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function. > > + * 00 is added here to make this format compatible with > > + * domain:Bus:Slot.Func for systems without nested PCI bridges. > > + * Slot.Function list specifies the slot and function numbers for all > > + * devices on the path from root to the specific device. */ > > + char domain[] = "DDDD:00"; > > + char slot[] = ":SS.F"; > > + int domain_len = sizeof domain - 1 /* For '\0' */; > > + int slot_len = sizeof slot - 1 /* For '\0' */; > > + int path_len; > > + char *path, *p; > > + int s; > > + > > + /* Calculate # of slots on path between device and root. */; > > + slot_depth = 0; > > + for (t = d; t; t = t->bus->parent_dev) { > > + ++slot_depth; > > + } > > + > > + path_len = domain_len + slot_len * slot_depth; > > + > > + /* Allocate memory, fill in the terminating null byte. */ > > + path = g_malloc(path_len + 1 /* For '\0' */); > > + path[path_len] = '\0'; > > + > > + /* First field is the domain. */ > > + s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus)); > > + assert(s == domain_len); > > + memcpy(path, domain, domain_len); > > + > > + /* Fill in slot numbers. We walk up from device to root, so need to print > > + * them in the reverse order, last to first. */ > > + p = path + path_len; > > + for (t = d; t; t = t->bus->parent_dev) { > > + p -= slot_len; > > + s = snprintf(slot, sizeof slot, ":%02x.%x", > > + PCI_SLOT(t->devfn), PCI_FUNC(t->devfn)); > > + assert(s == slot_len); > > + memcpy(p, slot, slot_len); > > + } > > + > > + return path; > > +} > > + > > +static int pci_qdev_find_recursive(PCIBus *bus, > > + const char *id, PCIDevice **pdev) > > +{ > > + DeviceState *qdev = qdev_find_recursive(&bus->qbus, id); > > + if (!qdev) { > > + return -ENODEV; > > + } > > + > > + /* roughly check if given qdev is pci device */ > > + if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) { > > + *pdev = PCI_DEVICE(qdev); > > + return 0; > > + } > > + return -EINVAL; > > +} > > + > > +int pci_qdev_find_device(const char *id, PCIDevice **pdev) > > +{ > > + struct PCIHostBus *host; > > + int rc = -ENODEV; > > + > > + QLIST_FOREACH(host, &host_buses, next) { > > + int tmp = pci_qdev_find_recursive(host->bus, id, pdev); > > + if (!tmp) { > > + rc = 0; > > + break; > > + } > > + if (tmp != -ENODEV) { > > + rc = tmp; > > + } > > + } > > + > > + return rc; > > +} > > + > > +MemoryRegion *pci_address_space(PCIDevice *dev) > > +{ > > + return dev->bus->address_space_mem; > > +} > > + > > +MemoryRegion *pci_address_space_io(PCIDevice *dev) > > +{ > > + return dev->bus->address_space_io; > > +} > > + > > +static void pci_device_class_init(ObjectClass *klass, void *data) > > +{ > > + DeviceClass *k = DEVICE_CLASS(klass); > > + k->init = pci_qdev_init; > > + k->unplug = pci_unplug_device; > > + k->exit = pci_unregister_device; > > + k->bus_type = TYPE_PCI_BUS; > > + k->props = pci_props; > > +} > > + > > +void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque) > > +{ > > + bus->dma_context_fn = fn; > > + bus->dma_context_opaque = opaque; > > +} > > + > > +static TypeInfo pci_device_type_info = { > > + .name = TYPE_PCI_DEVICE, > > + .parent = TYPE_DEVICE, > > + .instance_size = sizeof(PCIDevice), > > + .abstract = true, > > + .class_size = sizeof(PCIDeviceClass), > > + .class_init = pci_device_class_init, > > +}; > > + > > +static void pci_register_types(void) > > +{ > > + type_register_static(&pci_bus_info); > > + type_register_static(&pci_device_type_info); > > +} > > + > > +type_init(pci_register_types) > > diff --git a/hw/pci/pci.h b/hw/pci/pci.h > > new file mode 100644 > > index 0000000..4da0c2a > > --- /dev/null > > +++ b/hw/pci/pci.h > > @@ -0,0 +1,684 @@ > > +#ifndef QEMU_PCI_H > > +#define QEMU_PCI_H > > + > > +#include "qemu-common.h" > > + > > +#include "qdev.h" > > +#include "memory.h" > > +#include "dma.h" > > + > > +/* PCI includes legacy ISA access. */ > > +#include "isa.h" > > + > > +#include "pcie.h" > > + > > +/* PCI bus */ > > + > > +#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) > > +#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) > > +#define PCI_FUNC(devfn) ((devfn) & 0x07) > > +#define PCI_SLOT_MAX 32 > > +#define PCI_FUNC_MAX 8 > > + > > +/* Class, Vendor and Device IDs from Linux's pci_ids.h */ > > +#include "pci_ids.h" > > + > > +/* QEMU-specific Vendor and Device ID definitions */ > > + > > +/* IBM (0x1014) */ > > +#define PCI_DEVICE_ID_IBM_440GX 0x027f > > +#define PCI_DEVICE_ID_IBM_OPENPIC2 0xffff > > + > > +/* Hitachi (0x1054) */ > > +#define PCI_VENDOR_ID_HITACHI 0x1054 > > +#define PCI_DEVICE_ID_HITACHI_SH7751R 0x350e > > + > > +/* Apple (0x106b) */ > > +#define PCI_DEVICE_ID_APPLE_343S1201 0x0010 > > +#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI 0x001e > > +#define PCI_DEVICE_ID_APPLE_UNI_N_PCI 0x001f > > +#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL 0x0022 > > +#define PCI_DEVICE_ID_APPLE_IPID_USB 0x003f > > + > > +/* Realtek (0x10ec) */ > > +#define PCI_DEVICE_ID_REALTEK_8029 0x8029 > > + > > +/* Xilinx (0x10ee) */ > > +#define PCI_DEVICE_ID_XILINX_XC2VP30 0x0300 > > + > > +/* Marvell (0x11ab) */ > > +#define PCI_DEVICE_ID_MARVELL_GT6412X 0x4620 > > + > > +/* QEMU/Bochs VGA (0x1234) */ > > +#define PCI_VENDOR_ID_QEMU 0x1234 > > +#define PCI_DEVICE_ID_QEMU_VGA 0x1111 > > + > > +/* VMWare (0x15ad) */ > > +#define PCI_VENDOR_ID_VMWARE 0x15ad > > +#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 > > +#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 > > +#define PCI_DEVICE_ID_VMWARE_NET 0x0720 > > +#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 > > +#define PCI_DEVICE_ID_VMWARE_IDE 0x1729 > > + > > +/* Intel (0x8086) */ > > +#define PCI_DEVICE_ID_INTEL_82551IT 0x1209 > > +#define PCI_DEVICE_ID_INTEL_82557 0x1229 > > +#define PCI_DEVICE_ID_INTEL_82801IR 0x2922 > > + > > +/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */ > > +#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 > > +#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4 > > +#define PCI_SUBDEVICE_ID_QEMU 0x1100 > > + > > +#define PCI_DEVICE_ID_VIRTIO_NET 0x1000 > > +#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 > > +#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 > > +#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 > > +#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 > > +#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 > > + > > +#define FMT_PCIBUS PRIx64 > > + > > +typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, > > + uint32_t address, uint32_t data, int len); > > +typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, > > + uint32_t address, int len); > > +typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, > > + pcibus_t addr, pcibus_t size, int type); > > +typedef void PCIUnregisterFunc(PCIDevice *pci_dev); > > + > > +typedef struct PCIIORegion { > > + pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ > > +#define PCI_BAR_UNMAPPED (~(pcibus_t)0) > > + pcibus_t size; > > + uint8_t type; > > + MemoryRegion *memory; > > + MemoryRegion *address_space; > > +} PCIIORegion; > > + > > +#define PCI_ROM_SLOT 6 > > +#define PCI_NUM_REGIONS 7 > > + > > +#include "pci_regs.h" > > + > > +/* PCI HEADER_TYPE */ > > +#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 > > + > > +/* Size of the standard PCI config header */ > > +#define PCI_CONFIG_HEADER_SIZE 0x40 > > +/* Size of the standard PCI config space */ > > +#define PCI_CONFIG_SPACE_SIZE 0x100 > > +/* Size of the standart PCIe config space: 4KB */ > > +#define PCIE_CONFIG_SPACE_SIZE 0x1000 > > + > > +#define PCI_NUM_PINS 4 /* A-D */ > > + > > +/* Bits in cap_present field. */ > > +enum { > > + QEMU_PCI_CAP_MSI = 0x1, > > + QEMU_PCI_CAP_MSIX = 0x2, > > + QEMU_PCI_CAP_EXPRESS = 0x4, > > + > > + /* multifunction capable device */ > > +#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3 > > + QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR), > > + > > + /* command register SERR bit enabled */ > > +#define QEMU_PCI_CAP_SERR_BITNR 4 > > + QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR), > > + /* Standard hot plug controller. */ > > +#define QEMU_PCI_SHPC_BITNR 5 > > + QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR), > > +#define QEMU_PCI_SLOTID_BITNR 6 > > + QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_BITNR), > > +}; > > + > > +#define TYPE_PCI_DEVICE "pci-device" > > +#define PCI_DEVICE(obj) \ > > + OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE) > > +#define PCI_DEVICE_CLASS(klass) \ > > + OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE) > > +#define PCI_DEVICE_GET_CLASS(obj) \ > > + OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE) > > + > > +typedef struct PCIINTxRoute { > > + enum { > > + PCI_INTX_ENABLED, > > + PCI_INTX_INVERTED, > > + PCI_INTX_DISABLED, > > + } mode; > > + int irq; > > +} PCIINTxRoute; > > + > > +typedef struct PCIDeviceClass { > > + DeviceClass parent_class; > > + > > + int (*init)(PCIDevice *dev); > > + PCIUnregisterFunc *exit; > > + PCIConfigReadFunc *config_read; > > + PCIConfigWriteFunc *config_write; > > + > > + uint16_t vendor_id; > > + uint16_t device_id; > > + uint8_t revision; > > + uint16_t class_id; > > + uint16_t subsystem_vendor_id; /* only for header type = 0 */ > > + uint16_t subsystem_id; /* only for header type = 0 */ > > + > > + /* > > + * pci-to-pci bridge or normal device. > > + * This doesn't mean pci host switch. > > + * When card bus bridge is supported, this would be enhanced. > > + */ > > + int is_bridge; > > + > > + /* pcie stuff */ > > + int is_express; /* is this device pci express? */ > > + > > + /* device isn't hot-pluggable */ > > + int no_hotplug; > > + > > + /* rom bar */ > > + const char *romfile; > > +} PCIDeviceClass; > > + > > +typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev); > > +typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector, > > + MSIMessage msg); > > +typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector); > > + > > +struct PCIDevice { > > + DeviceState qdev; > > + > > + /* PCI config space */ > > + uint8_t *config; > > + > > + /* Used to enable config checks on load. Note that writable bits are > > + * never checked even if set in cmask. */ > > + uint8_t *cmask; > > + > > + /* Used to implement R/W bytes */ > > + uint8_t *wmask; > > + > > + /* Used to implement RW1C(Write 1 to Clear) bytes */ > > + uint8_t *w1cmask; > > + > > + /* Used to allocate config space for capabilities. */ > > + uint8_t *used; > > + > > + /* the following fields are read only */ > > + PCIBus *bus; > > + int32_t devfn; > > + char name[64]; > > + PCIIORegion io_regions[PCI_NUM_REGIONS]; > > + AddressSpace bus_master_as; > > + MemoryRegion bus_master_enable_region; > > + DMAContext *dma; > > + > > + /* do not access the following fields */ > > + PCIConfigReadFunc *config_read; > > + PCIConfigWriteFunc *config_write; > > + > > + /* IRQ objects for the INTA-INTD pins. */ > > + qemu_irq *irq; > > + > > + /* Current IRQ levels. Used internally by the generic PCI code. */ > > + uint8_t irq_state; > > + > > + /* Capability bits */ > > + uint32_t cap_present; > > + > > + /* Offset of MSI-X capability in config space */ > > + uint8_t msix_cap; > > + > > + /* MSI-X entries */ > > + int msix_entries_nr; > > + > > + /* Space to store MSIX table & pending bit array */ > > + uint8_t *msix_table; > > + uint8_t *msix_pba; > > + /* MemoryRegion container for msix exclusive BAR setup */ > > + MemoryRegion msix_exclusive_bar; > > + /* Memory Regions for MSIX table and pending bit entries. */ > > + MemoryRegion msix_table_mmio; > > + MemoryRegion msix_pba_mmio; > > + /* Reference-count for entries actually in use by driver. */ > > + unsigned *msix_entry_used; > > + /* MSIX function mask set or MSIX disabled */ > > + bool msix_function_masked; > > + /* Version id needed for VMState */ > > + int32_t version_id; > > + > > + /* Offset of MSI capability in config space */ > > + uint8_t msi_cap; > > + > > + /* PCI Express */ > > + PCIExpressDevice exp; > > + > > + /* SHPC */ > > + SHPCDevice *shpc; > > + > > + /* Location of option rom */ > > + char *romfile; > > + bool has_rom; > > + MemoryRegion rom; > > + uint32_t rom_bar; > > + > > + /* INTx routing notifier */ > > + PCIINTxRoutingNotifier intx_routing_notifier; > > + > > + /* MSI-X notifiers */ > > + MSIVectorUseNotifier msix_vector_use_notifier; > > + MSIVectorReleaseNotifier msix_vector_release_notifier; > > +}; > > + > > +void pci_register_bar(PCIDevice *pci_dev, int region_num, > > + uint8_t attr, MemoryRegion *memory); > > +pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num); > > + > > +int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, > > + uint8_t offset, uint8_t size); > > + > > +void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); > > + > > +uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id); > > + > > + > > +uint32_t pci_default_read_config(PCIDevice *d, > > + uint32_t address, int len); > > +void pci_default_write_config(PCIDevice *d, > > + uint32_t address, uint32_t val, int len); > > +void pci_device_save(PCIDevice *s, QEMUFile *f); > > +int pci_device_load(PCIDevice *s, QEMUFile *f); > > +MemoryRegion *pci_address_space(PCIDevice *dev); > > +MemoryRegion *pci_address_space_io(PCIDevice *dev); > > + > > +typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); > > +typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); > > +typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin); > > + > > +typedef enum { > > + PCI_HOTPLUG_DISABLED, > > + PCI_HOTPLUG_ENABLED, > > + PCI_COLDPLUG_ENABLED, > > +} PCIHotplugState; > > + > > +typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, > > + PCIHotplugState state); > > +void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, > > + const char *name, > > + MemoryRegion *address_space_mem, > > + MemoryRegion *address_space_io, > > + uint8_t devfn_min); > > +PCIBus *pci_bus_new(DeviceState *parent, const char *name, > > + MemoryRegion *address_space_mem, > > + MemoryRegion *address_space_io, > > + uint8_t devfn_min); > > +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > > + void *irq_opaque, int nirq); > > +int pci_bus_get_irq_level(PCIBus *bus, int irq_num); > > +void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev); > > +/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */ > > +int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin); > > +PCIBus *pci_register_bus(DeviceState *parent, const char *name, > > + pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, > > + void *irq_opaque, > > + MemoryRegion *address_space_mem, > > + MemoryRegion *address_space_io, > > + uint8_t devfn_min, int nirq); > > +void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn); > > +PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin); > > +bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new); > > +void pci_bus_fire_intx_routing_notifier(PCIBus *bus); > > +void pci_device_set_intx_routing_notifier(PCIDevice *dev, > > + PCIINTxRoutingNotifier notifier); > > +void pci_device_reset(PCIDevice *dev); > > +void pci_bus_reset(PCIBus *bus); > > + > > +PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, > > + const char *default_devaddr); > > +PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, > > + const char *default_devaddr); > > + > > +PCIDevice *pci_vga_init(PCIBus *bus); > > + > > +int pci_bus_num(PCIBus *s); > > +void pci_for_each_device(PCIBus *bus, int bus_num, > > + void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque), > > + void *opaque); > > +PCIBus *pci_find_root_bus(int domain); > > +int pci_find_domain(const PCIBus *bus); > > +PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn); > > +int pci_qdev_find_device(const char *id, PCIDevice **pdev); > > +PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr); > > + > > +int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, > > + unsigned *slotp); > > + > > +void pci_device_deassert_intx(PCIDevice *dev); > > + > > +typedef DMAContext *(*PCIDMAContextFunc)(PCIBus *, void *, int); > > + > > +void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque); > > + > > +static inline void > > +pci_set_byte(uint8_t *config, uint8_t val) > > +{ > > + *config = val; > > +} > > + > > +static inline uint8_t > > +pci_get_byte(const uint8_t *config) > > +{ > > + return *config; > > +} > > + > > +static inline void > > +pci_set_word(uint8_t *config, uint16_t val) > > +{ > > + cpu_to_le16wu((uint16_t *)config, val); > > +} > > + > > +static inline uint16_t > > +pci_get_word(const uint8_t *config) > > +{ > > + return le16_to_cpupu((const uint16_t *)config); > > +} > > + > > +static inline void > > +pci_set_long(uint8_t *config, uint32_t val) > > +{ > > + cpu_to_le32wu((uint32_t *)config, val); > > +} > > + > > +static inline uint32_t > > +pci_get_long(const uint8_t *config) > > +{ > > + return le32_to_cpupu((const uint32_t *)config); > > +} > > + > > +static inline void > > +pci_set_quad(uint8_t *config, uint64_t val) > > +{ > > + cpu_to_le64w((uint64_t *)config, val); > > +} > > + > > +static inline uint64_t > > +pci_get_quad(const uint8_t *config) > > +{ > > + return le64_to_cpup((const uint64_t *)config); > > +} > > + > > +static inline void > > +pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val) > > +{ > > + pci_set_word(&pci_config[PCI_VENDOR_ID], val); > > +} > > + > > +static inline void > > +pci_config_set_device_id(uint8_t *pci_config, uint16_t val) > > +{ > > + pci_set_word(&pci_config[PCI_DEVICE_ID], val); > > +} > > + > > +static inline void > > +pci_config_set_revision(uint8_t *pci_config, uint8_t val) > > +{ > > + pci_set_byte(&pci_config[PCI_REVISION_ID], val); > > +} > > + > > +static inline void > > +pci_config_set_class(uint8_t *pci_config, uint16_t val) > > +{ > > + pci_set_word(&pci_config[PCI_CLASS_DEVICE], val); > > +} > > + > > +static inline void > > +pci_config_set_prog_interface(uint8_t *pci_config, uint8_t val) > > +{ > > + pci_set_byte(&pci_config[PCI_CLASS_PROG], val); > > +} > > + > > +static inline void > > +pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val) > > +{ > > + pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val); > > +} > > + > > +/* > > + * helper functions to do bit mask operation on configuration space. > > + * Just to set bit, use test-and-set and discard returned value. > > + * Just to clear bit, use test-and-clear and discard returned value. > > + * NOTE: They aren't atomic. > > + */ > > +static inline uint8_t > > +pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask) > > +{ > > + uint8_t val = pci_get_byte(config); > > + pci_set_byte(config, val & ~mask); > > + return val & mask; > > +} > > + > > +static inline uint8_t > > +pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask) > > +{ > > + uint8_t val = pci_get_byte(config); > > + pci_set_byte(config, val | mask); > > + return val & mask; > > +} > > + > > +static inline uint16_t > > +pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask) > > +{ > > + uint16_t val = pci_get_word(config); > > + pci_set_word(config, val & ~mask); > > + return val & mask; > > +} > > + > > +static inline uint16_t > > +pci_word_test_and_set_mask(uint8_t *config, uint16_t mask) > > +{ > > + uint16_t val = pci_get_word(config); > > + pci_set_word(config, val | mask); > > + return val & mask; > > +} > > + > > +static inline uint32_t > > +pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask) > > +{ > > + uint32_t val = pci_get_long(config); > > + pci_set_long(config, val & ~mask); > > + return val & mask; > > +} > > + > > +static inline uint32_t > > +pci_long_test_and_set_mask(uint8_t *config, uint32_t mask) > > +{ > > + uint32_t val = pci_get_long(config); > > + pci_set_long(config, val | mask); > > + return val & mask; > > +} > > + > > +static inline uint64_t > > +pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask) > > +{ > > + uint64_t val = pci_get_quad(config); > > + pci_set_quad(config, val & ~mask); > > + return val & mask; > > +} > > + > > +static inline uint64_t > > +pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask) > > +{ > > + uint64_t val = pci_get_quad(config); > > + pci_set_quad(config, val | mask); > > + return val & mask; > > +} > > + > > +/* Access a register specified by a mask */ > > +static inline void > > +pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg) > > +{ > > + uint8_t val = pci_get_byte(config); > > + uint8_t rval = reg << (ffs(mask) - 1); > > + pci_set_byte(config, (~mask & val) | (mask & rval)); > > +} > > + > > +static inline uint8_t > > +pci_get_byte_by_mask(uint8_t *config, uint8_t mask) > > +{ > > + uint8_t val = pci_get_byte(config); > > + return (val & mask) >> (ffs(mask) - 1); > > +} > > + > > +static inline void > > +pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg) > > +{ > > + uint16_t val = pci_get_word(config); > > + uint16_t rval = reg << (ffs(mask) - 1); > > + pci_set_word(config, (~mask & val) | (mask & rval)); > > +} > > + > > +static inline uint16_t > > +pci_get_word_by_mask(uint8_t *config, uint16_t mask) > > +{ > > + uint16_t val = pci_get_word(config); > > + return (val & mask) >> (ffs(mask) - 1); > > +} > > + > > +static inline void > > +pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg) > > +{ > > + uint32_t val = pci_get_long(config); > > + uint32_t rval = reg << (ffs(mask) - 1); > > + pci_set_long(config, (~mask & val) | (mask & rval)); > > +} > > + > > +static inline uint32_t > > +pci_get_long_by_mask(uint8_t *config, uint32_t mask) > > +{ > > + uint32_t val = pci_get_long(config); > > + return (val & mask) >> (ffs(mask) - 1); > > +} > > + > > +static inline void > > +pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg) > > +{ > > + uint64_t val = pci_get_quad(config); > > + uint64_t rval = reg << (ffs(mask) - 1); > > + pci_set_quad(config, (~mask & val) | (mask & rval)); > > +} > > + > > +static inline uint64_t > > +pci_get_quad_by_mask(uint8_t *config, uint64_t mask) > > +{ > > + uint64_t val = pci_get_quad(config); > > + return (val & mask) >> (ffs(mask) - 1); > > +} > > + > > +PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, > > + const char *name); > > +PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, > > + bool multifunction, > > + const char *name); > > +PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); > > +PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name); > > + > > +static inline int pci_is_express(const PCIDevice *d) > > +{ > > + return d->cap_present & QEMU_PCI_CAP_EXPRESS; > > +} > > + > > +static inline uint32_t pci_config_size(const PCIDevice *d) > > +{ > > + return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; > > +} > > + > > +/* DMA access functions */ > > +static inline DMAContext *pci_dma_context(PCIDevice *dev) > > +{ > > + return dev->dma; > > +} > > + > > +static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, > > + void *buf, dma_addr_t len, DMADirection dir) > > +{ > > + dma_memory_rw(pci_dma_context(dev), addr, buf, len, dir); > > + return 0; > > +} > > + > > +static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr, > > + void *buf, dma_addr_t len) > > +{ > > + return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE); > > +} > > + > > +static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr, > > + const void *buf, dma_addr_t len) > > +{ > > + return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE); > > +} > > + > > +#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ > > + static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \ > > + dma_addr_t addr) \ > > + { \ > > + return ld##_l##_dma(pci_dma_context(dev), addr); \ > > + } \ > > + static inline void st##_s##_pci_dma(PCIDevice *dev, \ > > + dma_addr_t addr, uint##_bits##_t val) \ > > + { \ > > + st##_s##_dma(pci_dma_context(dev), addr, val); \ > > + } > > + > > +PCI_DMA_DEFINE_LDST(ub, b, 8); > > +PCI_DMA_DEFINE_LDST(uw_le, w_le, 16) > > +PCI_DMA_DEFINE_LDST(l_le, l_le, 32); > > +PCI_DMA_DEFINE_LDST(q_le, q_le, 64); > > +PCI_DMA_DEFINE_LDST(uw_be, w_be, 16) > > +PCI_DMA_DEFINE_LDST(l_be, l_be, 32); > > +PCI_DMA_DEFINE_LDST(q_be, q_be, 64); > > + > > +#undef PCI_DMA_DEFINE_LDST > > + > > +static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, > > + dma_addr_t *plen, DMADirection dir) > > +{ > > + void *buf; > > + > > + buf = dma_memory_map(pci_dma_context(dev), addr, plen, dir); > > + return buf; > > +} > > + > > +static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len, > > + DMADirection dir, dma_addr_t access_len) > > +{ > > + dma_memory_unmap(pci_dma_context(dev), buffer, len, dir, access_len); > > +} > > + > > +static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev, > > + int alloc_hint) > > +{ > > + qemu_sglist_init(qsg, alloc_hint, pci_dma_context(dev)); > > +} > > + > > +extern const VMStateDescription vmstate_pci_device; > > + > > +#define VMSTATE_PCI_DEVICE(_field, _state) { \ > > + .name = (stringify(_field)), \ > > + .size = sizeof(PCIDevice), \ > > + .vmsd = &vmstate_pci_device, \ > > + .flags = VMS_STRUCT, \ > > + .offset = vmstate_offset_value(_state, _field, PCIDevice), \ > > +} > > + > > +#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { \ > > + .name = (stringify(_field)), \ > > + .size = sizeof(PCIDevice), \ > > + .vmsd = &vmstate_pci_device, \ > > + .flags = VMS_STRUCT|VMS_POINTER, \ > > + .offset = vmstate_offset_pointer(_state, _field, PCIDevice), \ > > +} > > + > > +#endif > > diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c > > new file mode 100644 > > index 0000000..4680501 > > --- /dev/null > > +++ b/hw/pci/pci_bridge.c > > @@ -0,0 +1,363 @@ > > +/* > > + * QEMU PCI bus manager > > + * > > + * Copyright (c) 2004 Fabrice Bellard > > + * > > + * Permission is hereby granted, free of charge, to any person obtaining a copy > > + * of this software and associated documentation files (the "Software"), to dea > > + > > + * in the Software without restriction, including without limitation the rights > > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > > + * copies of the Software, and to permit persons to whom the Software is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be included in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM > > + > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > > + * THE SOFTWARE. > > + */ > > +/* > > + * split out from pci.c > > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + */ > > + > > +#include "pci_bridge.h" > > +#include "pci_internals.h" > > +#include "range.h" > > + > > +/* PCI bridge subsystem vendor ID helper functions */ > > +#define PCI_SSVID_SIZEOF 8 > > +#define PCI_SSVID_SVID 4 > > +#define PCI_SSVID_SSID 6 > > + > > +int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, > > + uint16_t svid, uint16_t ssid) > > +{ > > + int pos; > > + pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF); > > + if (pos < 0) { > > + return pos; > > + } > > + > > + pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid); > > + pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid); > > + return pos; > > +} > > + > > +/* Accessor function to get parent bridge device from pci bus. */ > > +PCIDevice *pci_bridge_get_device(PCIBus *bus) > > +{ > > + return bus->parent_dev; > > +} > > + > > +/* Accessor function to get secondary bus from pci-to-pci bridge device */ > > +PCIBus *pci_bridge_get_sec_bus(PCIBridge *br) > > +{ > > + return &br->sec_bus; > > +} > > + > > +static uint32_t pci_config_get_io_base(const PCIDevice *d, > > + uint32_t base, uint32_t base_upper16) > > +{ > > + uint32_t val; > > + > > + val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8; > > + if (d->config[base] & PCI_IO_RANGE_TYPE_32) { > > + val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16; > > + } > > + return val; > > +} > > + > > +static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base) > > +{ > > + return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) > > + << 16; > > +} > > + > > +static pcibus_t pci_config_get_pref_base(const PCIDevice *d, > > + uint32_t base, uint32_t upper) > > +{ > > + pcibus_t tmp; > > + pcibus_t val; > > + > > + tmp = (pcibus_t)pci_get_word(d->config + base); > > + val = (tmp & PCI_PREF_RANGE_MASK) << 16; > > + if (tmp & PCI_PREF_RANGE_TYPE_64) { > > + val |= (pcibus_t)pci_get_long(d->config + upper) << 32; > > + } > > + return val; > > +} > > + > > +/* accessor function to get bridge filtering base address */ > > +pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type) > > +{ > > + pcibus_t base; > > + if (type & PCI_BASE_ADDRESS_SPACE_IO) { > > + base = pci_config_get_io_base(bridge, > > + PCI_IO_BASE, PCI_IO_BASE_UPPER16); > > + } else { > > + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > > + base = pci_config_get_pref_base( > > + bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32); > > + } else { > > + base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE); > > + } > > + } > > + > > + return base; > > +} > > + > > +/* accessor funciton to get bridge filtering limit */ > > +pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type) > > +{ > > + pcibus_t limit; > > + if (type & PCI_BASE_ADDRESS_SPACE_IO) { > > + limit = pci_config_get_io_base(bridge, > > + PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16); > > + limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */ > > + } else { > > + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > > + limit = pci_config_get_pref_base( > > + bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32); > > + } else { > > + limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT); > > + } > > + limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */ > > + } > > + return limit; > > +} > > + > > +static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, > > + uint8_t type, const char *name, > > + MemoryRegion *space, > > + MemoryRegion *parent_space, > > + bool enabled) > > +{ > > + pcibus_t base = pci_bridge_get_base(&bridge->dev, type); > > + pcibus_t limit = pci_bridge_get_limit(&bridge->dev, type); > > + /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly. > > + * Apparently no way to do this with existing memory APIs. */ > > + pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0; > > + > > + memory_region_init_alias(alias, name, space, base, size); > > + memory_region_add_subregion_overlap(parent_space, base, alias, 1); > > +} > > + > > +static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) > > +{ > > + PCIBus *parent = br->dev.bus; > > + PCIBridgeWindows *w = g_new(PCIBridgeWindows, 1); > > + uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND); > > + > > + pci_bridge_init_alias(br, &w->alias_pref_mem, > > + PCI_BASE_ADDRESS_MEM_PREFETCH, > > + "pci_bridge_pref_mem", > > + &br->address_space_mem, > > + parent->address_space_mem, > > + cmd & PCI_COMMAND_MEMORY); > > + pci_bridge_init_alias(br, &w->alias_mem, > > + PCI_BASE_ADDRESS_SPACE_MEMORY, > > + "pci_bridge_mem", > > + &br->address_space_mem, > > + parent->address_space_mem, > > + cmd & PCI_COMMAND_MEMORY); > > + pci_bridge_init_alias(br, &w->alias_io, > > + PCI_BASE_ADDRESS_SPACE_IO, > > + "pci_bridge_io", > > + &br->address_space_io, > > + parent->address_space_io, > > + cmd & PCI_COMMAND_IO); > > + /* TODO: optinal VGA and VGA palette snooping support. */ > > + > > + return w; > > +} > > + > > +static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w) > > +{ > > + PCIBus *parent = br->dev.bus; > > + > > + memory_region_del_subregion(parent->address_space_io, &w->alias_io); > > + memory_region_del_subregion(parent->address_space_mem, &w->alias_mem); > > + memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem); > > +} > > + > > +static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w) > > +{ > > + memory_region_destroy(&w->alias_io); > > + memory_region_destroy(&w->alias_mem); > > + memory_region_destroy(&w->alias_pref_mem); > > + g_free(w); > > +} > > + > > +static void pci_bridge_update_mappings(PCIBridge *br) > > +{ > > + PCIBridgeWindows *w = br->windows; > > + > > + /* Make updates atomic to: handle the case of one VCPU updating the bridge > > + * while another accesses an unaffected region. */ > > + memory_region_transaction_begin(); > > + pci_bridge_region_del(br, br->windows); > > + br->windows = pci_bridge_region_init(br); > > + memory_region_transaction_commit(); > > + pci_bridge_region_cleanup(br, w); > > +} > > + > > +/* default write_config function for PCI-to-PCI bridge */ > > +void pci_bridge_write_config(PCIDevice *d, > > + uint32_t address, uint32_t val, int len) > > +{ > > + PCIBridge *s = container_of(d, PCIBridge, dev); > > + uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); > > + uint16_t newctl; > > + > > + pci_default_write_config(d, address, val, len); > > + > > + if (ranges_overlap(address, len, PCI_COMMAND, 2) || > > + > > + /* io base/limit */ > > + ranges_overlap(address, len, PCI_IO_BASE, 2) || > > + > > + /* memory base/limit, prefetchable base/limit and > > + io base/limit upper 16 */ > > + ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { > > + pci_bridge_update_mappings(s); > > + } > > + > > + newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); > > + if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) { > > + /* Trigger hot reset on 0->1 transition. */ > > + pci_bus_reset(&s->sec_bus); > > + } > > +} > > + > > +void pci_bridge_disable_base_limit(PCIDevice *dev) > > +{ > > + uint8_t *conf = dev->config; > > + > > + pci_byte_test_and_set_mask(conf + PCI_IO_BASE, > > + PCI_IO_RANGE_MASK & 0xff); > > + pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, > > + PCI_IO_RANGE_MASK & 0xff); > > + pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE, > > + PCI_MEMORY_RANGE_MASK & 0xffff); > > + pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, > > + PCI_MEMORY_RANGE_MASK & 0xffff); > > + pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE, > > + PCI_PREF_RANGE_MASK & 0xffff); > > + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, > > + PCI_PREF_RANGE_MASK & 0xffff); > > + pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); > > + pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); > > +} > > + > > +/* reset bridge specific configuration registers */ > > +void pci_bridge_reset(DeviceState *qdev) > > +{ > > + PCIDevice *dev = PCI_DEVICE(qdev); > > + uint8_t *conf = dev->config; > > + > > + conf[PCI_PRIMARY_BUS] = 0; > > + conf[PCI_SECONDARY_BUS] = 0; > > + conf[PCI_SUBORDINATE_BUS] = 0; > > + conf[PCI_SEC_LATENCY_TIMER] = 0; > > + > > + /* > > + * the default values for base/limit registers aren't specified > > + * in the PCI-to-PCI-bridge spec. So we don't thouch them here. > > + * Each implementation can override it. > > + * typical implementation does > > + * zero base/limit registers or > > + * disable forwarding: pci_bridge_disable_base_limit() > > + * If disable forwarding is wanted, call pci_bridge_disable_base_limit() > > + * after this function. > > + */ > > + pci_byte_test_and_clear_mask(conf + PCI_IO_BASE, > > + PCI_IO_RANGE_MASK & 0xff); > > + pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, > > + PCI_IO_RANGE_MASK & 0xff); > > + pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE, > > + PCI_MEMORY_RANGE_MASK & 0xffff); > > + pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, > > + PCI_MEMORY_RANGE_MASK & 0xffff); > > + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE, > > + PCI_PREF_RANGE_MASK & 0xffff); > > + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, > > + PCI_PREF_RANGE_MASK & 0xffff); > > + pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); > > + pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); > > + > > + pci_set_word(conf + PCI_BRIDGE_CONTROL, 0); > > +} > > + > > +/* default qdev initialization function for PCI-to-PCI bridge */ > > +int pci_bridge_initfn(PCIDevice *dev) > > +{ > > + PCIBus *parent = dev->bus; > > + PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); > > + PCIBus *sec_bus = &br->sec_bus; > > + > > + pci_word_test_and_set_mask(dev->config + PCI_STATUS, > > + PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); > > + pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI); > > + dev->config[PCI_HEADER_TYPE] = > > + (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) | > > + PCI_HEADER_TYPE_BRIDGE; > > + pci_set_word(dev->config + PCI_SEC_STATUS, > > + PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); > > + > > + /* > > + * If we don't specify the name, the bus will be addressed as <id>.0, where > > + * id is the device id. > > + * Since PCI Bridge devices have a single bus each, we don't need the index: > > + * let users address the bus using the device name. > > + */ > > + if (!br->bus_name && dev->qdev.id && *dev->qdev.id) { > > + br->bus_name = dev->qdev.id; > > + } > > + > > + qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev, > > + br->bus_name); > > + sec_bus->parent_dev = dev; > > + sec_bus->map_irq = br->map_irq; > > + sec_bus->address_space_mem = &br->address_space_mem; > > + memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX); > > + sec_bus->address_space_io = &br->address_space_io; > > + memory_region_init(&br->address_space_io, "pci_bridge_io", 65536); > > + br->windows = pci_bridge_region_init(br); > > + QLIST_INIT(&sec_bus->child); > > + QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); > > + return 0; > > +} > > + > > +/* default qdev clean up function for PCI-to-PCI bridge */ > > +void pci_bridge_exitfn(PCIDevice *pci_dev) > > +{ > > + PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); > > + assert(QLIST_EMPTY(&s->sec_bus.child)); > > + QLIST_REMOVE(&s->sec_bus, sibling); > > + pci_bridge_region_del(s, s->windows); > > + pci_bridge_region_cleanup(s, s->windows); > > + memory_region_destroy(&s->address_space_mem); > > + memory_region_destroy(&s->address_space_io); > > + /* qbus_free() is called automatically by qdev_free() */ > > +} > > + > > +/* > > + * before qdev initialization(qdev_init()), this function sets bus_name and > > + * map_irq callback which are necessry for pci_bridge_initfn() to > > + * initialize bus. > > + */ > > +void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, > > + pci_map_irq_fn map_irq) > > +{ > > + br->map_irq = map_irq; > > + br->bus_name = bus_name; > > +} > > diff --git a/hw/pci/pci_bridge.h b/hw/pci/pci_bridge.h > > new file mode 100644 > > index 0000000..a00accc > > --- /dev/null > > +++ b/hw/pci/pci_bridge.h > > @@ -0,0 +1,66 @@ > > +/* > > + * QEMU PCI bridge > > + * > > + * Copyright (c) 2004 Fabrice Bellard > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + * You should have received a copy of the GNU General Public License > > + * along with this program; if not, write to the Free Software > > + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > > + * > > + * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc] > > + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + */ > > + > > +#ifndef QEMU_PCI_BRIDGE_H > > +#define QEMU_PCI_BRIDGE_H > > + > > +#include "pci.h" > > + > > +int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, > > + uint16_t svid, uint16_t ssid); > > + > > +PCIDevice *pci_bridge_get_device(PCIBus *bus); > > +PCIBus *pci_bridge_get_sec_bus(PCIBridge *br); > > + > > +pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type); > > +pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type); > > + > > +void pci_bridge_write_config(PCIDevice *d, > > + uint32_t address, uint32_t val, int len); > > +void pci_bridge_disable_base_limit(PCIDevice *dev); > > +void pci_bridge_reset_reg(PCIDevice *dev); > > +void pci_bridge_reset(DeviceState *qdev); > > + > > +int pci_bridge_initfn(PCIDevice *pci_dev); > > +void pci_bridge_exitfn(PCIDevice *pci_dev); > > + > > + > > +/* > > + * before qdev initialization(qdev_init()), this function sets bus_name and > > + * map_irq callback which are necessry for pci_bridge_initfn() to > > + * initialize bus. > > + */ > > +void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, > > + pci_map_irq_fn map_irq); > > + > > +#endif /* QEMU_PCI_BRIDGE_H */ > > +/* > > + * Local variables: > > + * c-indent-level: 4 > > + * c-basic-offset: 4 > > + * tab-width: 8 > > + * indent-tab-mode: nil > > + * End: > > + */ > > diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c > > new file mode 100644 > > index 0000000..68e328c > > --- /dev/null > > +++ b/hw/pci/pci_host.c > > @@ -0,0 +1,180 @@ > > +/* > > + * pci_host.c > > + * > > + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#include "pci.h" > > +#include "pci_host.h" > > + > > +/* debug PCI */ > > +//#define DEBUG_PCI > > + > > +#ifdef DEBUG_PCI > > +#define PCI_DPRINTF(fmt, ...) \ > > +do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0) > > +#else > > +#define PCI_DPRINTF(fmt, ...) > > +#endif > > + > > +/* > > + * PCI address > > + * bit 16 - 24: bus number > > + * bit 8 - 15: devfun number > > + * bit 0 - 7: offset in configuration space of a given pci device > > + */ > > + > > +/* the helper functio to get a PCIDeice* for a given pci address */ > > +static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr) > > +{ > > + uint8_t bus_num = addr >> 16; > > + uint8_t devfn = addr >> 8; > > + > > + return pci_find_device(bus, bus_num, devfn); > > +} > > + > > +void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, > > + uint32_t limit, uint32_t val, uint32_t len) > > +{ > > + assert(len <= 4); > > + pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr)); > > +} > > + > > +uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, > > + uint32_t limit, uint32_t len) > > +{ > > + assert(len <= 4); > > + return pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr)); > > +} > > + > > +void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len) > > +{ > > + PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); > > + uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); > > + > > + if (!pci_dev) { > > + return; > > + } > > + > > + PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n", > > + __func__, pci_dev->name, config_addr, val, len); > > + pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE, > > + val, len); > > +} > > + > > +uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) > > +{ > > + PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); > > + uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); > > + uint32_t val; > > + > > + if (!pci_dev) { > > + return ~0x0; > > + } > > + > > + val = pci_host_config_read_common(pci_dev, config_addr, > > + PCI_CONFIG_SPACE_SIZE, len); > > + PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n", > > + __func__, pci_dev->name, config_addr, val, len); > > + > > + return val; > > +} > > + > > +static void pci_host_config_write(void *opaque, hwaddr addr, > > + uint64_t val, unsigned len) > > +{ > > + PCIHostState *s = opaque; > > + > > + PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", > > + __func__, addr, len, val); > > + if (addr != 0 || len != 4) { > > + return; > > + } > > + s->config_reg = val; > > +} > > + > > +static uint64_t pci_host_config_read(void *opaque, hwaddr addr, > > + unsigned len) > > +{ > > + PCIHostState *s = opaque; > > + uint32_t val = s->config_reg; > > + > > + PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n", > > + __func__, addr, len, val); > > + return val; > > +} > > + > > +static void pci_host_data_write(void *opaque, hwaddr addr, > > + uint64_t val, unsigned len) > > +{ > > + PCIHostState *s = opaque; > > + PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n", > > + addr, len, (unsigned)val); > > + if (s->config_reg & (1u << 31)) > > + pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); > > +} > > + > > +static uint64_t pci_host_data_read(void *opaque, > > + hwaddr addr, unsigned len) > > +{ > > + PCIHostState *s = opaque; > > + uint32_t val; > > + if (!(s->config_reg & (1 << 31))) > > + return 0xffffffff; > > + val = pci_data_read(s->bus, s->config_reg | (addr & 3), len); > > + PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n", > > + addr, len, val); > > + return val; > > +} > > + > > +const MemoryRegionOps pci_host_conf_le_ops = { > > + .read = pci_host_config_read, > > + .write = pci_host_config_write, > > + .endianness = DEVICE_LITTLE_ENDIAN, > > +}; > > + > > +const MemoryRegionOps pci_host_conf_be_ops = { > > + .read = pci_host_config_read, > > + .write = pci_host_config_write, > > + .endianness = DEVICE_BIG_ENDIAN, > > +}; > > + > > +const MemoryRegionOps pci_host_data_le_ops = { > > + .read = pci_host_data_read, > > + .write = pci_host_data_write, > > + .endianness = DEVICE_LITTLE_ENDIAN, > > +}; > > + > > +const MemoryRegionOps pci_host_data_be_ops = { > > + .read = pci_host_data_read, > > + .write = pci_host_data_write, > > + .endianness = DEVICE_BIG_ENDIAN, > > +}; > > + > > +static const TypeInfo pci_host_type_info = { > > + .name = TYPE_PCI_HOST_BRIDGE, > > + .parent = TYPE_SYS_BUS_DEVICE, > > + .abstract = true, > > + .instance_size = sizeof(PCIHostState), > > +}; > > + > > +static void pci_host_register_types(void) > > +{ > > + type_register_static(&pci_host_type_info); > > +} > > + > > +type_init(pci_host_register_types) > > diff --git a/hw/pci/pci_host.h b/hw/pci/pci_host.h > > new file mode 100644 > > index 0000000..4b9c300 > > --- /dev/null > > +++ b/hw/pci/pci_host.h > > @@ -0,0 +1,62 @@ > > +/* > > + * QEMU Common PCI Host bridge configuration data space access routines. > > + * > > + * Copyright (c) 2006 Fabrice Bellard > > + * > > + * Permission is hereby granted, free of charge, to any person obtaining a copy > > + * of this software and associated documentation files (the "Software"), to deal > > + * in the Software without restriction, including without limitation the rights > > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > > + * copies of the Software, and to permit persons to whom the Software is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be included in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > > + * THE SOFTWARE. > > + */ > > + > > +/* Worker routines for a PCI host controller that uses an {address,data} > > + register pair to access PCI configuration space. */ > > + > > +#ifndef PCI_HOST_H > > +#define PCI_HOST_H > > + > > +#include "sysbus.h" > > + > > +#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge" > > +#define PCI_HOST_BRIDGE(obj) \ > > + OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE) > > + > > +struct PCIHostState { > > + SysBusDevice busdev; > > + > > + MemoryRegion conf_mem; > > + MemoryRegion data_mem; > > + MemoryRegion mmcfg; > > + MemoryRegion *address_space; > > + uint32_t config_reg; > > + PCIBus *bus; > > +}; > > + > > +/* common internal helpers for PCI/PCIe hosts, cut off overflows */ > > +void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, > > + uint32_t limit, uint32_t val, uint32_t len); > > +uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, > > + uint32_t limit, uint32_t len); > > + > > +void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len); > > +uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len); > > + > > +extern const MemoryRegionOps pci_host_conf_le_ops; > > +extern const MemoryRegionOps pci_host_conf_be_ops; > > +extern const MemoryRegionOps pci_host_data_le_ops; > > +extern const MemoryRegionOps pci_host_data_be_ops; > > + > > +#endif /* PCI_HOST_H */ > > diff --git a/hw/pci/pci_ids.h b/hw/pci/pci_ids.h > > new file mode 100644 > > index 0000000..5df7245 > > --- /dev/null > > +++ b/hw/pci/pci_ids.h > > @@ -0,0 +1,147 @@ > > +/* > > + * PCI Class, Vendor and Device IDs > > + * > > + * Please keep sorted. > > + * > > + * Abbreviated version of linux/pci_ids.h > > + * > > + * QEMU-specific definitions belong in pci.h > > + */ > > + > > +/* Device classes and subclasses */ > > + > > +#define PCI_BASE_CLASS_STORAGE 0x01 > > +#define PCI_BASE_CLASS_NETWORK 0x02 > > + > > +#define PCI_CLASS_STORAGE_SCSI 0x0100 > > +#define PCI_CLASS_STORAGE_IDE 0x0101 > > +#define PCI_CLASS_STORAGE_RAID 0x0104 > > +#define PCI_CLASS_STORAGE_SATA 0x0106 > > +#define PCI_CLASS_STORAGE_OTHER 0x0180 > > + > > +#define PCI_CLASS_NETWORK_ETHERNET 0x0200 > > + > > +#define PCI_CLASS_DISPLAY_VGA 0x0300 > > +#define PCI_CLASS_DISPLAY_OTHER 0x0380 > > + > > +#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 > > + > > +#define PCI_CLASS_MEMORY_RAM 0x0500 > > + > > +#define PCI_CLASS_SYSTEM_OTHER 0x0880 > > + > > +#define PCI_CLASS_SERIAL_USB 0x0c03 > > +#define PCI_CLASS_SERIAL_SMBUS 0x0c05 > > + > > +#define PCI_CLASS_BRIDGE_HOST 0x0600 > > +#define PCI_CLASS_BRIDGE_ISA 0x0601 > > +#define PCI_CLASS_BRIDGE_PCI 0x0604 > > +#define PCI_CLASS_BRDIGE_PCI_INF_SUB 0x01 > > +#define PCI_CLASS_BRIDGE_OTHER 0x0680 > > + > > +#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 > > +#define PCI_CLASS_COMMUNICATION_OTHER 0x0780 > > + > > +#define PCI_CLASS_PROCESSOR_CO 0x0b40 > > +#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20 > > + > > +#define PCI_CLASS_OTHERS 0xff > > + > > +/* Vendors and devices. Sort key: vendor first, device next. */ > > + > > +#define PCI_VENDOR_ID_LSI_LOGIC 0x1000 > > +#define PCI_DEVICE_ID_LSI_53C895A 0x0012 > > +#define PCI_DEVICE_ID_LSI_SAS1078 0x0060 > > + > > +#define PCI_VENDOR_ID_DEC 0x1011 > > +#define PCI_DEVICE_ID_DEC_21154 0x0026 > > + > > +#define PCI_VENDOR_ID_CIRRUS 0x1013 > > + > > +#define PCI_VENDOR_ID_IBM 0x1014 > > + > > +#define PCI_VENDOR_ID_AMD 0x1022 > > +#define PCI_DEVICE_ID_AMD_LANCE 0x2000 > > +#define PCI_DEVICE_ID_AMD_SCSI 0x2020 > > + > > +#define PCI_VENDOR_ID_TI 0x104c > > + > > +#define PCI_VENDOR_ID_MOTOROLA 0x1057 > > +#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 > > +#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 > > + > > +#define PCI_VENDOR_ID_APPLE 0x106b > > +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 > > +#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b > > + > > +#define PCI_VENDOR_ID_SUN 0x108e > > +#define PCI_DEVICE_ID_SUN_EBUS 0x1000 > > +#define PCI_DEVICE_ID_SUN_SIMBA 0x5000 > > +#define PCI_DEVICE_ID_SUN_SABRE 0xa000 > > + > > +#define PCI_VENDOR_ID_CMD 0x1095 > > +#define PCI_DEVICE_ID_CMD_646 0x0646 > > + > > +#define PCI_VENDOR_ID_REALTEK 0x10ec > > +#define PCI_DEVICE_ID_REALTEK_8139 0x8139 > > + > > +#define PCI_VENDOR_ID_XILINX 0x10ee > > + > > +#define PCI_VENDOR_ID_VIA 0x1106 > > +#define PCI_DEVICE_ID_VIA_ISA_BRIDGE 0x0686 > > +#define PCI_DEVICE_ID_VIA_IDE 0x0571 > > +#define PCI_DEVICE_ID_VIA_UHCI 0x3038 > > +#define PCI_DEVICE_ID_VIA_ACPI 0x3057 > > +#define PCI_DEVICE_ID_VIA_AC97 0x3058 > > +#define PCI_DEVICE_ID_VIA_MC97 0x3068 > > + > > +#define PCI_VENDOR_ID_MARVELL 0x11ab > > + > > +#define PCI_VENDOR_ID_ENSONIQ 0x1274 > > +#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 > > + > > +#define PCI_VENDOR_ID_FREESCALE 0x1957 > > +#define PCI_DEVICE_ID_MPC8533E 0x0030 > > + > > +#define PCI_VENDOR_ID_INTEL 0x8086 > > +#define PCI_DEVICE_ID_INTEL_82378 0x0484 > > +#define PCI_DEVICE_ID_INTEL_82441 0x1237 > > +#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 > > +#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e > > +#define PCI_DEVICE_ID_INTEL_82801D 0x24CD > > +#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab > > +#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 > > +#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 > > +#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 > > +#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 > > +#define PCI_DEVICE_ID_INTEL_82371AB 0x7111 > > +#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 > > +#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 > > + > > +#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 > > +#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 > > +#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 > > +#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 > > +#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 > > +#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 > > +#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 > > +#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 > > +#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 > > + > > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934 > > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935 > > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936 > > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937 > > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938 > > +#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939 > > +#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a > > +#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c > > +#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed > > + > > +#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 > > + > > +#define PCI_VENDOR_ID_XEN 0x5853 > > +#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 > > + > > +#define PCI_VENDOR_ID_NEC 0x1033 > > +#define PCI_DEVICE_ID_NEC_UPD720200 0x0194 > > diff --git a/hw/pci/pci_internals.h b/hw/pci/pci_internals.h > > new file mode 100644 > > index 0000000..21d0ce6 > > --- /dev/null > > +++ b/hw/pci/pci_internals.h > > @@ -0,0 +1,78 @@ > > +#ifndef QEMU_PCI_INTERNALS_H > > +#define QEMU_PCI_INTERNALS_H > > + > > +/* > > + * This header files is private to pci.c and pci_bridge.c > > + * So following structures are opaque to others and shouldn't be > > + * accessed. > > + * > > + * For pci-to-pci bridge needs to include this header file to embed > > + * PCIBridge in its structure or to get sizeof(PCIBridge), > > + * However, they shouldn't access those following members directly. > > + * Use accessor function in pci.h, pci_bridge.h > > + */ > > + > > +#define TYPE_PCI_BUS "PCI" > > +#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) > > + > > +struct PCIBus { > > + BusState qbus; > > + PCIDMAContextFunc dma_context_fn; > > + void *dma_context_opaque; > > + uint8_t devfn_min; > > + pci_set_irq_fn set_irq; > > + pci_map_irq_fn map_irq; > > + pci_route_irq_fn route_intx_to_irq; > > + pci_hotplug_fn hotplug; > > + DeviceState *hotplug_qdev; > > + void *irq_opaque; > > + PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; > > + PCIDevice *parent_dev; > > + MemoryRegion *address_space_mem; > > + MemoryRegion *address_space_io; > > + > > + QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ > > + QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ > > + > > + /* The bus IRQ state is the logical OR of the connected devices. > > + Keep a count of the number of devices with raised IRQs. */ > > + int nirq; > > + int *irq_count; > > +}; > > + > > +typedef struct PCIBridgeWindows PCIBridgeWindows; > > + > > +/* > > + * Aliases for each of the address space windows that the bridge > > + * can forward. Mapped into the bridge's parent's address space, > > + * as subregions. > > + */ > > +struct PCIBridgeWindows { > > + MemoryRegion alias_pref_mem; > > + MemoryRegion alias_mem; > > + MemoryRegion alias_io; > > +}; > > + > > +struct PCIBridge { > > + PCIDevice dev; > > + > > + /* private member */ > > + PCIBus sec_bus; > > + /* > > + * Memory regions for the bridge's address spaces. These regions are not > > + * directly added to system_memory/system_io or its descendants. > > + * Bridge's secondary bus points to these, so that devices > > + * under the bridge see these regions as its address spaces. > > + * The regions are as large as the entire address space - > > + * they don't take into account any windows. > > + */ > > + MemoryRegion address_space_mem; > > + MemoryRegion address_space_io; > > + > > + PCIBridgeWindows *windows; > > + > > + pci_map_irq_fn map_irq; > > + const char *bus_name; > > +}; > > + > > +#endif /* QEMU_PCI_INTERNALS_H */ > > diff --git a/hw/pci/pci_regs.h b/hw/pci/pci_regs.h > > new file mode 100644 > > index 0000000..56a404b > > --- /dev/null > > +++ b/hw/pci/pci_regs.h > > @@ -0,0 +1,717 @@ > > +/* > > + * pci_regs.h > > + * > > + * PCI standard defines > > + * Copyright 1994, Drew Eckhardt > > + * Copyright 1997--1999 Martin Mares <mj@ucw.cz> > > + * > > + * For more information, please consult the following manuals (look at > > + * http://www.pcisig.com/ for how to get them): > > + * > > + * PCI BIOS Specification > > + * PCI Local Bus Specification > > + * PCI to PCI Bridge Specification > > + * PCI System Design Guide > > + * > > + * For hypertransport information, please consult the following manuals > > + * from http://www.hypertransport.org > > + * > > + * The Hypertransport I/O Link Specification > > + */ > > + > > +#ifndef LINUX_PCI_REGS_H > > +#define LINUX_PCI_REGS_H > > + > > +/* > > + * Under PCI, each device has 256 bytes of configuration address space, > > + * of which the first 64 bytes are standardized as follows: > > + */ > > +#define PCI_VENDOR_ID 0x00 /* 16 bits */ > > +#define PCI_DEVICE_ID 0x02 /* 16 bits */ > > +#define PCI_COMMAND 0x04 /* 16 bits */ > > +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ > > +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ > > +#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ > > +#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ > > +#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ > > +#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ > > +#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ > > +#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ > > +#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ > > +#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ > > +#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ > > + > > +#define PCI_STATUS 0x06 /* 16 bits */ > > +#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */ > > +#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ > > +#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ > > +#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ > > +#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ > > +#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ > > +#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ > > +#define PCI_STATUS_DEVSEL_FAST 0x000 > > +#define PCI_STATUS_DEVSEL_MEDIUM 0x200 > > +#define PCI_STATUS_DEVSEL_SLOW 0x400 > > +#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ > > +#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ > > +#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ > > +#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ > > +#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ > > + > > +#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ > > +#define PCI_REVISION_ID 0x08 /* Revision ID */ > > +#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ > > +#define PCI_CLASS_DEVICE 0x0a /* Device class */ > > + > > +#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ > > +#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ > > +#define PCI_HEADER_TYPE 0x0e /* 8 bits */ > > +#define PCI_HEADER_TYPE_NORMAL 0 > > +#define PCI_HEADER_TYPE_BRIDGE 1 > > +#define PCI_HEADER_TYPE_CARDBUS 2 > > + > > +#define PCI_BIST 0x0f /* 8 bits */ > > +#define PCI_BIST_CODE_MASK 0x0f /* Return result */ > > +#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ > > +#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ > > + > > +/* > > + * Base addresses specify locations in memory or I/O space. > > + * Decoded size can be determined by writing a value of > > + * 0xffffffff to the register, and reading it back. Only > > + * 1 bits are decoded. > > + */ > > +#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ > > +#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ > > +#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ > > +#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ > > +#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ > > +#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ > > +#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ > > +#define PCI_BASE_ADDRESS_SPACE_IO 0x01 > > +#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 > > +#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 > > +#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ > > +#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ > > +#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ > > +#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ > > +#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) > > +#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) > > +/* bit 1 is reserved if address_space = 1 */ > > + > > +/* Header type 0 (normal devices) */ > > +#define PCI_CARDBUS_CIS 0x28 > > +#define PCI_SUBSYSTEM_VENDOR_ID 0x2c > > +#define PCI_SUBSYSTEM_ID 0x2e > > +#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ > > +#define PCI_ROM_ADDRESS_ENABLE 0x01 > > +#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) > > + > > +#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ > > + > > +/* 0x35-0x3b are reserved */ > > +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ > > +#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ > > +#define PCI_MIN_GNT 0x3e /* 8 bits */ > > +#define PCI_MAX_LAT 0x3f /* 8 bits */ > > + > > +/* Header type 1 (PCI-to-PCI bridges) */ > > +#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ > > +#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ > > +#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ > > +#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ > > +#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ > > +#define PCI_IO_LIMIT 0x1d > > +#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ > > +#define PCI_IO_RANGE_TYPE_16 0x00 > > +#define PCI_IO_RANGE_TYPE_32 0x01 > > +#define PCI_IO_RANGE_MASK (~0x0fUL) > > +#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ > > +#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ > > +#define PCI_MEMORY_LIMIT 0x22 > > +#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL > > +#define PCI_MEMORY_RANGE_MASK (~0x0fUL) > > +#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ > > +#define PCI_PREF_MEMORY_LIMIT 0x26 > > +#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL > > +#define PCI_PREF_RANGE_TYPE_32 0x00 > > +#define PCI_PREF_RANGE_TYPE_64 0x01 > > +#define PCI_PREF_RANGE_MASK (~0x0fUL) > > +#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ > > +#define PCI_PREF_LIMIT_UPPER32 0x2c > > +#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ > > +#define PCI_IO_LIMIT_UPPER16 0x32 > > +/* 0x34 same as for htype 0 */ > > +/* 0x35-0x3b is reserved */ > > +#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ > > +/* 0x3c-0x3d are same as for htype 0 */ > > +#define PCI_BRIDGE_CONTROL 0x3e > > +#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ > > +#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ > > +#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */ > > +#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ > > +#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ > > +#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ > > +#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ > > + > > +/* Header type 2 (CardBus bridges) */ > > +#define PCI_CB_CAPABILITY_LIST 0x14 > > +/* 0x15 reserved */ > > +#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */ > > +#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */ > > +#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */ > > +#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */ > > +#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ > > +#define PCI_CB_MEMORY_BASE_0 0x1c > > +#define PCI_CB_MEMORY_LIMIT_0 0x20 > > +#define PCI_CB_MEMORY_BASE_1 0x24 > > +#define PCI_CB_MEMORY_LIMIT_1 0x28 > > +#define PCI_CB_IO_BASE_0 0x2c > > +#define PCI_CB_IO_BASE_0_HI 0x2e > > +#define PCI_CB_IO_LIMIT_0 0x30 > > +#define PCI_CB_IO_LIMIT_0_HI 0x32 > > +#define PCI_CB_IO_BASE_1 0x34 > > +#define PCI_CB_IO_BASE_1_HI 0x36 > > +#define PCI_CB_IO_LIMIT_1 0x38 > > +#define PCI_CB_IO_LIMIT_1_HI 0x3a > > +#define PCI_CB_IO_RANGE_MASK (~0x03UL) > > +/* 0x3c-0x3d are same as for htype 0 */ > > +#define PCI_CB_BRIDGE_CONTROL 0x3e > > +#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */ > > +#define PCI_CB_BRIDGE_CTL_SERR 0x02 > > +#define PCI_CB_BRIDGE_CTL_ISA 0x04 > > +#define PCI_CB_BRIDGE_CTL_VGA 0x08 > > +#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20 > > +#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */ > > +#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */ > > +#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */ > > +#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200 > > +#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400 > > +#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 > > +#define PCI_CB_SUBSYSTEM_ID 0x42 > > +#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */ > > +/* 0x48-0x7f reserved */ > > + > > +/* Capability lists */ > > + > > +#define PCI_CAP_LIST_ID 0 /* Capability ID */ > > +#define PCI_CAP_ID_PM 0x01 /* Power Management */ > > +#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ > > +#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ > > +#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ > > +#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ > > +#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ > > +#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ > > +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ > > +#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */ > > +#define PCI_CAP_ID_DBG 0x0A /* Debug port */ > > +#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ > > +#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ > > +#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ > > +#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ > > +#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ > > +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ > > +#define PCI_CAP_ID_SATA 0x12 /* Serial ATA */ > > +#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ > > +#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ > > +#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ > > +#define PCI_CAP_SIZEOF 4 > > + > > +/* Power Management Registers */ > > + > > +#define PCI_PM_PMC 2 /* PM Capabilities Register */ > > +#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ > > +#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ > > +#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ > > +#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ > > +#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */ > > +#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ > > +#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ > > +#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ > > +#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ > > +#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ > > +#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ > > +#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ > > +#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ > > +#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ > > +#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */ > > +#define PCI_PM_CTRL 4 /* PM control and status register */ > > +#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ > > +#define PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */ > > +#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ > > +#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ > > +#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ > > +#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ > > +#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ > > +#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ > > +#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ > > +#define PCI_PM_DATA_REGISTER 7 /* (??) */ > > +#define PCI_PM_SIZEOF 8 > > + > > +/* AGP registers */ > > + > > +#define PCI_AGP_VERSION 2 /* BCD version number */ > > +#define PCI_AGP_RFU 3 /* Rest of capability flags */ > > +#define PCI_AGP_STATUS 4 /* Status register */ > > +#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ > > +#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ > > +#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ > > +#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ > > +#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ > > +#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ > > +#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ > > +#define PCI_AGP_COMMAND 8 /* Control register */ > > +#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ > > +#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ > > +#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ > > +#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ > > +#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ > > +#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ > > +#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ > > +#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ > > +#define PCI_AGP_SIZEOF 12 > > + > > +/* Vital Product Data */ > > + > > +#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */ > > +#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */ > > +#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */ > > +#define PCI_VPD_DATA 4 /* 32-bits of data returned here */ > > + > > +/* Slot Identification */ > > + > > +#define PCI_SID_ESR 2 /* Expansion Slot Register */ > > +#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ > > +#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ > > +#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ > > + > > +/* Message Signalled Interrupts registers */ > > + > > +#define PCI_MSI_FLAGS 2 /* Various flags */ > > +#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */ > > +#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */ > > +#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */ > > +#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */ > > +#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */ > > +#define PCI_MSI_RFU 3 /* Rest of capability flags */ > > +#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ > > +#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ > > +#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ > > +#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */ > > +#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ > > +#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ > > + > > +/* MSI-X registers */ > > +#define PCI_MSIX_FLAGS 2 > > +#define PCI_MSIX_FLAGS_QSIZE 0x7FF > > +#define PCI_MSIX_FLAGS_ENABLE (1 << 15) > > +#define PCI_MSIX_FLAGS_MASKALL (1 << 14) > > +#define PCI_MSIX_TABLE 4 > > +#define PCI_MSIX_PBA 8 > > +#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) > > + > > +/* MSI-X entry's format */ > > +#define PCI_MSIX_ENTRY_SIZE 16 > > +#define PCI_MSIX_ENTRY_LOWER_ADDR 0 > > +#define PCI_MSIX_ENTRY_UPPER_ADDR 4 > > +#define PCI_MSIX_ENTRY_DATA 8 > > +#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 > > +#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 > > + > > +/* CompactPCI Hotswap Register */ > > + > > +#define PCI_CHSWP_CSR 2 /* Control and Status Register */ > > +#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */ > > +#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */ > > +#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */ > > +#define PCI_CHSWP_LOO 0x08 /* LED On / Off */ > > +#define PCI_CHSWP_PI 0x30 /* Programming Interface */ > > +#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ > > +#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ > > + > > +/* PCI Advanced Feature registers */ > > + > > +#define PCI_AF_LENGTH 2 > > +#define PCI_AF_CAP 3 > > +#define PCI_AF_CAP_TP 0x01 > > +#define PCI_AF_CAP_FLR 0x02 > > +#define PCI_AF_CTRL 4 > > +#define PCI_AF_CTRL_FLR 0x01 > > +#define PCI_AF_STATUS 5 > > +#define PCI_AF_STATUS_TP 0x01 > > + > > +/* PCI-X registers */ > > + > > +#define PCI_X_CMD 2 /* Modes & Features */ > > +#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ > > +#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ > > +#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ > > +#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ > > +#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ > > +#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ > > +#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ > > + /* Max # of outstanding split transactions */ > > +#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */ > > +#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */ > > +#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */ > > +#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */ > > +#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */ > > +#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */ > > +#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */ > > +#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */ > > +#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ > > +#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */ > > +#define PCI_X_STATUS 4 /* PCI-X capabilities */ > > +#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */ > > +#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */ > > +#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */ > > +#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */ > > +#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */ > > +#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */ > > +#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */ > > +#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count */ > > +#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */ > > +#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */ > > +#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ > > +#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ > > +#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ > > + > > +/* PCI Bridge Subsystem ID registers */ > > + > > +#define PCI_SSVID_VENDOR_ID 4 /* PCI-Bridge subsystem vendor id register */ > > +#define PCI_SSVID_DEVICE_ID 6 /* PCI-Bridge subsystem device id register */ > > + > > +/* PCI Express capability registers */ > > + > > +#define PCI_EXP_FLAGS 2 /* Capabilities register */ > > +#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ > > +#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ > > +#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ > > +#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ > > +#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ > > +#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ > > +#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ > > +#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ > > +#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */ > > +#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ > > +#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ > > +#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ > > +#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ > > +#define PCI_EXP_DEVCAP 4 /* Device capabilities */ > > +#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */ > > +#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */ > > +#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */ > > +#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */ > > +#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */ > > +#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ > > +#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ > > +#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ > > +#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ > > +#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ > > +#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ > > +#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ > > +#define PCI_EXP_DEVCTL 8 /* Device Control */ > > +#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ > > +#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ > > +#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ > > +#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ > > +#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */ > > +#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ > > +#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ > > +#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ > > +#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ > > +#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ > > +#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ > > +#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ > > +#define PCI_EXP_DEVSTA 10 /* Device Status */ > > +#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ > > +#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ > > +#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */ > > +#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */ > > +#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ > > +#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ > > +#define PCI_EXP_LNKCAP 12 /* Link Capabilities */ > > +#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */ > > +#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */ > > +#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */ > > +#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */ > > +#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */ > > +#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* L1 Clock Power Management */ > > +#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Reporting Capable */ > > +#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link Active Reporting Capable */ > > +#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notification Capability */ > > +#define PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */ > > +#define PCI_EXP_LNKCTL 16 /* Link Control */ > > +#define PCI_EXP_LNKCTL_ASPMC 0x0003 /* ASPM Control */ > > +#define PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */ > > +#define PCI_EXP_LNKCTL_LD 0x0010 /* Link Disable */ > > +#define PCI_EXP_LNKCTL_RL 0x0020 /* Retrain Link */ > > +#define PCI_EXP_LNKCTL_CCC 0x0040 /* Common Clock Configuration */ > > +#define PCI_EXP_LNKCTL_ES 0x0080 /* Extended Synch */ > > +#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ > > +#define PCI_EXP_LNKCTL_HAWD 0x0200 /* Hardware Autonomous Width Disable */ > > +#define PCI_EXP_LNKCTL_LBMIE 0x0400 /* Link Bandwidth Management Interrupt Enable */ > > +#define PCI_EXP_LNKCTL_LABIE 0x0800 /* Lnk Autonomous Bandwidth Interrupt Enable */ > > +#define PCI_EXP_LNKSTA 18 /* Link Status */ > > +#define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */ > > +#define PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */ > > +#define PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */ > > +#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Nogotiated Link Width */ > > +#define PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */ > > +#define PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */ > > +#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ > > +#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ > > +#define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ > > +#define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */ > > +#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ > > +#define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */ > > +#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */ > > +#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */ > > +#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Present */ > > +#define PCI_EXP_SLTCAP_PIP 0x00000010 /* Power Indicator Present */ > > +#define PCI_EXP_SLTCAP_HPS 0x00000020 /* Hot-Plug Surprise */ > > +#define PCI_EXP_SLTCAP_HPC 0x00000040 /* Hot-Plug Capable */ > > +#define PCI_EXP_SLTCAP_SPLV 0x00007f80 /* Slot Power Limit Value */ > > +#define PCI_EXP_SLTCAP_SPLS 0x00018000 /* Slot Power Limit Scale */ > > +#define PCI_EXP_SLTCAP_EIP 0x00020000 /* Electromechanical Interlock Present */ > > +#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Support */ > > +#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ > > +#define PCI_EXP_SLTCTL 24 /* Slot Control */ > > +#define PCI_EXP_SLTCTL_ABPE 0x0001 /* Attention Button Pressed Enable */ > > +#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enable */ > > +#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable */ > > +#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed Enable */ > > +#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable */ > > +#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */ > > +#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */ > > +#define PCI_EXP_SLTCTL_PIC 0x0300 /* Power Indicator Control */ > > +#define PCI_EXP_SLTCTL_PCC 0x0400 /* Power Controller Control */ > > +#define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */ > > +#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */ > > +#define PCI_EXP_SLTSTA 26 /* Slot Status */ > > +#define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */ > > +#define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */ > > +#define PCI_EXP_SLTSTA_MRLSC 0x0004 /* MRL Sensor Changed */ > > +#define PCI_EXP_SLTSTA_PDC 0x0008 /* Presence Detect Changed */ > > +#define PCI_EXP_SLTSTA_CC 0x0010 /* Command Completed */ > > +#define PCI_EXP_SLTSTA_MRLSS 0x0020 /* MRL Sensor State */ > > +#define PCI_EXP_SLTSTA_PDS 0x0040 /* Presence Detect State */ > > +#define PCI_EXP_SLTSTA_EIS 0x0080 /* Electromechanical Interlock Status */ > > +#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Changed */ > > +#define PCI_EXP_RTCTL 28 /* Root Control */ > > +#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctable Error */ > > +#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal Error */ > > +#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Error */ > > +#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */ > > +#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */ > > +#define PCI_EXP_RTCAP 30 /* Root Capabilities */ > > +#define PCI_EXP_RTSTA 32 /* Root Status */ > > +#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ > > +#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ > > +#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ > > +#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ > > +#define PCI_EXP_DEVCAP2_LTR 0x800 /* Latency tolerance reporting */ > > +#define PCI_EXP_OBFF_MASK 0xc0000 /* OBFF support mechanism */ > > +#define PCI_EXP_OBFF_MSG 0x40000 /* New message signaling */ > > +#define PCI_EXP_OBFF_WAKE 0x80000 /* Re-use WAKE# for OBFF */ > > +#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ > > +#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */ > > +#define PCI_EXP_IDO_REQ_EN 0x100 /* ID-based ordering request enable */ > > +#define PCI_EXP_IDO_CMP_EN 0x200 /* ID-based ordering completion enable */ > > +#define PCI_EXP_LTR_EN 0x400 /* Latency tolerance reporting */ > > +#define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message type A */ > > +#define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message type B */ > > +#define PCI_EXP_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ > > +#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ > > +#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ > > + > > +/* Extended Capabilities (PCI-X 2.0 and Express) */ > > +#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff) > > +#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf) > > +#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc) > > + > > +#define PCI_EXT_CAP_ID_ERR 1 > > +#define PCI_EXT_CAP_ID_VC 2 > > +#define PCI_EXT_CAP_ID_DSN 3 > > +#define PCI_EXT_CAP_ID_PWR 4 > > +#define PCI_EXT_CAP_ID_VNDR 11 > > +#define PCI_EXT_CAP_ID_ACS 13 > > +#define PCI_EXT_CAP_ID_ARI 14 > > +#define PCI_EXT_CAP_ID_ATS 15 > > +#define PCI_EXT_CAP_ID_SRIOV 16 > > +#define PCI_EXT_CAP_ID_LTR 24 > > + > > +/* Advanced Error Reporting */ > > +#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ > > +#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */ > > +#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ > > +#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */ > > +#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */ > > +#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */ > > +#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */ > > +#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */ > > +#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */ > > +#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */ > > +#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */ > > +#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */ > > +#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */ > > + /* Same bits as above */ > > +#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */ > > + /* Same bits as above */ > > +#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */ > > +#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */ > > +#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */ > > +#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */ > > +#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */ > > +#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */ > > +#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ > > + /* Same bits as above */ > > +#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ > > +#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */ > > +#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */ > > +#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */ > > +#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */ > > +#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ > > +#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */ > > +#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */ > > +/* Correctable Err Reporting Enable */ > > +#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 > > +/* Non-fatal Err Reporting Enable */ > > +#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 > > +/* Fatal Err Reporting Enable */ > > +#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 > > +#define PCI_ERR_ROOT_STATUS 48 > > +#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ > > +/* Multi ERR_COR Received */ > > +#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 > > +/* ERR_FATAL/NONFATAL Recevied */ > > +#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 > > +/* Multi ERR_FATAL/NONFATAL Recevied */ > > +#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 > > +#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */ > > +#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ > > +#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ > > +#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */ > > + > > +/* Virtual Channel */ > > +#define PCI_VC_PORT_REG1 4 > > +#define PCI_VC_PORT_REG2 8 > > +#define PCI_VC_PORT_CTRL 12 > > +#define PCI_VC_PORT_STATUS 14 > > +#define PCI_VC_RES_CAP 16 > > +#define PCI_VC_RES_CTRL 20 > > +#define PCI_VC_RES_STATUS 26 > > + > > +/* Power Budgeting */ > > +#define PCI_PWR_DSR 4 /* Data Select Register */ > > +#define PCI_PWR_DATA 8 /* Data Register */ > > +#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */ > > +#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */ > > +#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */ > > +#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */ > > +#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */ > > +#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */ > > +#define PCI_PWR_CAP 12 /* Capability */ > > +#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ > > + > > +/* > > + * Hypertransport sub capability types > > + * > > + * Unfortunately there are both 3 bit and 5 bit capability types defined > > + * in the HT spec, catering for that is a little messy. You probably don't > > + * want to use these directly, just use pci_find_ht_capability() and it > > + * will do the right thing for you. > > + */ > > +#define HT_3BIT_CAP_MASK 0xE0 > > +#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ > > +#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ > > + > > +#define HT_5BIT_CAP_MASK 0xF8 > > +#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ > > +#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ > > +#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ > > +#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */ > > +#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */ > > +#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */ > > +#define HT_MSI_FLAGS 0x02 /* Offset to flags */ > > +#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */ > > +#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */ > > +#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */ > > +#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */ > > +#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */ > > +#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */ > > +#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */ > > +#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */ > > +#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */ > > +#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */ > > +#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */ > > + > > +/* Alternative Routing-ID Interpretation */ > > +#define PCI_ARI_CAP 0x04 /* ARI Capability Register */ > > +#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */ > > +#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */ > > +#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */ > > +#define PCI_ARI_CTRL 0x06 /* ARI Control Register */ > > +#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */ > > +#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ > > +#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ > > + > > +/* Address Translation Service */ > > +#define PCI_ATS_CAP 0x04 /* ATS Capability Register */ > > +#define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f) /* Invalidate Queue Depth */ > > +#define PCI_ATS_MAX_QDEP 32 /* Max Invalidate Queue Depth */ > > +#define PCI_ATS_CTRL 0x06 /* ATS Control Register */ > > +#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */ > > +#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */ > > +#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */ > > + > > +/* Single Root I/O Virtualization */ > > +#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ > > +#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ > > +#define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */ > > +#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */ > > +#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */ > > +#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */ > > +#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */ > > +#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */ > > +#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */ > > +#define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */ > > +#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */ > > +#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */ > > +#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */ > > +#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */ > > +#define PCI_SRIOV_FUNC_LINK 0x12 /* Function Dependency Link */ > > +#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */ > > +#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */ > > +#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */ > > +#define PCI_SRIOV_SUP_PGSIZE 0x1c /* Supported Page Sizes */ > > +#define PCI_SRIOV_SYS_PGSIZE 0x20 /* System Page Size */ > > +#define PCI_SRIOV_BAR 0x24 /* VF BAR0 */ > > +#define PCI_SRIOV_NUM_BARS 6 /* Number of VF BARs */ > > +#define PCI_SRIOV_VFM 0x3c /* VF Migration State Array Offset*/ > > +#define PCI_SRIOV_VFM_BIR(x) ((x) & 7) /* State BIR */ > > +#define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7) /* State Offset */ > > +#define PCI_SRIOV_VFM_UA 0x0 /* Inactive.Unavailable */ > > +#define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */ > > +#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ > > +#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ > > + > > +#define PCI_LTR_MAX_SNOOP_LAT 0x4 > > +#define PCI_LTR_MAX_NOSNOOP_LAT 0x6 > > +#define PCI_LTR_VALUE_MASK 0x000003ff > > +#define PCI_LTR_SCALE_MASK 0x00001c00 > > +#define PCI_LTR_SCALE_SHIFT 10 > > + > > +/* Access Control Service */ > > +#define PCI_ACS_CAP 0x04 /* ACS Capability Register */ > > +#define PCI_ACS_SV 0x01 /* Source Validation */ > > +#define PCI_ACS_TB 0x02 /* Translation Blocking */ > > +#define PCI_ACS_RR 0x04 /* P2P Request Redirect */ > > +#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */ > > +#define PCI_ACS_UF 0x10 /* Upstream Forwarding */ > > +#define PCI_ACS_EC 0x20 /* P2P Egress Control */ > > +#define PCI_ACS_DT 0x40 /* Direct Translated P2P */ > > +#define PCI_ACS_CTRL 0x06 /* ACS Control Register */ > > +#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ > > + > > +#endif /* LINUX_PCI_REGS_H */ > > diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c > > new file mode 100644 > > index 0000000..7c92f19 > > --- /dev/null > > +++ b/hw/pci/pcie.c > > @@ -0,0 +1,555 @@ > > +/* > > + * pcie.c > > + * > > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#include "qemu-common.h" > > +#include "pci_bridge.h" > > +#include "pcie.h" > > +#include "msix.h" > > +#include "msi.h" > > +#include "pci_internals.h" > > +#include "pcie_regs.h" > > +#include "range.h" > > + > > +//#define DEBUG_PCIE > > +#ifdef DEBUG_PCIE > > +# define PCIE_DPRINTF(fmt, ...) \ > > + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > > +#else > > +# define PCIE_DPRINTF(fmt, ...) do {} while (0) > > +#endif > > +#define PCIE_DEV_PRINTF(dev, fmt, ...) \ > > + PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > > + > > + > > +/*************************************************************************** > > + * pci express capability helper functions > > + */ > > +int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) > > +{ > > + int pos; > > + uint8_t *exp_cap; > > + > > + assert(pci_is_express(dev)); > > + > > + pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, > > + PCI_EXP_VER2_SIZEOF); > > + if (pos < 0) { > > + return pos; > > + } > > + dev->exp.exp_cap = pos; > > + exp_cap = dev->config + pos; > > + > > + /* capability register > > + interrupt message number defaults to 0 */ > > + pci_set_word(exp_cap + PCI_EXP_FLAGS, > > + ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) | > > + PCI_EXP_FLAGS_VER2); > > + > > + /* device capability register > > + * table 7-12: > > + * roll based error reporting bit must be set by all > > + * Functions conforming to the ECN, PCI Express Base > > + * Specification, Revision 1.1., or subsequent PCI Express Base > > + * Specification revisions. > > + */ > > + pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER); > > + > > + pci_set_long(exp_cap + PCI_EXP_LNKCAP, > > + (port << PCI_EXP_LNKCAP_PN_SHIFT) | > > + PCI_EXP_LNKCAP_ASPMS_0S | > > + PCI_EXP_LNK_MLW_1 | > > + PCI_EXP_LNK_LS_25); > > + > > + pci_set_word(exp_cap + PCI_EXP_LNKSTA, > > + PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25); > > + > > + pci_set_long(exp_cap + PCI_EXP_DEVCAP2, > > + PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP); > > + > > + pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB); > > + return pos; > > +} > > + > > +void pcie_cap_exit(PCIDevice *dev) > > +{ > > + pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF); > > +} > > + > > +uint8_t pcie_cap_get_type(const PCIDevice *dev) > > +{ > > + uint32_t pos = dev->exp.exp_cap; > > + assert(pos > 0); > > + return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) & > > + PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT; > > +} > > + > > +/* MSI/MSI-X */ > > +/* pci express interrupt message number */ > > +/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */ > > +void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector) > > +{ > > + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > > + assert(vector < 32); > > + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ); > > + pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS, > > + vector << PCI_EXP_FLAGS_IRQ_SHIFT); > > +} > > + > > +uint8_t pcie_cap_flags_get_vector(PCIDevice *dev) > > +{ > > + return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) & > > + PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT; > > +} > > + > > +void pcie_cap_deverr_init(PCIDevice *dev) > > +{ > > + uint32_t pos = dev->exp.exp_cap; > > + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP, > > + PCI_EXP_DEVCAP_RBER); > > + pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL, > > + PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | > > + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); > > + pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA, > > + PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED | > > + PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD); > > +} > > + > > +void pcie_cap_deverr_reset(PCIDevice *dev) > > +{ > > + uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; > > + pci_long_test_and_clear_mask(devctl, > > + PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | > > + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); > > +} > > + > > +static void hotplug_event_update_event_status(PCIDevice *dev) > > +{ > > + uint32_t pos = dev->exp.exp_cap; > > + uint8_t *exp_cap = dev->config + pos; > > + uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL); > > + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > > + > > + dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) && > > + (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED); > > +} > > + > > +static void hotplug_event_notify(PCIDevice *dev) > > +{ > > + bool prev = dev->exp.hpev_notified; > > + > > + hotplug_event_update_event_status(dev); > > + > > + if (prev == dev->exp.hpev_notified) { > > + return; > > + } > > + > > + /* Note: the logic above does not take into account whether interrupts > > + * are masked. The result is that interrupt will be sent when it is > > + * subsequently unmasked. This appears to be legal: Section 6.7.3.4: > > + * The Port may optionally send an MSI when there are hot-plug events that > > + * occur while interrupt generation is disabled, and interrupt generation is > > + * subsequently enabled. */ > > + if (msix_enabled(dev)) { > > + msix_notify(dev, pcie_cap_flags_get_vector(dev)); > > + } else if (msi_enabled(dev)) { > > + msi_notify(dev, pcie_cap_flags_get_vector(dev)); > > + } else { > > + qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified); > > + } > > +} > > + > > +static void hotplug_event_clear(PCIDevice *dev) > > +{ > > + hotplug_event_update_event_status(dev); > > + if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) { > > + qemu_set_irq(dev->irq[dev->exp.hpev_intx], 0); > > + } > > +} > > + > > +/* > > + * A PCI Express Hot-Plug Event has occurred, so update slot status register > > + * and notify OS of the event if necessary. > > + * > > + * 6.7.3 PCI Express Hot-Plug Events > > + * 6.7.3.4 Software Notification of Hot-Plug Events > > + */ > > +static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) > > +{ > > + /* Minor optimization: if nothing changed - no event is needed. */ > > + if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap + > > + PCI_EXP_SLTSTA, event)) { > > + return; > > + } > > + hotplug_event_notify(dev); > > +} > > + > > +static int pcie_cap_slot_hotplug(DeviceState *qdev, > > + PCIDevice *pci_dev, PCIHotplugState state) > > +{ > > + PCIDevice *d = PCI_DEVICE(qdev); > > + uint8_t *exp_cap = d->config + d->exp.exp_cap; > > + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > > + > > + /* Don't send event when device is enabled during qemu machine creation: > > + * it is present on boot, no hotplug event is necessary. We do send an > > + * event when the device is disabled later. */ > > + if (state == PCI_COLDPLUG_ENABLED) { > > + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, > > + PCI_EXP_SLTSTA_PDS); > > + return 0; > > + } > > + > > + PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state); > > + if (sltsta & PCI_EXP_SLTSTA_EIS) { > > + /* the slot is electromechanically locked. > > + * This error is propagated up to qdev and then to HMP/QMP. > > + */ > > + return -EBUSY; > > + } > > + > > + /* TODO: multifunction hot-plug. > > + * Right now, only a device of function = 0 is allowed to be > > + * hot plugged/unplugged. > > + */ > > + assert(PCI_FUNC(pci_dev->devfn) == 0); > > + > > + if (state == PCI_HOTPLUG_ENABLED) { > > + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, > > + PCI_EXP_SLTSTA_PDS); > > + pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); > > + } else { > > + qdev_free(&pci_dev->qdev); > > + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, > > + PCI_EXP_SLTSTA_PDS); > > + pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); > > + } > > + return 0; > > +} > > + > > +/* pci express slot for pci express root/downstream port > > + PCI express capability slot registers */ > > +void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot) > > +{ > > + uint32_t pos = dev->exp.exp_cap; > > + > > + pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS, > > + PCI_EXP_FLAGS_SLOT); > > + > > + pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP, > > + ~PCI_EXP_SLTCAP_PSN); > > + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP, > > + (slot << PCI_EXP_SLTCAP_PSN_SHIFT) | > > + PCI_EXP_SLTCAP_EIP | > > + PCI_EXP_SLTCAP_HPS | > > + PCI_EXP_SLTCAP_HPC | > > + PCI_EXP_SLTCAP_PIP | > > + PCI_EXP_SLTCAP_AIP | > > + PCI_EXP_SLTCAP_ABP); > > + > > + pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL, > > + PCI_EXP_SLTCTL_PIC | > > + PCI_EXP_SLTCTL_AIC); > > + pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL, > > + PCI_EXP_SLTCTL_PIC_OFF | > > + PCI_EXP_SLTCTL_AIC_OFF); > > + pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, > > + PCI_EXP_SLTCTL_PIC | > > + PCI_EXP_SLTCTL_AIC | > > + PCI_EXP_SLTCTL_HPIE | > > + PCI_EXP_SLTCTL_CCIE | > > + PCI_EXP_SLTCTL_PDCE | > > + PCI_EXP_SLTCTL_ABPE); > > + /* Although reading PCI_EXP_SLTCTL_EIC returns always 0, > > + * make the bit writable here in order to detect 1b is written. > > + * pcie_cap_slot_write_config() test-and-clear the bit, so > > + * this bit always returns 0 to the guest. > > + */ > > + pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, > > + PCI_EXP_SLTCTL_EIC); > > + > > + pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA, > > + PCI_EXP_HP_EV_SUPPORTED); > > + > > + dev->exp.hpev_notified = false; > > + > > + pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)), > > + pcie_cap_slot_hotplug, &dev->qdev); > > +} > > + > > +void pcie_cap_slot_reset(PCIDevice *dev) > > +{ > > + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > > + > > + PCIE_DEV_PRINTF(dev, "reset\n"); > > + > > + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, > > + PCI_EXP_SLTCTL_EIC | > > + PCI_EXP_SLTCTL_PIC | > > + PCI_EXP_SLTCTL_AIC | > > + PCI_EXP_SLTCTL_HPIE | > > + PCI_EXP_SLTCTL_CCIE | > > + PCI_EXP_SLTCTL_PDCE | > > + PCI_EXP_SLTCTL_ABPE); > > + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL, > > + PCI_EXP_SLTCTL_PIC_OFF | > > + PCI_EXP_SLTCTL_AIC_OFF); > > + > > + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, > > + PCI_EXP_SLTSTA_EIS |/* on reset, > > + the lock is released */ > > + PCI_EXP_SLTSTA_CC | > > + PCI_EXP_SLTSTA_PDC | > > + PCI_EXP_SLTSTA_ABP); > > + > > + hotplug_event_update_event_status(dev); > > +} > > + > > +void pcie_cap_slot_write_config(PCIDevice *dev, > > + uint32_t addr, uint32_t val, int len) > > +{ > > + uint32_t pos = dev->exp.exp_cap; > > + uint8_t *exp_cap = dev->config + pos; > > + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > > + > > + if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) { > > + hotplug_event_clear(dev); > > + } > > + > > + if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) { > > + return; > > + } > > + > > + if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, > > + PCI_EXP_SLTCTL_EIC)) { > > + sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */ > > + pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta); > > + PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: " > > + "sltsta -> 0x%02"PRIx16"\n", > > + sltsta); > > + } > > + > > + hotplug_event_notify(dev); > > + > > + /* > > + * 6.7.3.2 Command Completed Events > > + * > > + * Software issues a command to a hot-plug capable Downstream Port by > > + * issuing a write transaction that targets any portion of the Port’s Slot > > + * Control register. A single write to the Slot Control register is > > + * considered to be a single command, even if the write affects more than > > + * one field in the Slot Control register. In response to this transaction, > > + * the Port must carry out the requested actions and then set the > > + * associated status field for the command completed event. */ > > + > > + /* Real hardware might take a while to complete requested command because > > + * physical movement would be involved like locking the electromechanical > > + * lock. However in our case, command is completed instantaneously above, > > + * so send a command completion event right now. > > + */ > > + pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI); > > +} > > + > > +int pcie_cap_slot_post_load(void *opaque, int version_id) > > +{ > > + PCIDevice *dev = opaque; > > + hotplug_event_update_event_status(dev); > > + return 0; > > +} > > + > > +void pcie_cap_slot_push_attention_button(PCIDevice *dev) > > +{ > > + pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP); > > +} > > + > > +/* root control/capabilities/status. PME isn't emulated for now */ > > +void pcie_cap_root_init(PCIDevice *dev) > > +{ > > + pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL, > > + PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | > > + PCI_EXP_RTCTL_SEFEE); > > +} > > + > > +void pcie_cap_root_reset(PCIDevice *dev) > > +{ > > + pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0); > > +} > > + > > +/* function level reset(FLR) */ > > +void pcie_cap_flr_init(PCIDevice *dev) > > +{ > > + pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP, > > + PCI_EXP_DEVCAP_FLR); > > + > > + /* Although reading BCR_FLR returns always 0, > > + * the bit is made writable here in order to detect the 1b is written > > + * pcie_cap_flr_write_config() test-and-clear the bit, so > > + * this bit always returns 0 to the guest. > > + */ > > + pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL, > > + PCI_EXP_DEVCTL_BCR_FLR); > > +} > > + > > +void pcie_cap_flr_write_config(PCIDevice *dev, > > + uint32_t addr, uint32_t val, int len) > > +{ > > + uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; > > + if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) { > > + /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler > > + so the handler can detect FLR by looking at this bit. */ > > + pci_device_reset(dev); > > + pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR); > > + } > > +} > > + > > +/* Alternative Routing-ID Interpretation (ARI) */ > > +/* ari forwarding support for down stream port */ > > +void pcie_cap_ari_init(PCIDevice *dev) > > +{ > > + uint32_t pos = dev->exp.exp_cap; > > + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2, > > + PCI_EXP_DEVCAP2_ARI); > > + pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2, > > + PCI_EXP_DEVCTL2_ARI); > > +} > > + > > +void pcie_cap_ari_reset(PCIDevice *dev) > > +{ > > + uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2; > > + pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI); > > +} > > + > > +bool pcie_cap_is_ari_enabled(const PCIDevice *dev) > > +{ > > + if (!pci_is_express(dev)) { > > + return false; > > + } > > + if (!dev->exp.exp_cap) { > > + return false; > > + } > > + > > + return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & > > + PCI_EXP_DEVCTL2_ARI; > > +} > > + > > +/************************************************************************** > > + * pci express extended capability allocation functions > > + * uint16_t ext_cap_id (16 bit) > > + * uint8_t cap_ver (4 bit) > > + * uint16_t cap_offset (12 bit) > > + * uint16_t ext_cap_size > > + */ > > + > > +static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id, > > + uint16_t *prev_p) > > +{ > > + uint16_t prev = 0; > > + uint16_t next; > > + uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE); > > + > > + if (!header) { > > + /* no extended capability */ > > + next = 0; > > + goto out; > > + } > > + for (next = PCI_CONFIG_SPACE_SIZE; next; > > + prev = next, next = PCI_EXT_CAP_NEXT(header)) { > > + > > + assert(next >= PCI_CONFIG_SPACE_SIZE); > > + assert(next <= PCIE_CONFIG_SPACE_SIZE - 8); > > + > > + header = pci_get_long(dev->config + next); > > + if (PCI_EXT_CAP_ID(header) == cap_id) { > > + break; > > + } > > + } > > + > > +out: > > + if (prev_p) { > > + *prev_p = prev; > > + } > > + return next; > > +} > > + > > +uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id) > > +{ > > + return pcie_find_capability_list(dev, cap_id, NULL); > > +} > > + > > +static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next) > > +{ > > + uint16_t header = pci_get_long(dev->config + pos); > > + assert(!(next & (PCI_EXT_CAP_ALIGN - 1))); > > + header = (header & ~PCI_EXT_CAP_NEXT_MASK) | > > + ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK); > > + pci_set_long(dev->config + pos, header); > > +} > > + > > +/* > > + * caller must supply valid (offset, size) * such that the range shouldn't > > + * overlap with other capability or other registers. > > + * This function doesn't check it. > > + */ > > +void pcie_add_capability(PCIDevice *dev, > > + uint16_t cap_id, uint8_t cap_ver, > > + uint16_t offset, uint16_t size) > > +{ > > + uint32_t header; > > + uint16_t next; > > + > > + assert(offset >= PCI_CONFIG_SPACE_SIZE); > > + assert(offset < offset + size); > > + assert(offset + size < PCIE_CONFIG_SPACE_SIZE); > > + assert(size >= 8); > > + assert(pci_is_express(dev)); > > + > > + if (offset == PCI_CONFIG_SPACE_SIZE) { > > + header = pci_get_long(dev->config + offset); > > + next = PCI_EXT_CAP_NEXT(header); > > + } else { > > + uint16_t prev; > > + > > + /* 0 is reserved cap id. use internally to find the last capability > > + in the linked list */ > > + next = pcie_find_capability_list(dev, 0, &prev); > > + > > + assert(prev >= PCI_CONFIG_SPACE_SIZE); > > + assert(next == 0); > > + pcie_ext_cap_set_next(dev, prev, offset); > > + } > > + pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next)); > > + > > + /* Make capability read-only by default */ > > + memset(dev->wmask + offset, 0, size); > > + memset(dev->w1cmask + offset, 0, size); > > + /* Check capability by default */ > > + memset(dev->cmask + offset, 0xFF, size); > > +} > > + > > +/************************************************************************** > > + * pci express extended capability helper functions > > + */ > > + > > +/* ARI */ > > +void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn) > > +{ > > + pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER, > > + offset, PCI_ARI_SIZEOF); > > + pci_set_long(dev->config + offset + PCI_ARI_CAP, PCI_ARI_CAP_NFN(nextfn)); > > +} > > diff --git a/hw/pci/pcie.h b/hw/pci/pcie.h > > new file mode 100644 > > index 0000000..4889194 > > --- /dev/null > > +++ b/hw/pci/pcie.h > > @@ -0,0 +1,142 @@ > > +/* > > + * pcie.h > > + * > > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#ifndef QEMU_PCIE_H > > +#define QEMU_PCIE_H > > + > > +#include "hw.h" > > +#include "pci_regs.h" > > +#include "pcie_regs.h" > > +#include "pcie_aer.h" > > + > > +typedef enum { > > + /* for attention and power indicator */ > > + PCI_EXP_HP_IND_RESERVED = PCI_EXP_SLTCTL_IND_RESERVED, > > + PCI_EXP_HP_IND_ON = PCI_EXP_SLTCTL_IND_ON, > > + PCI_EXP_HP_IND_BLINK = PCI_EXP_SLTCTL_IND_BLINK, > > + PCI_EXP_HP_IND_OFF = PCI_EXP_SLTCTL_IND_OFF, > > +} PCIExpressIndicator; > > + > > +typedef enum { > > + /* these bits must match the bits in Slot Control/Status registers. > > + * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx > > + * > > + * Not all the bits of slot control register match with the ones of > > + * slot status. Not some bits of slot status register is used to > > + * show status, not to report event occurrence. > > + * So such bits must be masked out when checking the software > > + * notification condition. > > + */ > > + PCI_EXP_HP_EV_ABP = PCI_EXP_SLTCTL_ABPE, > > + /* attention button pressed */ > > + PCI_EXP_HP_EV_PDC = PCI_EXP_SLTCTL_PDCE, > > + /* presence detect changed */ > > + PCI_EXP_HP_EV_CCI = PCI_EXP_SLTCTL_CCIE, > > + /* command completed */ > > + > > + PCI_EXP_HP_EV_SUPPORTED = PCI_EXP_HP_EV_ABP | > > + PCI_EXP_HP_EV_PDC | > > + PCI_EXP_HP_EV_CCI, > > + /* supported event mask */ > > + > > + /* events not listed aren't supported */ > > +} PCIExpressHotPlugEvent; > > + > > +struct PCIExpressDevice { > > + /* Offset of express capability in config space */ > > + uint8_t exp_cap; > > + > > + /* SLOT */ > > + unsigned int hpev_intx; /* INTx for hot plug event (0-3:INT[A-D]#) > > + * default is 0 = INTA# > > + * If the chip wants to use other interrupt > > + * line, initialize this member with the > > + * desired number. > > + * If the chip dynamically changes this member, > > + * also initialize it when loaded as > > + * appropreately. > > + */ > > + bool hpev_notified; /* Logical AND of conditions for hot plug event. > > + Following 6.7.3.4: > > + Software Notification of Hot-Plug Events, an interrupt > > + is sent whenever the logical and of these conditions > > + transitions from false to true. */ > > + > > + /* AER */ > > + uint16_t aer_cap; > > + PCIEAERLog aer_log; > > + unsigned int aer_intx; /* INTx for error reporting > > + * default is 0 = INTA# > > + * If the chip wants to use other interrupt > > + * line, initialize this member with the > > + * desired number. > > + * If the chip dynamically changes this member, > > + * also initialize it when loaded as > > + * appropreately. > > + */ > > +}; > > + > > +/* PCI express capability helper functions */ > > +int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port); > > +void pcie_cap_exit(PCIDevice *dev); > > +uint8_t pcie_cap_get_type(const PCIDevice *dev); > > +void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector); > > +uint8_t pcie_cap_flags_get_vector(PCIDevice *dev); > > + > > +void pcie_cap_deverr_init(PCIDevice *dev); > > +void pcie_cap_deverr_reset(PCIDevice *dev); > > + > > +void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot); > > +void pcie_cap_slot_reset(PCIDevice *dev); > > +void pcie_cap_slot_write_config(PCIDevice *dev, > > + uint32_t addr, uint32_t val, int len); > > +int pcie_cap_slot_post_load(void *opaque, int version_id); > > +void pcie_cap_slot_push_attention_button(PCIDevice *dev); > > + > > +void pcie_cap_root_init(PCIDevice *dev); > > +void pcie_cap_root_reset(PCIDevice *dev); > > + > > +void pcie_cap_flr_init(PCIDevice *dev); > > +void pcie_cap_flr_write_config(PCIDevice *dev, > > + uint32_t addr, uint32_t val, int len); > > + > > +void pcie_cap_ari_init(PCIDevice *dev); > > +void pcie_cap_ari_reset(PCIDevice *dev); > > +bool pcie_cap_is_ari_enabled(const PCIDevice *dev); > > + > > +/* PCI express extended capability helper functions */ > > +uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id); > > +void pcie_add_capability(PCIDevice *dev, > > + uint16_t cap_id, uint8_t cap_ver, > > + uint16_t offset, uint16_t size); > > + > > +void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn); > > + > > +extern const VMStateDescription vmstate_pcie_device; > > + > > +#define VMSTATE_PCIE_DEVICE(_field, _state) { \ > > + .name = (stringify(_field)), \ > > + .size = sizeof(PCIDevice), \ > > + .vmsd = &vmstate_pcie_device, \ > > + .flags = VMS_STRUCT, \ > > + .offset = vmstate_offset_value(_state, _field, PCIDevice), \ > > +} > > + > > +#endif /* QEMU_PCIE_H */ > > diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c > > new file mode 100644 > > index 0000000..b04c164 > > --- /dev/null > > +++ b/hw/pci/pcie_aer.c > > @@ -0,0 +1,1032 @@ > > +/* > > + * pcie_aer.c > > + * > > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#include "sysemu.h" > > +#include "qemu-objects.h" > > +#include "monitor.h" > > +#include "pci_bridge.h" > > +#include "pcie.h" > > +#include "msix.h" > > +#include "msi.h" > > +#include "pci_internals.h" > > +#include "pcie_regs.h" > > + > > +//#define DEBUG_PCIE > > +#ifdef DEBUG_PCIE > > +# define PCIE_DPRINTF(fmt, ...) \ > > + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > > +#else > > +# define PCIE_DPRINTF(fmt, ...) do {} while (0) > > +#endif > > +#define PCIE_DEV_PRINTF(dev, fmt, ...) \ > > + PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > > + > > +#define PCI_ERR_SRC_COR_OFFS 0 > > +#define PCI_ERR_SRC_UNCOR_OFFS 2 > > + > > +/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */ > > +static uint32_t pcie_aer_uncor_default_severity(uint32_t status) > > +{ > > + switch (status) { > > + case PCI_ERR_UNC_INTN: > > + case PCI_ERR_UNC_DLP: > > + case PCI_ERR_UNC_SDN: > > + case PCI_ERR_UNC_RX_OVER: > > + case PCI_ERR_UNC_FCP: > > + case PCI_ERR_UNC_MALF_TLP: > > + return PCI_ERR_ROOT_CMD_FATAL_EN; > > + case PCI_ERR_UNC_POISON_TLP: > > + case PCI_ERR_UNC_ECRC: > > + case PCI_ERR_UNC_UNSUP: > > + case PCI_ERR_UNC_COMP_TIME: > > + case PCI_ERR_UNC_COMP_ABORT: > > + case PCI_ERR_UNC_UNX_COMP: > > + case PCI_ERR_UNC_ACSV: > > + case PCI_ERR_UNC_MCBTLP: > > + case PCI_ERR_UNC_ATOP_EBLOCKED: > > + case PCI_ERR_UNC_TLP_PRF_BLOCKED: > > + return PCI_ERR_ROOT_CMD_NONFATAL_EN; > > + default: > > + abort(); > > + break; > > + } > > + return PCI_ERR_ROOT_CMD_FATAL_EN; > > +} > > + > > +static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err) > > +{ > > + if (aer_log->log_num == aer_log->log_max) { > > + return -1; > > + } > > + memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err); > > + aer_log->log_num++; > > + return 0; > > +} > > + > > +static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err) > > +{ > > + assert(aer_log->log_num); > > + *err = aer_log->log[0]; > > + aer_log->log_num--; > > + memmove(&aer_log->log[0], &aer_log->log[1], > > + aer_log->log_num * sizeof *err); > > +} > > + > > +static void aer_log_clear_all_err(PCIEAERLog *aer_log) > > +{ > > + aer_log->log_num = 0; > > +} > > + > > +int pcie_aer_init(PCIDevice *dev, uint16_t offset) > > +{ > > + PCIExpressDevice *exp; > > + > > + pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER, > > + offset, PCI_ERR_SIZEOF); > > + exp = &dev->exp; > > + exp->aer_cap = offset; > > + > > + /* log_max is property */ > > + if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) { > > + dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT; > > + } > > + /* clip down the value to avoid unreasobale memory usage */ > > + if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) { > > + return -EINVAL; > > + } > > + dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] * > > + dev->exp.aer_log.log_max); > > + > > + pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS, > > + PCI_ERR_UNC_SUPPORTED); > > + > > + pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER, > > + PCI_ERR_UNC_SEVERITY_DEFAULT); > > + pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER, > > + PCI_ERR_UNC_SUPPORTED); > > + > > + pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS, > > + PCI_ERR_COR_STATUS); > > + > > + pci_set_long(dev->config + offset + PCI_ERR_COR_MASK, > > + PCI_ERR_COR_MASK_DEFAULT); > > + pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK, > > + PCI_ERR_COR_SUPPORTED); > > + > > + /* capabilities and control. multiple header logging is supported */ > > + if (dev->exp.aer_log.log_max > 0) { > > + pci_set_long(dev->config + offset + PCI_ERR_CAP, > > + PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC | > > + PCI_ERR_CAP_MHRC); > > + pci_set_long(dev->wmask + offset + PCI_ERR_CAP, > > + PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE | > > + PCI_ERR_CAP_MHRE); > > + } else { > > + pci_set_long(dev->config + offset + PCI_ERR_CAP, > > + PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC); > > + pci_set_long(dev->wmask + offset + PCI_ERR_CAP, > > + PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); > > + } > > + > > + switch (pcie_cap_get_type(dev)) { > > + case PCI_EXP_TYPE_ROOT_PORT: > > + /* this case will be set by pcie_aer_root_init() */ > > + /* fallthrough */ > > + case PCI_EXP_TYPE_DOWNSTREAM: > > + case PCI_EXP_TYPE_UPSTREAM: > > + pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL, > > + PCI_BRIDGE_CTL_SERR); > > + pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS, > > + PCI_SEC_STATUS_RCV_SYSTEM_ERROR); > > + break; > > + default: > > + /* nothing */ > > + break; > > + } > > + return 0; > > +} > > + > > +void pcie_aer_exit(PCIDevice *dev) > > +{ > > + g_free(dev->exp.aer_log.log); > > +} > > + > > +static void pcie_aer_update_uncor_status(PCIDevice *dev) > > +{ > > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > + PCIEAERLog *aer_log = &dev->exp.aer_log; > > + > > + uint16_t i; > > + for (i = 0; i < aer_log->log_num; i++) { > > + pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS, > > + dev->exp.aer_log.log[i].status); > > + } > > +} > > + > > +/* > > + * return value: > > + * true: error message needs to be sent up > > + * false: error message is masked > > + * > > + * 6.2.6 Error Message Control > > + * Figure 6-3 > > + * all pci express devices part > > + */ > > +static bool > > +pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg) > > +{ > > + if (!(pcie_aer_msg_is_uncor(msg) && > > + (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) { > > + return false; > > + } > > + > > + /* Signaled System Error > > + * > > + * 7.5.1.1 Command register > > + * Bit 8 SERR# Enable > > + * > > + * When Set, this bit enables reporting of Non-fatal and Fatal > > + * errors detected by the Function to the Root Complex. Note that > > + * errors are reported if enabled either through this bit or through > > + * the PCI Express specific bits in the Device Control register (see > > + * Section 7.8.4). > > + */ > > + pci_word_test_and_set_mask(dev->config + PCI_STATUS, > > + PCI_STATUS_SIG_SYSTEM_ERROR); > > + > > + if (!(msg->severity & > > + pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) { > > + return false; > > + } > > + > > + /* send up error message */ > > + return true; > > +} > > + > > +/* > > + * return value: > > + * true: error message is sent up > > + * false: error message is masked > > + * > > + * 6.2.6 Error Message Control > > + * Figure 6-3 > > + * virtual pci bridge part > > + */ > > +static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg) > > +{ > > + uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL); > > + > > + if (pcie_aer_msg_is_uncor(msg)) { > > + /* Received System Error */ > > + pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS, > > + PCI_SEC_STATUS_RCV_SYSTEM_ERROR); > > + } > > + > > + if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) { > > + return false; > > + } > > + return true; > > +} > > + > > +void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector) > > +{ > > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > + assert(vector < PCI_ERR_ROOT_IRQ_MAX); > > + pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS, > > + PCI_ERR_ROOT_IRQ); > > + pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS, > > + vector << PCI_ERR_ROOT_IRQ_SHIFT); > > +} > > + > > +static unsigned int pcie_aer_root_get_vector(PCIDevice *dev) > > +{ > > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > + uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > > + return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT; > > +} > > + > > +/* Given a status register, get corresponding bits in the command register */ > > +static uint32_t pcie_aer_status_to_cmd(uint32_t status) > > +{ > > + uint32_t cmd = 0; > > + if (status & PCI_ERR_ROOT_COR_RCV) { > > + cmd |= PCI_ERR_ROOT_CMD_COR_EN; > > + } > > + if (status & PCI_ERR_ROOT_NONFATAL_RCV) { > > + cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN; > > + } > > + if (status & PCI_ERR_ROOT_FATAL_RCV) { > > + cmd |= PCI_ERR_ROOT_CMD_FATAL_EN; > > + } > > + return cmd; > > +} > > + > > +static void pcie_aer_root_notify(PCIDevice *dev) > > +{ > > + if (msix_enabled(dev)) { > > + msix_notify(dev, pcie_aer_root_get_vector(dev)); > > + } else if (msi_enabled(dev)) { > > + msi_notify(dev, pcie_aer_root_get_vector(dev)); > > + } else { > > + qemu_set_irq(dev->irq[dev->exp.aer_intx], 1); > > + } > > +} > > + > > +/* > > + * 6.2.6 Error Message Control > > + * Figure 6-3 > > + * root port part > > + */ > > +static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg) > > +{ > > + uint16_t cmd; > > + uint8_t *aer_cap; > > + uint32_t root_cmd; > > + uint32_t root_status, prev_status; > > + > > + cmd = pci_get_word(dev->config + PCI_COMMAND); > > + aer_cap = dev->config + dev->exp.aer_cap; > > + root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); > > + prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > > + > > + if (cmd & PCI_COMMAND_SERR) { > > + /* System Error. > > + * > > + * The way to report System Error is platform specific and > > + * it isn't implemented in qemu right now. > > + * So just discard the error for now. > > + * OS which cares of aer would receive errors via > > + * native aer mechanims, so this wouldn't matter. > > + */ > > + } > > + > > + /* Errro Message Received: Root Error Status register */ > > + switch (msg->severity) { > > + case PCI_ERR_ROOT_CMD_COR_EN: > > + if (root_status & PCI_ERR_ROOT_COR_RCV) { > > + root_status |= PCI_ERR_ROOT_MULTI_COR_RCV; > > + } else { > > + pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SRC_COR_OFFS, > > + msg->source_id); > > + } > > + root_status |= PCI_ERR_ROOT_COR_RCV; > > + break; > > + case PCI_ERR_ROOT_CMD_NONFATAL_EN: > > + root_status |= PCI_ERR_ROOT_NONFATAL_RCV; > > + break; > > + case PCI_ERR_ROOT_CMD_FATAL_EN: > > + if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) { > > + root_status |= PCI_ERR_ROOT_FIRST_FATAL; > > + } > > + root_status |= PCI_ERR_ROOT_FATAL_RCV; > > + break; > > + default: > > + abort(); > > + break; > > + } > > + if (pcie_aer_msg_is_uncor(msg)) { > > + if (root_status & PCI_ERR_ROOT_UNCOR_RCV) { > > + root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV; > > + } else { > > + pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + > > + PCI_ERR_SRC_UNCOR_OFFS, msg->source_id); > > + } > > + root_status |= PCI_ERR_ROOT_UNCOR_RCV; > > + } > > + pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status); > > + > > + /* 6.2.4.1.2 Interrupt Generation */ > > + /* All the above did was set some bits in the status register. > > + * Specifically these that match message severity. > > + * The below code relies on this fact. */ > > + if (!(root_cmd & msg->severity) || > > + (pcie_aer_status_to_cmd(prev_status) & root_cmd)) { > > + /* Condition is not being set or was already true so nothing to do. */ > > + return; > > + } > > + > > + pcie_aer_root_notify(dev); > > +} > > + > > +/* > > + * 6.2.6 Error Message Control Figure 6-3 > > + * > > + * Walk up the bus tree from the device, propagate the error message. > > + */ > > +static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) > > +{ > > + uint8_t type; > > + > > + while (dev) { > > + if (!pci_is_express(dev)) { > > + /* just ignore it */ > > + /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR? > > + * Consider e.g. a PCI bridge above a PCI Express device. */ > > + return; > > + } > > + > > + type = pcie_cap_get_type(dev); > > + if ((type == PCI_EXP_TYPE_ROOT_PORT || > > + type == PCI_EXP_TYPE_UPSTREAM || > > + type == PCI_EXP_TYPE_DOWNSTREAM) && > > + !pcie_aer_msg_vbridge(dev, msg)) { > > + return; > > + } > > + if (!pcie_aer_msg_alldev(dev, msg)) { > > + return; > > + } > > + if (type == PCI_EXP_TYPE_ROOT_PORT) { > > + pcie_aer_msg_root_port(dev, msg); > > + /* Root port can notify system itself, > > + or send the error message to root complex event collector. */ > > + /* > > + * if root port is associated with an event collector, > > + * return the root complex event collector here. > > + * For now root complex event collector isn't supported. > > + */ > > + return; > > + } > > + dev = pci_bridge_get_device(dev->bus); > > + } > > +} > > + > > +static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err) > > +{ > > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > + uint8_t first_bit = ffs(err->status) - 1; > > + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > > + int i; > > + > > + assert(err->status); > > + assert(!(err->status & (err->status - 1))); > > + > > + errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); > > + errcap |= PCI_ERR_CAP_FEP(first_bit); > > + > > + if (err->flags & PCIE_AER_ERR_HEADER_VALID) { > > + for (i = 0; i < ARRAY_SIZE(err->header); ++i) { > > + /* 7.10.8 Header Log Register */ > > + uint8_t *header_log = > > + aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0]; > > + cpu_to_be32wu((uint32_t*)header_log, err->header[i]); > > + } > > + } else { > > + assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT)); > > + memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); > > + } > > + > > + if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) && > > + (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & > > + PCI_EXP_DEVCAP2_EETLPP)) { > > + for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) { > > + /* 7.10.12 tlp prefix log register */ > > + uint8_t *prefix_log = > > + aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0]; > > + cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]); > > + } > > + errcap |= PCI_ERR_CAP_TLP; > > + } else { > > + memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, > > + PCI_ERR_TLP_PREFIX_LOG_SIZE); > > + } > > + pci_set_long(aer_cap + PCI_ERR_CAP, errcap); > > +} > > + > > +static void pcie_aer_clear_log(PCIDevice *dev) > > +{ > > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > + > > + pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP, > > + PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); > > + > > + memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); > > + memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE); > > +} > > + > > +static void pcie_aer_clear_error(PCIDevice *dev) > > +{ > > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > > + PCIEAERLog *aer_log = &dev->exp.aer_log; > > + PCIEAERErr err; > > + > > + if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) { > > + pcie_aer_clear_log(dev); > > + return; > > + } > > + > > + /* > > + * If more errors are queued, set corresponding bits in uncorrectable > > + * error status. > > + * We emulate uncorrectable error status register as W1CS. > > + * So set bit in uncorrectable error status here again for multiple > > + * error recording support. > > + * > > + * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability) > > + */ > > + pcie_aer_update_uncor_status(dev); > > + > > + aer_log_del_err(aer_log, &err); > > + pcie_aer_update_log(dev, &err); > > +} > > + > > +static int pcie_aer_record_error(PCIDevice *dev, > > + const PCIEAERErr *err) > > +{ > > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > > + int fep = PCI_ERR_CAP_FEP(errcap); > > + > > + assert(err->status); > > + assert(!(err->status & (err->status - 1))); > > + > > + if (errcap & PCI_ERR_CAP_MHRE && > > + (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) { > > + /* Not first error. queue error */ > > + if (aer_log_add_err(&dev->exp.aer_log, err) < 0) { > > + /* overflow */ > > + return -1; > > + } > > + return 0; > > + } > > + > > + pcie_aer_update_log(dev, err); > > + return 0; > > +} > > + > > +typedef struct PCIEAERInject { > > + PCIDevice *dev; > > + uint8_t *aer_cap; > > + const PCIEAERErr *err; > > + uint16_t devctl; > > + uint16_t devsta; > > + uint32_t error_status; > > + bool unsupported_request; > > + bool log_overflow; > > + PCIEAERMsg msg; > > +} PCIEAERInject; > > + > > +static bool pcie_aer_inject_cor_error(PCIEAERInject *inj, > > + uint32_t uncor_status, > > + bool is_advisory_nonfatal) > > +{ > > + PCIDevice *dev = inj->dev; > > + > > + inj->devsta |= PCI_EXP_DEVSTA_CED; > > + if (inj->unsupported_request) { > > + inj->devsta |= PCI_EXP_DEVSTA_URD; > > + } > > + pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); > > + > > + if (inj->aer_cap) { > > + uint32_t mask; > > + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS, > > + inj->error_status); > > + mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK); > > + if (mask & inj->error_status) { > > + return false; > > + } > > + if (is_advisory_nonfatal) { > > + uint32_t uncor_mask = > > + pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); > > + if (!(uncor_mask & uncor_status)) { > > + inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); > > + } > > + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > > + uncor_status); > > + } > > + } > > + > > + if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) { > > + return false; > > + } > > + if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) { > > + return false; > > + } > > + > > + inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN; > > + return true; > > +} > > + > > +static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal) > > +{ > > + PCIDevice *dev = inj->dev; > > + uint16_t cmd; > > + > > + if (is_fatal) { > > + inj->devsta |= PCI_EXP_DEVSTA_FED; > > + } else { > > + inj->devsta |= PCI_EXP_DEVSTA_NFED; > > + } > > + if (inj->unsupported_request) { > > + inj->devsta |= PCI_EXP_DEVSTA_URD; > > + } > > + pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); > > + > > + if (inj->aer_cap) { > > + uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); > > + if (mask & inj->error_status) { > > + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > > + inj->error_status); > > + return false; > > + } > > + > > + inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); > > + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > > + inj->error_status); > > + } > > + > > + cmd = pci_get_word(dev->config + PCI_COMMAND); > > + if (inj->unsupported_request && > > + !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) { > > + return false; > > + } > > + if (is_fatal) { > > + if (!((cmd & PCI_COMMAND_SERR) || > > + (inj->devctl & PCI_EXP_DEVCTL_FERE))) { > > + return false; > > + } > > + inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN; > > + } else { > > + if (!((cmd & PCI_COMMAND_SERR) || > > + (inj->devctl & PCI_EXP_DEVCTL_NFERE))) { > > + return false; > > + } > > + inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN; > > + } > > + return true; > > +} > > + > > +/* > > + * non-Function specific error must be recorded in all functions. > > + * It is the responsibility of the caller of this function. > > + * It is also caller's responsibility to determine which function should > > + * report the rerror. > > + * > > + * 6.2.4 Error Logging > > + * 6.2.5 Sqeunce of Device Error Signaling and Logging Operations > > + * table 6-2: Flowchard Showing Sequence of Device Error Signaling and Logging > > + * Operations > > + */ > > +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err) > > +{ > > + uint8_t *aer_cap = NULL; > > + uint16_t devctl = 0; > > + uint16_t devsta = 0; > > + uint32_t error_status = err->status; > > + PCIEAERInject inj; > > + > > + if (!pci_is_express(dev)) { > > + return -ENOSYS; > > + } > > + > > + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > > + error_status &= PCI_ERR_COR_SUPPORTED; > > + } else { > > + error_status &= PCI_ERR_UNC_SUPPORTED; > > + } > > + > > + /* invalid status bit. one and only one bit must be set */ > > + if (!error_status || (error_status & (error_status - 1))) { > > + return -EINVAL; > > + } > > + > > + if (dev->exp.aer_cap) { > > + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > > + aer_cap = dev->config + dev->exp.aer_cap; > > + devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL); > > + devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA); > > + } > > + > > + inj.dev = dev; > > + inj.aer_cap = aer_cap; > > + inj.err = err; > > + inj.devctl = devctl; > > + inj.devsta = devsta; > > + inj.error_status = error_status; > > + inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) && > > + err->status == PCI_ERR_UNC_UNSUP; > > + inj.log_overflow = false; > > + > > + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > > + if (!pcie_aer_inject_cor_error(&inj, 0, false)) { > > + return 0; > > + } > > + } else { > > + bool is_fatal = > > + pcie_aer_uncor_default_severity(error_status) == > > + PCI_ERR_ROOT_CMD_FATAL_EN; > > + if (aer_cap) { > > + is_fatal = > > + error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER); > > + } > > + if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) { > > + inj.error_status = PCI_ERR_COR_ADV_NONFATAL; > > + if (!pcie_aer_inject_cor_error(&inj, error_status, true)) { > > + return 0; > > + } > > + } else { > > + if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) { > > + return 0; > > + } > > + } > > + } > > + > > + /* send up error message */ > > + inj.msg.source_id = err->source_id; > > + pcie_aer_msg(dev, &inj.msg); > > + > > + if (inj.log_overflow) { > > + PCIEAERErr header_log_overflow = { > > + .status = PCI_ERR_COR_HL_OVERFLOW, > > + .flags = PCIE_AER_ERR_IS_CORRECTABLE, > > + }; > > + int ret = pcie_aer_inject_error(dev, &header_log_overflow); > > + assert(!ret); > > + } > > + return 0; > > +} > > + > > +void pcie_aer_write_config(PCIDevice *dev, > > + uint32_t addr, uint32_t val, int len) > > +{ > > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > > + uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap); > > + uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS); > > + > > + /* uncorrectable error */ > > + if (!(uncorsta & first_error)) { > > + /* the bit that corresponds to the first error is cleared */ > > + pcie_aer_clear_error(dev); > > + } else if (errcap & PCI_ERR_CAP_MHRE) { > > + /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared > > + * nothing should happen. So we have to revert the modification to > > + * the register. > > + */ > > + pcie_aer_update_uncor_status(dev); > > + } else { > > + /* capability & control > > + * PCI_ERR_CAP_MHRE might be cleared, so clear of header log. > > + */ > > + aer_log_clear_all_err(&dev->exp.aer_log); > > + } > > +} > > + > > +void pcie_aer_root_init(PCIDevice *dev) > > +{ > > + uint16_t pos = dev->exp.aer_cap; > > + > > + pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND, > > + PCI_ERR_ROOT_CMD_EN_MASK); > > + pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS, > > + PCI_ERR_ROOT_STATUS_REPORT_MASK); > > + /* PCI_ERR_ROOT_IRQ is RO but devices change it using a > > + * device-specific method. > > + */ > > + pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS, > > + ~PCI_ERR_ROOT_IRQ); > > +} > > + > > +void pcie_aer_root_reset(PCIDevice *dev) > > +{ > > + uint8_t* aer_cap = dev->config + dev->exp.aer_cap; > > + > > + pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0); > > + > > + /* > > + * Advanced Error Interrupt Message Number in Root Error Status Register > > + * must be updated by chip dependent code because it's chip dependent > > + * which number is used. > > + */ > > +} > > + > > +void pcie_aer_root_write_config(PCIDevice *dev, > > + uint32_t addr, uint32_t val, int len, > > + uint32_t root_cmd_prev) > > +{ > > + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > + uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > > + uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status); > > + uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); > > + /* 6.2.4.1.2 Interrupt Generation */ > > + if (!msix_enabled(dev) && !msi_enabled(dev)) { > > + qemu_set_irq(dev->irq[dev->exp.aer_intx], !!(root_cmd & enabled_cmd)); > > + return; > > + } > > + > > + if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) { > > + /* Send MSI on transition from false to true. */ > > + return; > > + } > > + > > + pcie_aer_root_notify(dev); > > +} > > + > > +static const VMStateDescription vmstate_pcie_aer_err = { > > + .name = "PCIE_AER_ERROR", > > + .version_id = 1, > > + .minimum_version_id = 1, > > + .minimum_version_id_old = 1, > > + .fields = (VMStateField[]) { > > + VMSTATE_UINT32(status, PCIEAERErr), > > + VMSTATE_UINT16(source_id, PCIEAERErr), > > + VMSTATE_UINT16(flags, PCIEAERErr), > > + VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4), > > + VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4), > > + VMSTATE_END_OF_LIST() > > + } > > +}; > > + > > +const VMStateDescription vmstate_pcie_aer_log = { > > + .name = "PCIE_AER_ERROR_LOG", > > + .version_id = 1, > > + .minimum_version_id = 1, > > + .minimum_version_id_old = 1, > > + .fields = (VMStateField[]) { > > + VMSTATE_UINT16(log_num, PCIEAERLog), > > + VMSTATE_UINT16(log_max, PCIEAERLog), > > + VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num, > > + vmstate_pcie_aer_err, PCIEAERErr), > > + VMSTATE_END_OF_LIST() > > + } > > +}; > > + > > +void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) > > +{ > > + QDict *qdict; > > + int devfn; > > + assert(qobject_type(data) == QTYPE_QDICT); > > + qdict = qobject_to_qdict(data); > > + > > + devfn = (int)qdict_get_int(qdict, "devfn"); > > + monitor_printf(mon, "OK id: %s domain: %x, bus: %x devfn: %x.%x\n", > > + qdict_get_str(qdict, "id"), > > + (int) qdict_get_int(qdict, "domain"), > > + (int) qdict_get_int(qdict, "bus"), > > + PCI_SLOT(devfn), PCI_FUNC(devfn)); > > +} > > + > > +typedef struct PCIEAERErrorName { > > + const char *name; > > + uint32_t val; > > + bool correctable; > > +} PCIEAERErrorName; > > + > > +/* > > + * AER error name -> value conversion table > > + * This naming scheme is same to linux aer-injection tool. > > + */ > > +static const struct PCIEAERErrorName pcie_aer_error_list[] = { > > + { > > + .name = "TRAIN", > > + .val = PCI_ERR_UNC_TRAIN, > > + .correctable = false, > > + }, { > > + .name = "DLP", > > + .val = PCI_ERR_UNC_DLP, > > + .correctable = false, > > + }, { > > + .name = "SDN", > > + .val = PCI_ERR_UNC_SDN, > > + .correctable = false, > > + }, { > > + .name = "POISON_TLP", > > + .val = PCI_ERR_UNC_POISON_TLP, > > + .correctable = false, > > + }, { > > + .name = "FCP", > > + .val = PCI_ERR_UNC_FCP, > > + .correctable = false, > > + }, { > > + .name = "COMP_TIME", > > + .val = PCI_ERR_UNC_COMP_TIME, > > + .correctable = false, > > + }, { > > + .name = "COMP_ABORT", > > + .val = PCI_ERR_UNC_COMP_ABORT, > > + .correctable = false, > > + }, { > > + .name = "UNX_COMP", > > + .val = PCI_ERR_UNC_UNX_COMP, > > + .correctable = false, > > + }, { > > + .name = "RX_OVER", > > + .val = PCI_ERR_UNC_RX_OVER, > > + .correctable = false, > > + }, { > > + .name = "MALF_TLP", > > + .val = PCI_ERR_UNC_MALF_TLP, > > + .correctable = false, > > + }, { > > + .name = "ECRC", > > + .val = PCI_ERR_UNC_ECRC, > > + .correctable = false, > > + }, { > > + .name = "UNSUP", > > + .val = PCI_ERR_UNC_UNSUP, > > + .correctable = false, > > + }, { > > + .name = "ACSV", > > + .val = PCI_ERR_UNC_ACSV, > > + .correctable = false, > > + }, { > > + .name = "INTN", > > + .val = PCI_ERR_UNC_INTN, > > + .correctable = false, > > + }, { > > + .name = "MCBTLP", > > + .val = PCI_ERR_UNC_MCBTLP, > > + .correctable = false, > > + }, { > > + .name = "ATOP_EBLOCKED", > > + .val = PCI_ERR_UNC_ATOP_EBLOCKED, > > + .correctable = false, > > + }, { > > + .name = "TLP_PRF_BLOCKED", > > + .val = PCI_ERR_UNC_TLP_PRF_BLOCKED, > > + .correctable = false, > > + }, { > > + .name = "RCVR", > > + .val = PCI_ERR_COR_RCVR, > > + .correctable = true, > > + }, { > > + .name = "BAD_TLP", > > + .val = PCI_ERR_COR_BAD_TLP, > > + .correctable = true, > > + }, { > > + .name = "BAD_DLLP", > > + .val = PCI_ERR_COR_BAD_DLLP, > > + .correctable = true, > > + }, { > > + .name = "REP_ROLL", > > + .val = PCI_ERR_COR_REP_ROLL, > > + .correctable = true, > > + }, { > > + .name = "REP_TIMER", > > + .val = PCI_ERR_COR_REP_TIMER, > > + .correctable = true, > > + }, { > > + .name = "ADV_NONFATAL", > > + .val = PCI_ERR_COR_ADV_NONFATAL, > > + .correctable = true, > > + }, { > > + .name = "INTERNAL", > > + .val = PCI_ERR_COR_INTERNAL, > > + .correctable = true, > > + }, { > > + .name = "HL_OVERFLOW", > > + .val = PCI_ERR_COR_HL_OVERFLOW, > > + .correctable = true, > > + }, > > +}; > > + > > +static int pcie_aer_parse_error_string(const char *error_name, > > + uint32_t *status, bool *correctable) > > +{ > > + int i; > > + > > + for (i = 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) { > > + const PCIEAERErrorName *e = &pcie_aer_error_list[i]; > > + if (strcmp(error_name, e->name)) { > > + continue; > > + } > > + > > + *status = e->val; > > + *correctable = e->correctable; > > + return 0; > > + } > > + return -EINVAL; > > +} > > + > > +int do_pcie_aer_inject_error(Monitor *mon, > > + const QDict *qdict, QObject **ret_data) > > +{ > > + const char *id = qdict_get_str(qdict, "id"); > > + const char *error_name; > > + uint32_t error_status; > > + bool correctable; > > + PCIDevice *dev; > > + PCIEAERErr err; > > + int ret; > > + > > + ret = pci_qdev_find_device(id, &dev); > > + if (ret < 0) { > > + monitor_printf(mon, > > + "id or pci device path is invalid or device not " > > + "found. %s\n", id); > > + return ret; > > + } > > + if (!pci_is_express(dev)) { > > + monitor_printf(mon, "the device doesn't support pci express. %s\n", > > + id); > > + return -ENOSYS; > > + } > > + > > + error_name = qdict_get_str(qdict, "error_status"); > > + if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) { > > + char *e = NULL; > > + error_status = strtoul(error_name, &e, 0); > > + correctable = qdict_get_try_bool(qdict, "correctable", 0); > > + if (!e || *e != '\0') { > > + monitor_printf(mon, "invalid error status value. \"%s\"", > > + error_name); > > + return -EINVAL; > > + } > > + } > > + err.status = error_status; > > + err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn; > > + > > + err.flags = 0; > > + if (correctable) { > > + err.flags |= PCIE_AER_ERR_IS_CORRECTABLE; > > + } > > + if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) { > > + err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY; > > + } > > + if (qdict_haskey(qdict, "header0")) { > > + err.flags |= PCIE_AER_ERR_HEADER_VALID; > > + } > > + if (qdict_haskey(qdict, "prefix0")) { > > + err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT; > > + } > > + > > + err.header[0] = qdict_get_try_int(qdict, "header0", 0); > > + err.header[1] = qdict_get_try_int(qdict, "header1", 0); > > + err.header[2] = qdict_get_try_int(qdict, "header2", 0); > > + err.header[3] = qdict_get_try_int(qdict, "header3", 0); > > + > > + err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0); > > + err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0); > > + err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0); > > + err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0); > > + > > + ret = pcie_aer_inject_error(dev, &err); > > + *ret_data = qobject_from_jsonf("{'id': %s, " > > + "'domain': %d, 'bus': %d, 'devfn': %d, " > > + "'ret': %d}", > > + id, > > + pci_find_domain(dev->bus), > > + pci_bus_num(dev->bus), dev->devfn, > > + ret); > > + assert(*ret_data); > > + > > + return 0; > > +} > > diff --git a/hw/pci/pcie_aer.h b/hw/pci/pcie_aer.h > > new file mode 100644 > > index 0000000..7539500 > > --- /dev/null > > +++ b/hw/pci/pcie_aer.h > > @@ -0,0 +1,106 @@ > > +/* > > + * pcie_aer.h > > + * > > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#ifndef QEMU_PCIE_AER_H > > +#define QEMU_PCIE_AER_H > > + > > +#include "hw.h" > > + > > +/* definitions which PCIExpressDevice uses */ > > + > > +/* AER log */ > > +struct PCIEAERLog { > > + /* This structure is saved/loaded. > > + So explicitly size them instead of unsigned int */ > > + > > + /* the number of currently recorded log in log member */ > > + uint16_t log_num; > > + > > + /* > > + * The maximum number of the log. Errors can be logged up to this. > > + * > > + * This is configurable property. > > + * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT > > + * to avoid unreasonable memory usage. > > + * I bet that 128 log size would be big enough, otherwise too many errors > > + * for system to function normaly. But could consecutive errors occur? > > + */ > > +#define PCIE_AER_LOG_MAX_DEFAULT 8 > > +#define PCIE_AER_LOG_MAX_LIMIT 128 > > +#define PCIE_AER_LOG_MAX_UNSET 0xffff > > + uint16_t log_max; > > + > > + /* Error log. log_max-sized array */ > > + PCIEAERErr *log; > > +}; > > + > > +/* aer error message: error signaling message has only error sevirity and > > + source id. See 2.2.8.3 error signaling messages */ > > +struct PCIEAERMsg { > > + /* > > + * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN > > + * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE} > > + */ > > + uint32_t severity; > > + > > + uint16_t source_id; /* bdf */ > > +}; > > + > > +static inline bool > > +pcie_aer_msg_is_uncor(const PCIEAERMsg *msg) > > +{ > > + return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN || > > + msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN; > > +} > > + > > +/* error */ > > +struct PCIEAERErr { > > + uint32_t status; /* error status bits */ > > + uint16_t source_id; /* bdf */ > > + > > +#define PCIE_AER_ERR_IS_CORRECTABLE 0x1 /* correctable/uncorrectable */ > > +#define PCIE_AER_ERR_MAYBE_ADVISORY 0x2 /* maybe advisory non-fatal */ > > +#define PCIE_AER_ERR_HEADER_VALID 0x4 /* TLP header is logged */ > > +#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8 /* TLP Prefix is logged */ > > + uint16_t flags; > > + > > + uint32_t header[4]; /* TLP header */ > > + uint32_t prefix[4]; /* TLP header prefix */ > > +}; > > + > > +extern const VMStateDescription vmstate_pcie_aer_log; > > + > > +int pcie_aer_init(PCIDevice *dev, uint16_t offset); > > +void pcie_aer_exit(PCIDevice *dev); > > +void pcie_aer_write_config(PCIDevice *dev, > > + uint32_t addr, uint32_t val, int len); > > + > > +/* aer root port */ > > +void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector); > > +void pcie_aer_root_init(PCIDevice *dev); > > +void pcie_aer_root_reset(PCIDevice *dev); > > +void pcie_aer_root_write_config(PCIDevice *dev, > > + uint32_t addr, uint32_t val, int len, > > + uint32_t root_cmd_prev); > > + > > +/* error injection */ > > +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err); > > + > > +#endif /* QEMU_PCIE_AER_H */ > > diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c > > new file mode 100644 > > index 0000000..c257fb4 > > --- /dev/null > > +++ b/hw/pci/pcie_host.c > > @@ -0,0 +1,161 @@ > > +/* > > + * pcie_host.c > > + * utility functions for pci express host bridge. > > + * > > + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#include "hw.h" > > +#include "pci.h" > > +#include "pcie_host.h" > > +#include "exec-memory.h" > > + > > +/* > > + * PCI express mmcfig address > > + * bit 20 - 28: bus number > > + * bit 15 - 19: device number > > + * bit 12 - 14: function number > > + * bit 0 - 11: offset in configuration space of a given device > > + */ > > +#define PCIE_MMCFG_SIZE_MAX (1ULL << 28) > > +#define PCIE_MMCFG_SIZE_MIN (1ULL << 20) > > +#define PCIE_MMCFG_BUS_BIT 20 > > +#define PCIE_MMCFG_BUS_MASK 0x1ff > > +#define PCIE_MMCFG_DEVFN_BIT 12 > > +#define PCIE_MMCFG_DEVFN_MASK 0xff > > +#define PCIE_MMCFG_CONFOFFSET_MASK 0xfff > > +#define PCIE_MMCFG_BUS(addr) (((addr) >> PCIE_MMCFG_BUS_BIT) & \ > > + PCIE_MMCFG_BUS_MASK) > > +#define PCIE_MMCFG_DEVFN(addr) (((addr) >> PCIE_MMCFG_DEVFN_BIT) & \ > > + PCIE_MMCFG_DEVFN_MASK) > > +#define PCIE_MMCFG_CONFOFFSET(addr) ((addr) & PCIE_MMCFG_CONFOFFSET_MASK) > > + > > + > > +/* a helper function to get a PCIDevice for a given mmconfig address */ > > +static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, > > + uint32_t mmcfg_addr) > > +{ > > + return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), > > + PCIE_MMCFG_DEVFN(mmcfg_addr)); > > +} > > + > > +static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr, > > + uint64_t val, unsigned len) > > +{ > > + PCIExpressHost *e = opaque; > > + PCIBus *s = e->pci.bus; > > + PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); > > + uint32_t addr; > > + uint32_t limit; > > + > > + if (!pci_dev) { > > + return; > > + } > > + addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > > + limit = pci_config_size(pci_dev); > > + if (limit <= addr) { > > + /* conventional pci device can be behind pcie-to-pci bridge. > > + 256 <= addr < 4K has no effects. */ > > + return; > > + } > > + pci_host_config_write_common(pci_dev, addr, limit, val, len); > > +} > > + > > +static uint64_t pcie_mmcfg_data_read(void *opaque, > > + hwaddr mmcfg_addr, > > + unsigned len) > > +{ > > + PCIExpressHost *e = opaque; > > + PCIBus *s = e->pci.bus; > > + PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); > > + uint32_t addr; > > + uint32_t limit; > > + > > + if (!pci_dev) { > > + return ~0x0; > > + } > > + addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > > + limit = pci_config_size(pci_dev); > > + if (limit <= addr) { > > + /* conventional pci device can be behind pcie-to-pci bridge. > > + 256 <= addr < 4K has no effects. */ > > + return ~0x0; > > + } > > + return pci_host_config_read_common(pci_dev, addr, limit, len); > > +} > > + > > +static const MemoryRegionOps pcie_mmcfg_ops = { > > + .read = pcie_mmcfg_data_read, > > + .write = pcie_mmcfg_data_write, > > + .endianness = DEVICE_NATIVE_ENDIAN, > > +}; > > + > > +/* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */ > > +#define PCIE_BASE_ADDR_UNMAPPED ((hwaddr)-1ULL) > > + > > +int pcie_host_init(PCIExpressHost *e) > > +{ > > + e->base_addr = PCIE_BASE_ADDR_UNMAPPED; > > + > > + return 0; > > +} > > + > > +void pcie_host_mmcfg_unmap(PCIExpressHost *e) > > +{ > > + if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { > > + memory_region_del_subregion(get_system_memory(), &e->mmio); > > + memory_region_destroy(&e->mmio); > > + e->base_addr = PCIE_BASE_ADDR_UNMAPPED; > > + } > > +} > > + > > +void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, > > + uint32_t size) > > +{ > > + assert(!(size & (size - 1))); /* power of 2 */ > > + assert(size >= PCIE_MMCFG_SIZE_MIN); > > + assert(size <= PCIE_MMCFG_SIZE_MAX); > > + e->size = size; > > + memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size); > > + e->base_addr = addr; > > + memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio); > > +} > > + > > +void pcie_host_mmcfg_update(PCIExpressHost *e, > > + int enable, > > + hwaddr addr, > > + uint32_t size) > > +{ > > + pcie_host_mmcfg_unmap(e); > > + if (enable) { > > + pcie_host_mmcfg_map(e, addr, size); > > + } > > +} > > + > > +static const TypeInfo pcie_host_type_info = { > > + .name = TYPE_PCIE_HOST_BRIDGE, > > + .parent = TYPE_PCI_HOST_BRIDGE, > > + .abstract = true, > > + .instance_size = sizeof(PCIExpressHost), > > +}; > > + > > +static void pcie_host_register_types(void) > > +{ > > + type_register_static(&pcie_host_type_info); > > +} > > + > > +type_init(pcie_host_register_types) > > diff --git a/hw/pci/pcie_host.h b/hw/pci/pcie_host.h > > new file mode 100644 > > index 0000000..3921935 > > --- /dev/null > > +++ b/hw/pci/pcie_host.h > > @@ -0,0 +1,54 @@ > > +/* > > + * pcie_host.h > > + * > > + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#ifndef PCIE_HOST_H > > +#define PCIE_HOST_H > > + > > +#include "pci_host.h" > > +#include "memory.h" > > + > > +#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge" > > +#define PCIE_HOST_BRIDGE(obj) \ > > + OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE) > > + > > +struct PCIExpressHost { > > + PCIHostState pci; > > + > > + /* express part */ > > + > > + /* base address where MMCONFIG area is mapped. */ > > + hwaddr base_addr; > > + > > + /* the size of MMCONFIG area. It's host bridge dependent */ > > + hwaddr size; > > + > > + /* MMCONFIG mmio area */ > > + MemoryRegion mmio; > > +}; > > + > > +int pcie_host_init(PCIExpressHost *e); > > +void pcie_host_mmcfg_unmap(PCIExpressHost *e); > > +void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size); > > +void pcie_host_mmcfg_update(PCIExpressHost *e, > > + int enable, > > + hwaddr addr, > > + uint32_t size); > > + > > +#endif /* PCIE_HOST_H */ > > diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c > > new file mode 100644 > > index 0000000..d6350e5 > > --- /dev/null > > +++ b/hw/pci/pcie_port.c > > @@ -0,0 +1,114 @@ > > +/* > > + * pcie_port.c > > + * > > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#include "pcie_port.h" > > + > > +void pcie_port_init_reg(PCIDevice *d) > > +{ > > + /* Unlike pci bridge, > > + 66MHz and fast back to back don't apply to pci express port. */ > > + pci_set_word(d->config + PCI_STATUS, 0); > > + pci_set_word(d->config + PCI_SEC_STATUS, 0); > > + > > + /* Unlike conventional pci bridge, some bits are hardwired to 0. */ > > + pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, > > + PCI_BRIDGE_CTL_PARITY | > > + PCI_BRIDGE_CTL_ISA | > > + PCI_BRIDGE_CTL_VGA | > > + PCI_BRIDGE_CTL_SERR | > > + PCI_BRIDGE_CTL_BUS_RESET); > > +} > > + > > +/************************************************************************** > > + * (chassis number, pcie physical slot number) -> pcie slot conversion > > + */ > > +struct PCIEChassis { > > + uint8_t number; > > + > > + QLIST_HEAD(, PCIESlot) slots; > > + QLIST_ENTRY(PCIEChassis) next; > > +}; > > + > > +static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis); > > + > > +static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number) > > +{ > > + struct PCIEChassis *c; > > + QLIST_FOREACH(c, &chassis, next) { > > + if (c->number == chassis_number) { > > + break; > > + } > > + } > > + return c; > > +} > > + > > +void pcie_chassis_create(uint8_t chassis_number) > > +{ > > + struct PCIEChassis *c; > > + c = pcie_chassis_find(chassis_number); > > + if (c) { > > + return; > > + } > > + c = g_malloc0(sizeof(*c)); > > + c->number = chassis_number; > > + QLIST_INIT(&c->slots); > > + QLIST_INSERT_HEAD(&chassis, c, next); > > +} > > + > > +static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c, > > + uint8_t slot) > > +{ > > + PCIESlot *s; > > + QLIST_FOREACH(s, &c->slots, next) { > > + if (s->slot == slot) { > > + break; > > + } > > + } > > + return s; > > +} > > + > > +PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot) > > +{ > > + struct PCIEChassis *c; > > + c = pcie_chassis_find(chassis_number); > > + if (!c) { > > + return NULL; > > + } > > + return pcie_chassis_find_slot_with_chassis(c, slot); > > +} > > + > > +int pcie_chassis_add_slot(struct PCIESlot *slot) > > +{ > > + struct PCIEChassis *c; > > + c = pcie_chassis_find(slot->chassis); > > + if (!c) { > > + return -ENODEV; > > + } > > + if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) { > > + return -EBUSY; > > + } > > + QLIST_INSERT_HEAD(&c->slots, slot, next); > > + return 0; > > +} > > + > > +void pcie_chassis_del_slot(PCIESlot *s) > > +{ > > + QLIST_REMOVE(s, next); > > +} > > diff --git a/hw/pci/pcie_port.h b/hw/pci/pcie_port.h > > new file mode 100644 > > index 0000000..3709583 > > --- /dev/null > > +++ b/hw/pci/pcie_port.h > > @@ -0,0 +1,51 @@ > > +/* > > + * pcie_port.h > > + * > > + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + * You should have received a copy of the GNU General Public License along > > + * with this program; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#ifndef QEMU_PCIE_PORT_H > > +#define QEMU_PCIE_PORT_H > > + > > +#include "pci_bridge.h" > > +#include "pci_internals.h" > > + > > +struct PCIEPort { > > + PCIBridge br; > > + > > + /* pci express switch port */ > > + uint8_t port; > > +}; > > + > > +void pcie_port_init_reg(PCIDevice *d); > > + > > +struct PCIESlot { > > + PCIEPort port; > > + > > + /* pci express switch port with slot */ > > + uint8_t chassis; > > + uint16_t slot; > > + QLIST_ENTRY(PCIESlot) next; > > +}; > > + > > +void pcie_chassis_create(uint8_t chassis_number); > > +void pcie_main_chassis_create(void); > > +PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot); > > +int pcie_chassis_add_slot(struct PCIESlot *slot); > > +void pcie_chassis_del_slot(PCIESlot *s); > > + > > +#endif /* QEMU_PCIE_PORT_H */ > > diff --git a/hw/pci/pcie_regs.h b/hw/pci/pcie_regs.h > > new file mode 100644 > > index 0000000..4d123d9 > > --- /dev/null > > +++ b/hw/pci/pcie_regs.h > > @@ -0,0 +1,156 @@ > > +/* > > + * constants for pcie configurations space from pci express spec. > > + * > > + * TODO: > > + * Those constants and macros should go to Linux pci_regs.h > > + * Once they're merged, they will go away. > > + */ > > +#ifndef QEMU_PCIE_REGS_H > > +#define QEMU_PCIE_REGS_H > > + > > + > > +/* express capability */ > > + > > +#define PCI_EXP_VER2_SIZEOF 0x3c /* express capability of ver. 2 */ > > +#define PCI_EXT_CAP_VER_SHIFT 16 > > +#define PCI_EXT_CAP_NEXT_SHIFT 20 > > +#define PCI_EXT_CAP_NEXT_MASK (0xffc << PCI_EXT_CAP_NEXT_SHIFT) > > + > > +#define PCI_EXT_CAP(id, ver, next) \ > > + ((id) | \ > > + ((ver) << PCI_EXT_CAP_VER_SHIFT) | \ > > + ((next) << PCI_EXT_CAP_NEXT_SHIFT)) > > + > > +#define PCI_EXT_CAP_ALIGN 4 > > +#define PCI_EXT_CAP_ALIGNUP(x) \ > > + (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1)) > > + > > +/* PCI_EXP_FLAGS */ > > +#define PCI_EXP_FLAGS_VER2 2 /* for now, supports only ver. 2 */ > > +#define PCI_EXP_FLAGS_IRQ_SHIFT (ffs(PCI_EXP_FLAGS_IRQ) - 1) > > +#define PCI_EXP_FLAGS_TYPE_SHIFT (ffs(PCI_EXP_FLAGS_TYPE) - 1) > > + > > + > > +/* PCI_EXP_LINK{CAP, STA} */ > > +/* link speed */ > > +#define PCI_EXP_LNK_LS_25 1 > > + > > +#define PCI_EXP_LNK_MLW_SHIFT (ffs(PCI_EXP_LNKCAP_MLW) - 1) > > +#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT) > > + > > +/* PCI_EXP_LINKCAP */ > > +#define PCI_EXP_LNKCAP_ASPMS_SHIFT (ffs(PCI_EXP_LNKCAP_ASPMS) - 1) > > +#define PCI_EXP_LNKCAP_ASPMS_0S (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT) > > + > > +#define PCI_EXP_LNKCAP_PN_SHIFT (ffs(PCI_EXP_LNKCAP_PN) - 1) > > + > > +#define PCI_EXP_SLTCAP_PSN_SHIFT (ffs(PCI_EXP_SLTCAP_PSN) - 1) > > + > > +#define PCI_EXP_SLTCTL_IND_RESERVED 0x0 > > +#define PCI_EXP_SLTCTL_IND_ON 0x1 > > +#define PCI_EXP_SLTCTL_IND_BLINK 0x2 > > +#define PCI_EXP_SLTCTL_IND_OFF 0x3 > > +#define PCI_EXP_SLTCTL_AIC_SHIFT (ffs(PCI_EXP_SLTCTL_AIC) - 1) > > +#define PCI_EXP_SLTCTL_AIC_OFF \ > > + (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT) > > + > > +#define PCI_EXP_SLTCTL_PIC_SHIFT (ffs(PCI_EXP_SLTCTL_PIC) - 1) > > +#define PCI_EXP_SLTCTL_PIC_OFF \ > > + (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT) > > + > > +#define PCI_EXP_SLTCTL_SUPPORTED \ > > + (PCI_EXP_SLTCTL_ABPE | \ > > + PCI_EXP_SLTCTL_PDCE | \ > > + PCI_EXP_SLTCTL_CCIE | \ > > + PCI_EXP_SLTCTL_HPIE | \ > > + PCI_EXP_SLTCTL_AIC | \ > > + PCI_EXP_SLTCTL_PCC | \ > > + PCI_EXP_SLTCTL_EIC) > > + > > +#define PCI_EXP_DEVCAP2_EFF 0x100000 > > +#define PCI_EXP_DEVCAP2_EETLPP 0x200000 > > + > > +#define PCI_EXP_DEVCTL2_EETLPPB 0x80 > > + > > +/* ARI */ > > +#define PCI_ARI_VER 1 > > +#define PCI_ARI_SIZEOF 8 > > + > > +/* AER */ > > +#define PCI_ERR_VER 2 > > +#define PCI_ERR_SIZEOF 0x48 > > + > > +#define PCI_ERR_UNC_SDN 0x00000020 /* surprise down */ > > +#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */ > > +#define PCI_ERR_UNC_INTN 0x00400000 /* Internal Error */ > > +#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC Blcoked TLP */ > > +#define PCI_ERR_UNC_ATOP_EBLOCKED 0x01000000 /* atomic op egress blocked */ > > +#define PCI_ERR_UNC_TLP_PRF_BLOCKED 0x02000000 /* TLP Prefix Blocked */ > > +#define PCI_ERR_COR_ADV_NONFATAL 0x00002000 /* Advisory Non-Fatal */ > > +#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected Internal */ > > +#define PCI_ERR_COR_HL_OVERFLOW 0x00008000 /* Header Long Overflow */ > > +#define PCI_ERR_CAP_FEP_MASK 0x0000001f > > +#define PCI_ERR_CAP_MHRC 0x00000200 > > +#define PCI_ERR_CAP_MHRE 0x00000400 > > +#define PCI_ERR_CAP_TLP 0x00000800 > > + > > +#define PCI_ERR_HEADER_LOG_SIZE 16 > > +#define PCI_ERR_TLP_PREFIX_LOG 0x38 > > +#define PCI_ERR_TLP_PREFIX_LOG_SIZE 16 > > + > > +#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR 0x4000 > > + > > +/* aer root error command/status */ > > +#define PCI_ERR_ROOT_CMD_EN_MASK (PCI_ERR_ROOT_CMD_COR_EN | \ > > + PCI_ERR_ROOT_CMD_NONFATAL_EN | \ > > + PCI_ERR_ROOT_CMD_FATAL_EN) > > + > > +#define PCI_ERR_ROOT_IRQ_MAX 32 > > +#define PCI_ERR_ROOT_IRQ 0xf8000000 > > +#define PCI_ERR_ROOT_IRQ_SHIFT (ffs(PCI_ERR_ROOT_IRQ) - 1) > > +#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV | \ > > + PCI_ERR_ROOT_MULTI_COR_RCV | \ > > + PCI_ERR_ROOT_UNCOR_RCV | \ > > + PCI_ERR_ROOT_MULTI_UNCOR_RCV | \ > > + PCI_ERR_ROOT_FIRST_FATAL | \ > > + PCI_ERR_ROOT_NONFATAL_RCV | \ > > + PCI_ERR_ROOT_FATAL_RCV) > > + > > +#define PCI_ERR_UNC_SUPPORTED (PCI_ERR_UNC_DLP | \ > > + PCI_ERR_UNC_SDN | \ > > + PCI_ERR_UNC_POISON_TLP | \ > > + PCI_ERR_UNC_FCP | \ > > + PCI_ERR_UNC_COMP_TIME | \ > > + PCI_ERR_UNC_COMP_ABORT | \ > > + PCI_ERR_UNC_UNX_COMP | \ > > + PCI_ERR_UNC_RX_OVER | \ > > + PCI_ERR_UNC_MALF_TLP | \ > > + PCI_ERR_UNC_ECRC | \ > > + PCI_ERR_UNC_UNSUP | \ > > + PCI_ERR_UNC_ACSV | \ > > + PCI_ERR_UNC_INTN | \ > > + PCI_ERR_UNC_MCBTLP | \ > > + PCI_ERR_UNC_ATOP_EBLOCKED | \ > > + PCI_ERR_UNC_TLP_PRF_BLOCKED) > > + > > +#define PCI_ERR_UNC_SEVERITY_DEFAULT (PCI_ERR_UNC_DLP | \ > > + PCI_ERR_UNC_SDN | \ > > + PCI_ERR_UNC_FCP | \ > > + PCI_ERR_UNC_RX_OVER | \ > > + PCI_ERR_UNC_MALF_TLP | \ > > + PCI_ERR_UNC_INTN) > > + > > +#define PCI_ERR_COR_SUPPORTED (PCI_ERR_COR_RCVR | \ > > + PCI_ERR_COR_BAD_TLP | \ > > + PCI_ERR_COR_BAD_DLLP | \ > > + PCI_ERR_COR_REP_ROLL | \ > > + PCI_ERR_COR_REP_TIMER | \ > > + PCI_ERR_COR_ADV_NONFATAL | \ > > + PCI_ERR_COR_INTERNAL | \ > > + PCI_ERR_COR_HL_OVERFLOW) > > + > > +#define PCI_ERR_COR_MASK_DEFAULT (PCI_ERR_COR_ADV_NONFATAL | \ > > + PCI_ERR_COR_INTERNAL | \ > > + PCI_ERR_COR_HL_OVERFLOW) > > + > > +#endif /* QEMU_PCIE_REGS_H */ > > diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c > > new file mode 100644 > > index 0000000..4597bbd > > --- /dev/null > > +++ b/hw/pci/shpc.c > > @@ -0,0 +1,681 @@ > > +#include <strings.h> > > +#include <stdint.h> > > +#include "range.h" > > +#include "range.h" > > +#include "shpc.h" > > +#include "pci.h" > > +#include "pci_internals.h" > > +#include "msi.h" > > + > > +/* TODO: model power only and disabled slot states. */ > > +/* TODO: handle SERR and wakeups */ > > +/* TODO: consider enabling 66MHz support */ > > + > > +/* TODO: remove fully only on state DISABLED and LED off. > > + * track state to properly record this. */ > > + > > +/* SHPC Working Register Set */ > > +#define SHPC_BASE_OFFSET 0x00 /* 4 bytes */ > > +#define SHPC_SLOTS_33 0x04 /* 4 bytes. Also encodes PCI-X slots. */ > > +#define SHPC_SLOTS_66 0x08 /* 4 bytes. */ > > +#define SHPC_NSLOTS 0x0C /* 1 byte */ > > +#define SHPC_FIRST_DEV 0x0D /* 1 byte */ > > +#define SHPC_PHYS_SLOT 0x0E /* 2 byte */ > > +#define SHPC_PHYS_NUM_MAX 0x7ff > > +#define SHPC_PHYS_NUM_UP 0x2000 > > +#define SHPC_PHYS_MRL 0x4000 > > +#define SHPC_PHYS_BUTTON 0x8000 > > +#define SHPC_SEC_BUS 0x10 /* 2 bytes */ > > +#define SHPC_SEC_BUS_33 0x0 > > +#define SHPC_SEC_BUS_66 0x1 /* Unused */ > > +#define SHPC_SEC_BUS_MASK 0x7 > > +#define SHPC_MSI_CTL 0x12 /* 1 byte */ > > +#define SHPC_PROG_IFC 0x13 /* 1 byte */ > > +#define SHPC_PROG_IFC_1_0 0x1 > > +#define SHPC_CMD_CODE 0x14 /* 1 byte */ > > +#define SHPC_CMD_TRGT 0x15 /* 1 byte */ > > +#define SHPC_CMD_TRGT_MIN 0x1 > > +#define SHPC_CMD_TRGT_MAX 0x1f > > +#define SHPC_CMD_STATUS 0x16 /* 2 bytes */ > > +#define SHPC_CMD_STATUS_BUSY 0x1 > > +#define SHPC_CMD_STATUS_MRL_OPEN 0x2 > > +#define SHPC_CMD_STATUS_INVALID_CMD 0x4 > > +#define SHPC_CMD_STATUS_INVALID_MODE 0x8 > > +#define SHPC_INT_LOCATOR 0x18 /* 4 bytes */ > > +#define SHPC_INT_COMMAND 0x1 > > +#define SHPC_SERR_LOCATOR 0x1C /* 4 bytes */ > > +#define SHPC_SERR_INT 0x20 /* 4 bytes */ > > +#define SHPC_INT_DIS 0x1 > > +#define SHPC_SERR_DIS 0x2 > > +#define SHPC_CMD_INT_DIS 0x4 > > +#define SHPC_ARB_SERR_DIS 0x8 > > +#define SHPC_CMD_DETECTED 0x10000 > > +#define SHPC_ARB_DETECTED 0x20000 > > + /* 4 bytes * slot # (start from 0) */ > > +#define SHPC_SLOT_REG(s) (0x24 + (s) * 4) > > + /* 2 bytes */ > > +#define SHPC_SLOT_STATUS(s) (0x0 + SHPC_SLOT_REG(s)) > > + > > +/* Same slot state masks are used for command and status registers */ > > +#define SHPC_SLOT_STATE_MASK 0x03 > > +#define SHPC_SLOT_STATE_SHIFT \ > > + (ffs(SHPC_SLOT_STATE_MASK) - 1) > > + > > +#define SHPC_STATE_NO 0x0 > > +#define SHPC_STATE_PWRONLY 0x1 > > +#define SHPC_STATE_ENABLED 0x2 > > +#define SHPC_STATE_DISABLED 0x3 > > + > > +#define SHPC_SLOT_PWR_LED_MASK 0xC > > +#define SHPC_SLOT_PWR_LED_SHIFT \ > > + (ffs(SHPC_SLOT_PWR_LED_MASK) - 1) > > +#define SHPC_SLOT_ATTN_LED_MASK 0x30 > > +#define SHPC_SLOT_ATTN_LED_SHIFT \ > > + (ffs(SHPC_SLOT_ATTN_LED_MASK) - 1) > > + > > +#define SHPC_LED_NO 0x0 > > +#define SHPC_LED_ON 0x1 > > +#define SHPC_LED_BLINK 0x2 > > +#define SHPC_LED_OFF 0x3 > > + > > +#define SHPC_SLOT_STATUS_PWR_FAULT 0x40 > > +#define SHPC_SLOT_STATUS_BUTTON 0x80 > > +#define SHPC_SLOT_STATUS_MRL_OPEN 0x100 > > +#define SHPC_SLOT_STATUS_66 0x200 > > +#define SHPC_SLOT_STATUS_PRSNT_MASK 0xC00 > > +#define SHPC_SLOT_STATUS_PRSNT_EMPTY 0x3 > > +#define SHPC_SLOT_STATUS_PRSNT_25W 0x1 > > +#define SHPC_SLOT_STATUS_PRSNT_15W 0x2 > > +#define SHPC_SLOT_STATUS_PRSNT_7_5W 0x0 > > + > > +#define SHPC_SLOT_STATUS_PRSNT_PCIX 0x3000 > > + > > + > > + /* 1 byte */ > > +#define SHPC_SLOT_EVENT_LATCH(s) (0x2 + SHPC_SLOT_REG(s)) > > + /* 1 byte */ > > +#define SHPC_SLOT_EVENT_SERR_INT_DIS(d, s) (0x3 + SHPC_SLOT_REG(s)) > > +#define SHPC_SLOT_EVENT_PRESENCE 0x01 > > +#define SHPC_SLOT_EVENT_ISOLATED_FAULT 0x02 > > +#define SHPC_SLOT_EVENT_BUTTON 0x04 > > +#define SHPC_SLOT_EVENT_MRL 0x08 > > +#define SHPC_SLOT_EVENT_CONNECTED_FAULT 0x10 > > +/* Bits below are used for Serr/Int disable only */ > > +#define SHPC_SLOT_EVENT_MRL_SERR_DIS 0x20 > > +#define SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS 0x40 > > + > > +#define SHPC_MIN_SLOTS 1 > > +#define SHPC_MAX_SLOTS 31 > > +#define SHPC_SIZEOF(d) SHPC_SLOT_REG((d)->shpc->nslots) > > + > > +/* SHPC Slot identifiers */ > > + > > +/* Hotplug supported at 31 slots out of the total 32. We reserve slot 0, > > + and give the rest of them physical *and* pci numbers starting from 1, so > > + they match logical numbers. Note: this means that multiple slots must have > > + different chassis number values, to make chassis+physical slot unique. > > + TODO: make this configurable? */ > > +#define SHPC_IDX_TO_LOGICAL(slot) ((slot) + 1) > > +#define SHPC_LOGICAL_TO_IDX(target) ((target) - 1) > > +#define SHPC_IDX_TO_PCI(slot) ((slot) + 1) > > +#define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1) > > +#define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1) > > + > > +static int roundup_pow_of_two(int x) > > +{ > > + x |= (x >> 1); > > + x |= (x >> 2); > > + x |= (x >> 4); > > + x |= (x >> 8); > > + x |= (x >> 16); > > + return x + 1; > > +} > > + > > +static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk) > > +{ > > + uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); > > + return (pci_get_word(status) & msk) >> (ffs(msk) - 1); > > +} > > + > > +static void shpc_set_status(SHPCDevice *shpc, > > + int slot, uint8_t value, uint16_t msk) > > +{ > > + uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); > > + pci_word_test_and_clear_mask(status, msk); > > + pci_word_test_and_set_mask(status, value << (ffs(msk) - 1)); > > +} > > + > > +static void shpc_interrupt_update(PCIDevice *d) > > +{ > > + SHPCDevice *shpc = d->shpc; > > + int slot; > > + int level = 0; > > + uint32_t serr_int; > > + uint32_t int_locator = 0; > > + > > + /* Update interrupt locator register */ > > + for (slot = 0; slot < shpc->nslots; ++slot) { > > + uint8_t event = shpc->config[SHPC_SLOT_EVENT_LATCH(slot)]; > > + uint8_t disable = shpc->config[SHPC_SLOT_EVENT_SERR_INT_DIS(d, slot)]; > > + uint32_t mask = 1 << SHPC_IDX_TO_LOGICAL(slot); > > + if (event & ~disable) { > > + int_locator |= mask; > > + } > > + } > > + serr_int = pci_get_long(shpc->config + SHPC_SERR_INT); > > + if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_DIS)) { > > + int_locator |= SHPC_INT_COMMAND; > > + } > > + pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator); > > + level = (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0; > > + if (msi_enabled(d) && shpc->msi_requested != level) > > + msi_notify(d, 0); > > + else > > + qemu_set_irq(d->irq[0], level); > > + shpc->msi_requested = level; > > +} > > + > > +static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed) > > +{ > > + switch (speed) { > > + case SHPC_SEC_BUS_33: > > + shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK; > > + shpc->config[SHPC_SEC_BUS] |= speed; > > + break; > > + default: > > + pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, > > + SHPC_CMD_STATUS_INVALID_MODE); > > + } > > +} > > + > > +void shpc_reset(PCIDevice *d) > > +{ > > + SHPCDevice *shpc = d->shpc; > > + int nslots = shpc->nslots; > > + int i; > > + memset(shpc->config, 0, SHPC_SIZEOF(d)); > > + pci_set_byte(shpc->config + SHPC_NSLOTS, nslots); > > + pci_set_long(shpc->config + SHPC_SLOTS_33, nslots); > > + pci_set_long(shpc->config + SHPC_SLOTS_66, 0); > > + pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0)); > > + pci_set_word(shpc->config + SHPC_PHYS_SLOT, > > + SHPC_IDX_TO_PHYSICAL(0) | > > + SHPC_PHYS_NUM_UP | > > + SHPC_PHYS_MRL | > > + SHPC_PHYS_BUTTON); > > + pci_set_long(shpc->config + SHPC_SERR_INT, SHPC_INT_DIS | > > + SHPC_SERR_DIS | > > + SHPC_CMD_INT_DIS | > > + SHPC_ARB_SERR_DIS); > > + pci_set_byte(shpc->config + SHPC_PROG_IFC, SHPC_PROG_IFC_1_0); > > + pci_set_word(shpc->config + SHPC_SEC_BUS, SHPC_SEC_BUS_33); > > + for (i = 0; i < shpc->nslots; ++i) { > > + pci_set_byte(shpc->config + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), > > + SHPC_SLOT_EVENT_PRESENCE | > > + SHPC_SLOT_EVENT_ISOLATED_FAULT | > > + SHPC_SLOT_EVENT_BUTTON | > > + SHPC_SLOT_EVENT_MRL | > > + SHPC_SLOT_EVENT_CONNECTED_FAULT | > > + SHPC_SLOT_EVENT_MRL_SERR_DIS | > > + SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); > > + if (shpc->sec_bus->devices[PCI_DEVFN(SHPC_IDX_TO_PCI(i), 0)]) { > > + shpc_set_status(shpc, i, SHPC_STATE_ENABLED, SHPC_SLOT_STATE_MASK); > > + shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_MRL_OPEN); > > + shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_7_5W, > > + SHPC_SLOT_STATUS_PRSNT_MASK); > > + shpc_set_status(shpc, i, SHPC_LED_ON, SHPC_SLOT_PWR_LED_MASK); > > + } else { > > + shpc_set_status(shpc, i, SHPC_STATE_DISABLED, SHPC_SLOT_STATE_MASK); > > + shpc_set_status(shpc, i, 1, SHPC_SLOT_STATUS_MRL_OPEN); > > + shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_EMPTY, > > + SHPC_SLOT_STATUS_PRSNT_MASK); > > + shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK); > > + } > > + shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66); > > + } > > + shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33); > > + shpc->msi_requested = 0; > > + shpc_interrupt_update(d); > > +} > > + > > +static void shpc_invalid_command(SHPCDevice *shpc) > > +{ > > + pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, > > + SHPC_CMD_STATUS_INVALID_CMD); > > +} > > + > > +static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot) > > +{ > > + int devfn; > > + int pci_slot = SHPC_IDX_TO_PCI(slot); > > + for (devfn = PCI_DEVFN(pci_slot, 0); > > + devfn <= PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1); > > + ++devfn) { > > + PCIDevice *affected_dev = shpc->sec_bus->devices[devfn]; > > + if (affected_dev) { > > + qdev_free(&affected_dev->qdev); > > + } > > + } > > +} > > + > > +static void shpc_slot_command(SHPCDevice *shpc, uint8_t target, > > + uint8_t state, uint8_t power, uint8_t attn) > > +{ > > + uint8_t current_state; > > + int slot = SHPC_LOGICAL_TO_IDX(target); > > + if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) { > > + shpc_invalid_command(shpc); > > + return; > > + } > > + current_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); > > + if (current_state == SHPC_STATE_ENABLED && state == SHPC_STATE_PWRONLY) { > > + shpc_invalid_command(shpc); > > + return; > > + } > > + > > + switch (power) { > > + case SHPC_LED_NO: > > + break; > > + default: > > + /* TODO: send event to monitor */ > > + shpc_set_status(shpc, slot, power, SHPC_SLOT_PWR_LED_MASK); > > + } > > + switch (attn) { > > + case SHPC_LED_NO: > > + break; > > + default: > > + /* TODO: send event to monitor */ > > + shpc_set_status(shpc, slot, attn, SHPC_SLOT_ATTN_LED_MASK); > > + } > > + > > + if ((current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_PWRONLY) || > > + (current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_ENABLED)) { > > + shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > > + } else if ((current_state == SHPC_STATE_ENABLED || > > + current_state == SHPC_STATE_PWRONLY) && > > + state == SHPC_STATE_DISABLED) { > > + shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > > + power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); > > + /* TODO: track what monitor requested. */ > > + /* Look at LED to figure out whether it's ok to remove the device. */ > > + if (power == SHPC_LED_OFF) { > > + shpc_free_devices_in_slot(shpc, slot); > > + shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); > > + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, > > + SHPC_SLOT_STATUS_PRSNT_MASK); > > + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > > + SHPC_SLOT_EVENT_BUTTON | > > + SHPC_SLOT_EVENT_MRL | > > + SHPC_SLOT_EVENT_PRESENCE; > > + } > > + } > > +} > > + > > +static void shpc_command(SHPCDevice *shpc) > > +{ > > + uint8_t code = pci_get_byte(shpc->config + SHPC_CMD_CODE); > > + uint8_t speed; > > + uint8_t target; > > + uint8_t attn; > > + uint8_t power; > > + uint8_t state; > > + int i; > > + > > + /* Clear status from the previous command. */ > > + pci_word_test_and_clear_mask(shpc->config + SHPC_CMD_STATUS, > > + SHPC_CMD_STATUS_BUSY | > > + SHPC_CMD_STATUS_MRL_OPEN | > > + SHPC_CMD_STATUS_INVALID_CMD | > > + SHPC_CMD_STATUS_INVALID_MODE); > > + switch (code) { > > + case 0x00 ... 0x3f: > > + target = shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX; > > + state = (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_SHIFT; > > + power = (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_LED_SHIFT; > > + attn = (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_LED_SHIFT; > > + shpc_slot_command(shpc, target, state, power, attn); > > + break; > > + case 0x40 ... 0x47: > > + speed = code & SHPC_SEC_BUS_MASK; > > + shpc_set_sec_bus_speed(shpc, speed); > > + break; > > + case 0x48: > > + /* Power only all slots */ > > + /* first verify no slots are enabled */ > > + for (i = 0; i < shpc->nslots; ++i) { > > + state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); > > + if (state == SHPC_STATE_ENABLED) { > > + shpc_invalid_command(shpc); > > + goto done; > > + } > > + } > > + for (i = 0; i < shpc->nslots; ++i) { > > + if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { > > + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > > + SHPC_STATE_PWRONLY, SHPC_LED_ON, SHPC_LED_NO); > > + } else { > > + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > > + SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); > > + } > > + } > > + break; > > + case 0x49: > > + /* Enable all slots */ > > + /* TODO: Spec says this shall fail if some are already enabled. > > + * This doesn't make sense - why not? a spec bug? */ > > + for (i = 0; i < shpc->nslots; ++i) { > > + state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); > > + if (state == SHPC_STATE_ENABLED) { > > + shpc_invalid_command(shpc); > > + goto done; > > + } > > + } > > + for (i = 0; i < shpc->nslots; ++i) { > > + if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { > > + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > > + SHPC_STATE_ENABLED, SHPC_LED_ON, SHPC_LED_NO); > > + } else { > > + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > > + SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); > > + } > > + } > > + break; > > + default: > > + shpc_invalid_command(shpc); > > + break; > > + } > > +done: > > + pci_long_test_and_set_mask(shpc->config + SHPC_SERR_INT, SHPC_CMD_DETECTED); > > +} > > + > > +static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, int l) > > +{ > > + SHPCDevice *shpc = d->shpc; > > + int i; > > + if (addr >= SHPC_SIZEOF(d)) { > > + return; > > + } > > + l = MIN(l, SHPC_SIZEOF(d) - addr); > > + > > + /* TODO: code duplicated from pci.c */ > > + for (i = 0; i < l; val >>= 8, ++i) { > > + unsigned a = addr + i; > > + uint8_t wmask = shpc->wmask[a]; > > + uint8_t w1cmask = shpc->w1cmask[a]; > > + assert(!(wmask & w1cmask)); > > + shpc->config[a] = (shpc->config[a] & ~wmask) | (val & wmask); > > + shpc->config[a] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ > > + } > > + if (ranges_overlap(addr, l, SHPC_CMD_CODE, 2)) { > > + shpc_command(shpc); > > + } > > + shpc_interrupt_update(d); > > +} > > + > > +static uint64_t shpc_read(PCIDevice *d, unsigned addr, int l) > > +{ > > + uint64_t val = 0x0; > > + if (addr >= SHPC_SIZEOF(d)) { > > + return val; > > + } > > + l = MIN(l, SHPC_SIZEOF(d) - addr); > > + memcpy(&val, d->shpc->config + addr, l); > > + return val; > > +} > > + > > +/* SHPC Bridge Capability */ > > +#define SHPC_CAP_LENGTH 0x08 > > +#define SHPC_CAP_DWORD_SELECT 0x2 /* 1 byte */ > > +#define SHPC_CAP_CxP 0x3 /* 1 byte: CSP, CIP */ > > +#define SHPC_CAP_DWORD_DATA 0x4 /* 4 bytes */ > > +#define SHPC_CAP_CSP_MASK 0x4 > > +#define SHPC_CAP_CIP_MASK 0x8 > > + > > +static uint8_t shpc_cap_dword(PCIDevice *d) > > +{ > > + return pci_get_byte(d->config + d->shpc->cap + SHPC_CAP_DWORD_SELECT); > > +} > > + > > +/* Update dword data capability register */ > > +static void shpc_cap_update_dword(PCIDevice *d) > > +{ > > + unsigned data; > > + data = shpc_read(d, shpc_cap_dword(d) * 4, 4); > > + pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, data); > > +} > > + > > +/* Add SHPC capability to the config space for the device. */ > > +static int shpc_cap_add_config(PCIDevice *d) > > +{ > > + uint8_t *config; > > + int config_offset; > > + config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC, > > + 0, SHPC_CAP_LENGTH); > > + if (config_offset < 0) { > > + return config_offset; > > + } > > + config = d->config + config_offset; > > + > > + pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0); > > + pci_set_byte(config + SHPC_CAP_CxP, 0); > > + pci_set_long(config + SHPC_CAP_DWORD_DATA, 0); > > + d->shpc->cap = config_offset; > > + /* Make dword select and data writeable. */ > > + pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff); > > + pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff); > > + return 0; > > +} > > + > > +static uint64_t shpc_mmio_read(void *opaque, hwaddr addr, > > + unsigned size) > > +{ > > + return shpc_read(opaque, addr, size); > > +} > > + > > +static void shpc_mmio_write(void *opaque, hwaddr addr, > > + uint64_t val, unsigned size) > > +{ > > + shpc_write(opaque, addr, val, size); > > +} > > + > > +static const MemoryRegionOps shpc_mmio_ops = { > > + .read = shpc_mmio_read, > > + .write = shpc_mmio_write, > > + .endianness = DEVICE_LITTLE_ENDIAN, > > + .valid = { > > + /* SHPC ECN requires dword accesses, but the original 1.0 spec doesn't. > > + * It's easier to suppport all sizes than worry about it. */ > > + .min_access_size = 1, > > + .max_access_size = 4, > > + }, > > +}; > > + > > +static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev, > > + PCIHotplugState hotplug_state) > > +{ > > + int pci_slot = PCI_SLOT(affected_dev->devfn); > > + uint8_t state; > > + uint8_t led; > > + PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); > > + SHPCDevice *shpc = d->shpc; > > + int slot = SHPC_PCI_TO_IDX(pci_slot); > > + if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) { > > + error_report("Unsupported PCI slot %d for standard hotplug " > > + "controller. Valid slots are between %d and %d.", > > + pci_slot, SHPC_IDX_TO_PCI(0), > > + SHPC_IDX_TO_PCI(shpc->nslots) - 1); > > + return -1; > > + } > > + /* Don't send event when device is enabled during qemu machine creation: > > + * it is present on boot, no hotplug event is necessary. We do send an > > + * event when the device is disabled later. */ > > + if (hotplug_state == PCI_COLDPLUG_ENABLED) { > > + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); > > + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, > > + SHPC_SLOT_STATUS_PRSNT_MASK); > > + return 0; > > + } > > + if (hotplug_state == PCI_HOTPLUG_DISABLED) { > > + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON; > > + state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); > > + led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); > > + if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) { > > + shpc_free_devices_in_slot(shpc, slot); > > + shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); > > + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, > > + SHPC_SLOT_STATUS_PRSNT_MASK); > > + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > > + SHPC_SLOT_EVENT_MRL | > > + SHPC_SLOT_EVENT_PRESENCE; > > + } > > + } else { > > + /* This could be a cancellation of the previous removal. > > + * We check MRL state to figure out. */ > > + if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) { > > + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); > > + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, > > + SHPC_SLOT_STATUS_PRSNT_MASK); > > + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > > + SHPC_SLOT_EVENT_BUTTON | > > + SHPC_SLOT_EVENT_MRL | > > + SHPC_SLOT_EVENT_PRESENCE; > > + } else { > > + /* Press attention button to cancel removal */ > > + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > > + SHPC_SLOT_EVENT_BUTTON; > > + } > > + } > > + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66); > > + shpc_interrupt_update(d); > > + return 0; > > +} > > + > > +/* Initialize the SHPC structure in bridge's BAR. */ > > +int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset) > > +{ > > + int i, ret; > > + int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */ > > + SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc)); > > + shpc->sec_bus = sec_bus; > > + ret = shpc_cap_add_config(d); > > + if (ret) { > > + g_free(d->shpc); > > + return ret; > > + } > > + if (nslots < SHPC_MIN_SLOTS) { > > + return 0; > > + } > > + if (nslots > SHPC_MAX_SLOTS || > > + SHPC_IDX_TO_PCI(nslots) > PCI_SLOT_MAX) { > > + /* TODO: report an error mesage that makes sense. */ > > + return -EINVAL; > > + } > > + shpc->nslots = nslots; > > + shpc->config = g_malloc0(SHPC_SIZEOF(d)); > > + shpc->cmask = g_malloc0(SHPC_SIZEOF(d)); > > + shpc->wmask = g_malloc0(SHPC_SIZEOF(d)); > > + shpc->w1cmask = g_malloc0(SHPC_SIZEOF(d)); > > + > > + shpc_reset(d); > > + > > + pci_set_long(shpc->config + SHPC_BASE_OFFSET, offset); > > + > > + pci_set_byte(shpc->wmask + SHPC_CMD_CODE, 0xff); > > + pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); > > + pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); > > + pci_set_long(shpc->wmask + SHPC_SERR_INT, > > + SHPC_INT_DIS | > > + SHPC_SERR_DIS | > > + SHPC_CMD_INT_DIS | > > + SHPC_ARB_SERR_DIS); > > + pci_set_long(shpc->w1cmask + SHPC_SERR_INT, > > + SHPC_CMD_DETECTED | > > + SHPC_ARB_DETECTED); > > + for (i = 0; i < nslots; ++i) { > > + pci_set_byte(shpc->wmask + > > + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), > > + SHPC_SLOT_EVENT_PRESENCE | > > + SHPC_SLOT_EVENT_ISOLATED_FAULT | > > + SHPC_SLOT_EVENT_BUTTON | > > + SHPC_SLOT_EVENT_MRL | > > + SHPC_SLOT_EVENT_CONNECTED_FAULT | > > + SHPC_SLOT_EVENT_MRL_SERR_DIS | > > + SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); > > + pci_set_byte(shpc->w1cmask + > > + SHPC_SLOT_EVENT_LATCH(i), > > + SHPC_SLOT_EVENT_PRESENCE | > > + SHPC_SLOT_EVENT_ISOLATED_FAULT | > > + SHPC_SLOT_EVENT_BUTTON | > > + SHPC_SLOT_EVENT_MRL | > > + SHPC_SLOT_EVENT_CONNECTED_FAULT); > > + } > > + > > + /* TODO: init cmask */ > > + memory_region_init_io(&shpc->mmio, &shpc_mmio_ops, d, "shpc-mmio", > > + SHPC_SIZEOF(d)); > > + shpc_cap_update_dword(d); > > + memory_region_add_subregion(bar, offset, &shpc->mmio); > > + pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev); > > + > > + d->cap_present |= QEMU_PCI_CAP_SHPC; > > + return 0; > > +} > > + > > +int shpc_bar_size(PCIDevice *d) > > +{ > > + return roundup_pow_of_two(SHPC_SLOT_REG(SHPC_MAX_SLOTS)); > > +} > > + > > +void shpc_cleanup(PCIDevice *d, MemoryRegion *bar) > > +{ > > + SHPCDevice *shpc = d->shpc; > > + d->cap_present &= ~QEMU_PCI_CAP_SHPC; > > + memory_region_del_subregion(bar, &shpc->mmio); > > + /* TODO: cleanup config space changes? */ > > + g_free(shpc->config); > > + g_free(shpc->cmask); > > + g_free(shpc->wmask); > > + g_free(shpc->w1cmask); > > + memory_region_destroy(&shpc->mmio); > > + g_free(shpc); > > +} > > + > > +void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) > > +{ > > + if (!ranges_overlap(addr, l, d->shpc->cap, SHPC_CAP_LENGTH)) { > > + return; > > + } > > + if (ranges_overlap(addr, l, d->shpc->cap + SHPC_CAP_DWORD_DATA, 4)) { > > + unsigned dword_data; > > + dword_data = pci_get_long(d->shpc->config + d->shpc->cap > > + + SHPC_CAP_DWORD_DATA); > > + shpc_write(d, shpc_cap_dword(d) * 4, dword_data, 4); > > + } > > + /* Update cap dword data in case guest is going to read it. */ > > + shpc_cap_update_dword(d); > > +} > > + > > +static void shpc_save(QEMUFile *f, void *pv, size_t size) > > +{ > > + PCIDevice *d = container_of(pv, PCIDevice, shpc); > > + qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); > > +} > > + > > +static int shpc_load(QEMUFile *f, void *pv, size_t size) > > +{ > > + PCIDevice *d = container_of(pv, PCIDevice, shpc); > > + int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); > > + if (ret != SHPC_SIZEOF(d)) { > > + return -EINVAL; > > + } > > + /* Make sure we don't lose notifications. An extra interrupt is harmless. */ > > + d->shpc->msi_requested = 0; > > + shpc_interrupt_update(d); > > + return 0; > > +} > > + > > +VMStateInfo shpc_vmstate_info = { > > + .name = "shpc", > > + .get = shpc_load, > > + .put = shpc_save, > > +}; > > diff --git a/hw/pci/shpc.h b/hw/pci/shpc.h > > new file mode 100644 > > index 0000000..130b71d > > --- /dev/null > > +++ b/hw/pci/shpc.h > > @@ -0,0 +1,48 @@ > > +#ifndef SHPC_H > > +#define SHPC_H > > + > > +#include "qemu-common.h" > > +#include "memory.h" > > +#include "vmstate.h" > > + > > +struct SHPCDevice { > > + /* Capability offset in device's config space */ > > + int cap; > > + > > + /* # of hot-pluggable slots */ > > + int nslots; > > + > > + /* SHPC WRS: working register set */ > > + uint8_t *config; > > + > > + /* Used to enable checks on load. Note that writable bits are > > + * never checked even if set in cmask. */ > > + uint8_t *cmask; > > + > > + /* Used to implement R/W bytes */ > > + uint8_t *wmask; > > + > > + /* Used to implement RW1C(Write 1 to Clear) bytes */ > > + uint8_t *w1cmask; > > + > > + /* MMIO for the SHPC BAR */ > > + MemoryRegion mmio; > > + > > + /* Bus controlled by this SHPC */ > > + PCIBus *sec_bus; > > + > > + /* MSI already requested for this event */ > > + int msi_requested; > > +}; > > + > > +void shpc_reset(PCIDevice *d); > > +int shpc_bar_size(PCIDevice *dev); > > +int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off); > > +void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar); > > +void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len); > > + > > +extern VMStateInfo shpc_vmstate_info; > > +#define SHPC_VMSTATE(_field, _type) \ > > + VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0) > > + > > +#endif > > diff --git a/hw/pci/slotid_cap.c b/hw/pci/slotid_cap.c > > new file mode 100644 > > index 0000000..0106452 > > --- /dev/null > > +++ b/hw/pci/slotid_cap.c > > @@ -0,0 +1,44 @@ > > +#include "slotid_cap.h" > > +#include "pci.h" > > + > > +#define SLOTID_CAP_LENGTH 4 > > +#define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1) > > + > > +int slotid_cap_init(PCIDevice *d, int nslots, > > + uint8_t chassis, > > + unsigned offset) > > +{ > > + int cap; > > + if (!chassis) { > > + error_report("Bridge chassis not specified. Each bridge is required " > > + "to be assigned a unique chassis id > 0."); > > + return -EINVAL; > > + } > > + if (nslots < 0 || nslots > (PCI_SID_ESR_NSLOTS >> SLOTID_NSLOTS_SHIFT)) { > > + /* TODO: error report? */ > > + return -EINVAL; > > + } > > + > > + cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset, SLOTID_CAP_LENGTH); > > + if (cap < 0) { > > + return cap; > > + } > > + /* We make each chassis unique, this way each bridge is First in Chassis */ > > + d->config[cap + PCI_SID_ESR] = PCI_SID_ESR_FIC | > > + (nslots << SLOTID_NSLOTS_SHIFT); > > + d->cmask[cap + PCI_SID_ESR] = 0xff; > > + d->config[cap + PCI_SID_CHASSIS_NR] = chassis; > > + /* Note: Chassis number register is non-volatile, > > + so we don't reset it. */ > > + /* TODO: store in eeprom? */ > > + d->wmask[cap + PCI_SID_CHASSIS_NR] = 0xff; > > + > > + d->cap_present |= QEMU_PCI_CAP_SLOTID; > > + return 0; > > +} > > + > > +void slotid_cap_cleanup(PCIDevice *d) > > +{ > > + /* TODO: cleanup config space? */ > > + d->cap_present &= ~QEMU_PCI_CAP_SLOTID; > > +} > > diff --git a/hw/pci/slotid_cap.h b/hw/pci/slotid_cap.h > > new file mode 100644 > > index 0000000..70db047 > > --- /dev/null > > +++ b/hw/pci/slotid_cap.h > > @@ -0,0 +1,11 @@ > > +#ifndef PCI_SLOTID_CAP_H > > +#define PCI_SLOTID_CAP_H > > + > > +#include "qemu-common.h" > > + > > +int slotid_cap_init(PCIDevice *dev, int nslots, > > + uint8_t chassis, > > + unsigned offset); > > +void slotid_cap_cleanup(PCIDevice *dev); > > + > > +#endif > > diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c > > deleted file mode 100644 > > index 4680501..0000000 > > --- a/hw/pci_bridge.c > > +++ /dev/null > > @@ -1,363 +0,0 @@ > > -/* > > - * QEMU PCI bus manager > > - * > > - * Copyright (c) 2004 Fabrice Bellard > > - * > > - * Permission is hereby granted, free of charge, to any person obtaining a copy > > - * of this software and associated documentation files (the "Software"), to dea > > - > > - * in the Software without restriction, including without limitation the rights > > - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > > - * copies of the Software, and to permit persons to whom the Software is > > - * furnished to do so, subject to the following conditions: > > - * > > - * The above copyright notice and this permission notice shall be included in > > - * all copies or substantial portions of the Software. > > - * > > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM > > - > > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > > - * THE SOFTWARE. > > - */ > > -/* > > - * split out from pci.c > > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - */ > > - > > -#include "pci_bridge.h" > > -#include "pci_internals.h" > > -#include "range.h" > > - > > -/* PCI bridge subsystem vendor ID helper functions */ > > -#define PCI_SSVID_SIZEOF 8 > > -#define PCI_SSVID_SVID 4 > > -#define PCI_SSVID_SSID 6 > > - > > -int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, > > - uint16_t svid, uint16_t ssid) > > -{ > > - int pos; > > - pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF); > > - if (pos < 0) { > > - return pos; > > - } > > - > > - pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid); > > - pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid); > > - return pos; > > -} > > - > > -/* Accessor function to get parent bridge device from pci bus. */ > > -PCIDevice *pci_bridge_get_device(PCIBus *bus) > > -{ > > - return bus->parent_dev; > > -} > > - > > -/* Accessor function to get secondary bus from pci-to-pci bridge device */ > > -PCIBus *pci_bridge_get_sec_bus(PCIBridge *br) > > -{ > > - return &br->sec_bus; > > -} > > - > > -static uint32_t pci_config_get_io_base(const PCIDevice *d, > > - uint32_t base, uint32_t base_upper16) > > -{ > > - uint32_t val; > > - > > - val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8; > > - if (d->config[base] & PCI_IO_RANGE_TYPE_32) { > > - val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16; > > - } > > - return val; > > -} > > - > > -static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base) > > -{ > > - return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) > > - << 16; > > -} > > - > > -static pcibus_t pci_config_get_pref_base(const PCIDevice *d, > > - uint32_t base, uint32_t upper) > > -{ > > - pcibus_t tmp; > > - pcibus_t val; > > - > > - tmp = (pcibus_t)pci_get_word(d->config + base); > > - val = (tmp & PCI_PREF_RANGE_MASK) << 16; > > - if (tmp & PCI_PREF_RANGE_TYPE_64) { > > - val |= (pcibus_t)pci_get_long(d->config + upper) << 32; > > - } > > - return val; > > -} > > - > > -/* accessor function to get bridge filtering base address */ > > -pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type) > > -{ > > - pcibus_t base; > > - if (type & PCI_BASE_ADDRESS_SPACE_IO) { > > - base = pci_config_get_io_base(bridge, > > - PCI_IO_BASE, PCI_IO_BASE_UPPER16); > > - } else { > > - if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > > - base = pci_config_get_pref_base( > > - bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32); > > - } else { > > - base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE); > > - } > > - } > > - > > - return base; > > -} > > - > > -/* accessor funciton to get bridge filtering limit */ > > -pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type) > > -{ > > - pcibus_t limit; > > - if (type & PCI_BASE_ADDRESS_SPACE_IO) { > > - limit = pci_config_get_io_base(bridge, > > - PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16); > > - limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */ > > - } else { > > - if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > > - limit = pci_config_get_pref_base( > > - bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32); > > - } else { > > - limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT); > > - } > > - limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */ > > - } > > - return limit; > > -} > > - > > -static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, > > - uint8_t type, const char *name, > > - MemoryRegion *space, > > - MemoryRegion *parent_space, > > - bool enabled) > > -{ > > - pcibus_t base = pci_bridge_get_base(&bridge->dev, type); > > - pcibus_t limit = pci_bridge_get_limit(&bridge->dev, type); > > - /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly. > > - * Apparently no way to do this with existing memory APIs. */ > > - pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0; > > - > > - memory_region_init_alias(alias, name, space, base, size); > > - memory_region_add_subregion_overlap(parent_space, base, alias, 1); > > -} > > - > > -static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) > > -{ > > - PCIBus *parent = br->dev.bus; > > - PCIBridgeWindows *w = g_new(PCIBridgeWindows, 1); > > - uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND); > > - > > - pci_bridge_init_alias(br, &w->alias_pref_mem, > > - PCI_BASE_ADDRESS_MEM_PREFETCH, > > - "pci_bridge_pref_mem", > > - &br->address_space_mem, > > - parent->address_space_mem, > > - cmd & PCI_COMMAND_MEMORY); > > - pci_bridge_init_alias(br, &w->alias_mem, > > - PCI_BASE_ADDRESS_SPACE_MEMORY, > > - "pci_bridge_mem", > > - &br->address_space_mem, > > - parent->address_space_mem, > > - cmd & PCI_COMMAND_MEMORY); > > - pci_bridge_init_alias(br, &w->alias_io, > > - PCI_BASE_ADDRESS_SPACE_IO, > > - "pci_bridge_io", > > - &br->address_space_io, > > - parent->address_space_io, > > - cmd & PCI_COMMAND_IO); > > - /* TODO: optinal VGA and VGA palette snooping support. */ > > - > > - return w; > > -} > > - > > -static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w) > > -{ > > - PCIBus *parent = br->dev.bus; > > - > > - memory_region_del_subregion(parent->address_space_io, &w->alias_io); > > - memory_region_del_subregion(parent->address_space_mem, &w->alias_mem); > > - memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem); > > -} > > - > > -static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w) > > -{ > > - memory_region_destroy(&w->alias_io); > > - memory_region_destroy(&w->alias_mem); > > - memory_region_destroy(&w->alias_pref_mem); > > - g_free(w); > > -} > > - > > -static void pci_bridge_update_mappings(PCIBridge *br) > > -{ > > - PCIBridgeWindows *w = br->windows; > > - > > - /* Make updates atomic to: handle the case of one VCPU updating the bridge > > - * while another accesses an unaffected region. */ > > - memory_region_transaction_begin(); > > - pci_bridge_region_del(br, br->windows); > > - br->windows = pci_bridge_region_init(br); > > - memory_region_transaction_commit(); > > - pci_bridge_region_cleanup(br, w); > > -} > > - > > -/* default write_config function for PCI-to-PCI bridge */ > > -void pci_bridge_write_config(PCIDevice *d, > > - uint32_t address, uint32_t val, int len) > > -{ > > - PCIBridge *s = container_of(d, PCIBridge, dev); > > - uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); > > - uint16_t newctl; > > - > > - pci_default_write_config(d, address, val, len); > > - > > - if (ranges_overlap(address, len, PCI_COMMAND, 2) || > > - > > - /* io base/limit */ > > - ranges_overlap(address, len, PCI_IO_BASE, 2) || > > - > > - /* memory base/limit, prefetchable base/limit and > > - io base/limit upper 16 */ > > - ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { > > - pci_bridge_update_mappings(s); > > - } > > - > > - newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); > > - if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) { > > - /* Trigger hot reset on 0->1 transition. */ > > - pci_bus_reset(&s->sec_bus); > > - } > > -} > > - > > -void pci_bridge_disable_base_limit(PCIDevice *dev) > > -{ > > - uint8_t *conf = dev->config; > > - > > - pci_byte_test_and_set_mask(conf + PCI_IO_BASE, > > - PCI_IO_RANGE_MASK & 0xff); > > - pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, > > - PCI_IO_RANGE_MASK & 0xff); > > - pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE, > > - PCI_MEMORY_RANGE_MASK & 0xffff); > > - pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, > > - PCI_MEMORY_RANGE_MASK & 0xffff); > > - pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE, > > - PCI_PREF_RANGE_MASK & 0xffff); > > - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, > > - PCI_PREF_RANGE_MASK & 0xffff); > > - pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); > > - pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); > > -} > > - > > -/* reset bridge specific configuration registers */ > > -void pci_bridge_reset(DeviceState *qdev) > > -{ > > - PCIDevice *dev = PCI_DEVICE(qdev); > > - uint8_t *conf = dev->config; > > - > > - conf[PCI_PRIMARY_BUS] = 0; > > - conf[PCI_SECONDARY_BUS] = 0; > > - conf[PCI_SUBORDINATE_BUS] = 0; > > - conf[PCI_SEC_LATENCY_TIMER] = 0; > > - > > - /* > > - * the default values for base/limit registers aren't specified > > - * in the PCI-to-PCI-bridge spec. So we don't thouch them here. > > - * Each implementation can override it. > > - * typical implementation does > > - * zero base/limit registers or > > - * disable forwarding: pci_bridge_disable_base_limit() > > - * If disable forwarding is wanted, call pci_bridge_disable_base_limit() > > - * after this function. > > - */ > > - pci_byte_test_and_clear_mask(conf + PCI_IO_BASE, > > - PCI_IO_RANGE_MASK & 0xff); > > - pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, > > - PCI_IO_RANGE_MASK & 0xff); > > - pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE, > > - PCI_MEMORY_RANGE_MASK & 0xffff); > > - pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT, > > - PCI_MEMORY_RANGE_MASK & 0xffff); > > - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE, > > - PCI_PREF_RANGE_MASK & 0xffff); > > - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT, > > - PCI_PREF_RANGE_MASK & 0xffff); > > - pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0); > > - pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0); > > - > > - pci_set_word(conf + PCI_BRIDGE_CONTROL, 0); > > -} > > - > > -/* default qdev initialization function for PCI-to-PCI bridge */ > > -int pci_bridge_initfn(PCIDevice *dev) > > -{ > > - PCIBus *parent = dev->bus; > > - PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); > > - PCIBus *sec_bus = &br->sec_bus; > > - > > - pci_word_test_and_set_mask(dev->config + PCI_STATUS, > > - PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); > > - pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI); > > - dev->config[PCI_HEADER_TYPE] = > > - (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) | > > - PCI_HEADER_TYPE_BRIDGE; > > - pci_set_word(dev->config + PCI_SEC_STATUS, > > - PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); > > - > > - /* > > - * If we don't specify the name, the bus will be addressed as <id>.0, where > > - * id is the device id. > > - * Since PCI Bridge devices have a single bus each, we don't need the index: > > - * let users address the bus using the device name. > > - */ > > - if (!br->bus_name && dev->qdev.id && *dev->qdev.id) { > > - br->bus_name = dev->qdev.id; > > - } > > - > > - qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev, > > - br->bus_name); > > - sec_bus->parent_dev = dev; > > - sec_bus->map_irq = br->map_irq; > > - sec_bus->address_space_mem = &br->address_space_mem; > > - memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX); > > - sec_bus->address_space_io = &br->address_space_io; > > - memory_region_init(&br->address_space_io, "pci_bridge_io", 65536); > > - br->windows = pci_bridge_region_init(br); > > - QLIST_INIT(&sec_bus->child); > > - QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); > > - return 0; > > -} > > - > > -/* default qdev clean up function for PCI-to-PCI bridge */ > > -void pci_bridge_exitfn(PCIDevice *pci_dev) > > -{ > > - PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); > > - assert(QLIST_EMPTY(&s->sec_bus.child)); > > - QLIST_REMOVE(&s->sec_bus, sibling); > > - pci_bridge_region_del(s, s->windows); > > - pci_bridge_region_cleanup(s, s->windows); > > - memory_region_destroy(&s->address_space_mem); > > - memory_region_destroy(&s->address_space_io); > > - /* qbus_free() is called automatically by qdev_free() */ > > -} > > - > > -/* > > - * before qdev initialization(qdev_init()), this function sets bus_name and > > - * map_irq callback which are necessry for pci_bridge_initfn() to > > - * initialize bus. > > - */ > > -void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, > > - pci_map_irq_fn map_irq) > > -{ > > - br->map_irq = map_irq; > > - br->bus_name = bus_name; > > -} > > diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h > > deleted file mode 100644 > > index a00accc..0000000 > > --- a/hw/pci_bridge.h > > +++ /dev/null > > @@ -1,66 +0,0 @@ > > -/* > > - * QEMU PCI bridge > > - * > > - * Copyright (c) 2004 Fabrice Bellard > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - * > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - * > > - * You should have received a copy of the GNU General Public License > > - * along with this program; if not, write to the Free Software > > - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > > - * > > - * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc] > > - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - */ > > - > > -#ifndef QEMU_PCI_BRIDGE_H > > -#define QEMU_PCI_BRIDGE_H > > - > > -#include "pci.h" > > - > > -int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, > > - uint16_t svid, uint16_t ssid); > > - > > -PCIDevice *pci_bridge_get_device(PCIBus *bus); > > -PCIBus *pci_bridge_get_sec_bus(PCIBridge *br); > > - > > -pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type); > > -pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type); > > - > > -void pci_bridge_write_config(PCIDevice *d, > > - uint32_t address, uint32_t val, int len); > > -void pci_bridge_disable_base_limit(PCIDevice *dev); > > -void pci_bridge_reset_reg(PCIDevice *dev); > > -void pci_bridge_reset(DeviceState *qdev); > > - > > -int pci_bridge_initfn(PCIDevice *pci_dev); > > -void pci_bridge_exitfn(PCIDevice *pci_dev); > > - > > - > > -/* > > - * before qdev initialization(qdev_init()), this function sets bus_name and > > - * map_irq callback which are necessry for pci_bridge_initfn() to > > - * initialize bus. > > - */ > > -void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, > > - pci_map_irq_fn map_irq); > > - > > -#endif /* QEMU_PCI_BRIDGE_H */ > > -/* > > - * Local variables: > > - * c-indent-level: 4 > > - * c-basic-offset: 4 > > - * tab-width: 8 > > - * indent-tab-mode: nil > > - * End: > > - */ > > diff --git a/hw/pci_host.c b/hw/pci_host.c > > deleted file mode 100644 > > index 68e328c..0000000 > > --- a/hw/pci_host.c > > +++ /dev/null > > @@ -1,180 +0,0 @@ > > -/* > > - * pci_host.c > > - * > > - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#include "pci.h" > > -#include "pci_host.h" > > - > > -/* debug PCI */ > > -//#define DEBUG_PCI > > - > > -#ifdef DEBUG_PCI > > -#define PCI_DPRINTF(fmt, ...) \ > > -do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0) > > -#else > > -#define PCI_DPRINTF(fmt, ...) > > -#endif > > - > > -/* > > - * PCI address > > - * bit 16 - 24: bus number > > - * bit 8 - 15: devfun number > > - * bit 0 - 7: offset in configuration space of a given pci device > > - */ > > - > > -/* the helper functio to get a PCIDeice* for a given pci address */ > > -static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr) > > -{ > > - uint8_t bus_num = addr >> 16; > > - uint8_t devfn = addr >> 8; > > - > > - return pci_find_device(bus, bus_num, devfn); > > -} > > - > > -void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, > > - uint32_t limit, uint32_t val, uint32_t len) > > -{ > > - assert(len <= 4); > > - pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr)); > > -} > > - > > -uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, > > - uint32_t limit, uint32_t len) > > -{ > > - assert(len <= 4); > > - return pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr)); > > -} > > - > > -void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len) > > -{ > > - PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); > > - uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); > > - > > - if (!pci_dev) { > > - return; > > - } > > - > > - PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n", > > - __func__, pci_dev->name, config_addr, val, len); > > - pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE, > > - val, len); > > -} > > - > > -uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) > > -{ > > - PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); > > - uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); > > - uint32_t val; > > - > > - if (!pci_dev) { > > - return ~0x0; > > - } > > - > > - val = pci_host_config_read_common(pci_dev, config_addr, > > - PCI_CONFIG_SPACE_SIZE, len); > > - PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n", > > - __func__, pci_dev->name, config_addr, val, len); > > - > > - return val; > > -} > > - > > -static void pci_host_config_write(void *opaque, hwaddr addr, > > - uint64_t val, unsigned len) > > -{ > > - PCIHostState *s = opaque; > > - > > - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", > > - __func__, addr, len, val); > > - if (addr != 0 || len != 4) { > > - return; > > - } > > - s->config_reg = val; > > -} > > - > > -static uint64_t pci_host_config_read(void *opaque, hwaddr addr, > > - unsigned len) > > -{ > > - PCIHostState *s = opaque; > > - uint32_t val = s->config_reg; > > - > > - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n", > > - __func__, addr, len, val); > > - return val; > > -} > > - > > -static void pci_host_data_write(void *opaque, hwaddr addr, > > - uint64_t val, unsigned len) > > -{ > > - PCIHostState *s = opaque; > > - PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n", > > - addr, len, (unsigned)val); > > - if (s->config_reg & (1u << 31)) > > - pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); > > -} > > - > > -static uint64_t pci_host_data_read(void *opaque, > > - hwaddr addr, unsigned len) > > -{ > > - PCIHostState *s = opaque; > > - uint32_t val; > > - if (!(s->config_reg & (1 << 31))) > > - return 0xffffffff; > > - val = pci_data_read(s->bus, s->config_reg | (addr & 3), len); > > - PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n", > > - addr, len, val); > > - return val; > > -} > > - > > -const MemoryRegionOps pci_host_conf_le_ops = { > > - .read = pci_host_config_read, > > - .write = pci_host_config_write, > > - .endianness = DEVICE_LITTLE_ENDIAN, > > -}; > > - > > -const MemoryRegionOps pci_host_conf_be_ops = { > > - .read = pci_host_config_read, > > - .write = pci_host_config_write, > > - .endianness = DEVICE_BIG_ENDIAN, > > -}; > > - > > -const MemoryRegionOps pci_host_data_le_ops = { > > - .read = pci_host_data_read, > > - .write = pci_host_data_write, > > - .endianness = DEVICE_LITTLE_ENDIAN, > > -}; > > - > > -const MemoryRegionOps pci_host_data_be_ops = { > > - .read = pci_host_data_read, > > - .write = pci_host_data_write, > > - .endianness = DEVICE_BIG_ENDIAN, > > -}; > > - > > -static const TypeInfo pci_host_type_info = { > > - .name = TYPE_PCI_HOST_BRIDGE, > > - .parent = TYPE_SYS_BUS_DEVICE, > > - .abstract = true, > > - .instance_size = sizeof(PCIHostState), > > -}; > > - > > -static void pci_host_register_types(void) > > -{ > > - type_register_static(&pci_host_type_info); > > -} > > - > > -type_init(pci_host_register_types) > > diff --git a/hw/pci_host.h b/hw/pci_host.h > > deleted file mode 100644 > > index 4b9c300..0000000 > > --- a/hw/pci_host.h > > +++ /dev/null > > @@ -1,62 +0,0 @@ > > -/* > > - * QEMU Common PCI Host bridge configuration data space access routines. > > - * > > - * Copyright (c) 2006 Fabrice Bellard > > - * > > - * Permission is hereby granted, free of charge, to any person obtaining a copy > > - * of this software and associated documentation files (the "Software"), to deal > > - * in the Software without restriction, including without limitation the rights > > - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > > - * copies of the Software, and to permit persons to whom the Software is > > - * furnished to do so, subject to the following conditions: > > - * > > - * The above copyright notice and this permission notice shall be included in > > - * all copies or substantial portions of the Software. > > - * > > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > > - * THE SOFTWARE. > > - */ > > - > > -/* Worker routines for a PCI host controller that uses an {address,data} > > - register pair to access PCI configuration space. */ > > - > > -#ifndef PCI_HOST_H > > -#define PCI_HOST_H > > - > > -#include "sysbus.h" > > - > > -#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge" > > -#define PCI_HOST_BRIDGE(obj) \ > > - OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE) > > - > > -struct PCIHostState { > > - SysBusDevice busdev; > > - > > - MemoryRegion conf_mem; > > - MemoryRegion data_mem; > > - MemoryRegion mmcfg; > > - MemoryRegion *address_space; > > - uint32_t config_reg; > > - PCIBus *bus; > > -}; > > - > > -/* common internal helpers for PCI/PCIe hosts, cut off overflows */ > > -void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, > > - uint32_t limit, uint32_t val, uint32_t len); > > -uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, > > - uint32_t limit, uint32_t len); > > - > > -void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len); > > -uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len); > > - > > -extern const MemoryRegionOps pci_host_conf_le_ops; > > -extern const MemoryRegionOps pci_host_conf_be_ops; > > -extern const MemoryRegionOps pci_host_data_le_ops; > > -extern const MemoryRegionOps pci_host_data_be_ops; > > - > > -#endif /* PCI_HOST_H */ > > diff --git a/hw/pci_ids.h b/hw/pci_ids.h > > deleted file mode 100644 > > index 5df7245..0000000 > > --- a/hw/pci_ids.h > > +++ /dev/null > > @@ -1,147 +0,0 @@ > > -/* > > - * PCI Class, Vendor and Device IDs > > - * > > - * Please keep sorted. > > - * > > - * Abbreviated version of linux/pci_ids.h > > - * > > - * QEMU-specific definitions belong in pci.h > > - */ > > - > > -/* Device classes and subclasses */ > > - > > -#define PCI_BASE_CLASS_STORAGE 0x01 > > -#define PCI_BASE_CLASS_NETWORK 0x02 > > - > > -#define PCI_CLASS_STORAGE_SCSI 0x0100 > > -#define PCI_CLASS_STORAGE_IDE 0x0101 > > -#define PCI_CLASS_STORAGE_RAID 0x0104 > > -#define PCI_CLASS_STORAGE_SATA 0x0106 > > -#define PCI_CLASS_STORAGE_OTHER 0x0180 > > - > > -#define PCI_CLASS_NETWORK_ETHERNET 0x0200 > > - > > -#define PCI_CLASS_DISPLAY_VGA 0x0300 > > -#define PCI_CLASS_DISPLAY_OTHER 0x0380 > > - > > -#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 > > - > > -#define PCI_CLASS_MEMORY_RAM 0x0500 > > - > > -#define PCI_CLASS_SYSTEM_OTHER 0x0880 > > - > > -#define PCI_CLASS_SERIAL_USB 0x0c03 > > -#define PCI_CLASS_SERIAL_SMBUS 0x0c05 > > - > > -#define PCI_CLASS_BRIDGE_HOST 0x0600 > > -#define PCI_CLASS_BRIDGE_ISA 0x0601 > > -#define PCI_CLASS_BRIDGE_PCI 0x0604 > > -#define PCI_CLASS_BRDIGE_PCI_INF_SUB 0x01 > > -#define PCI_CLASS_BRIDGE_OTHER 0x0680 > > - > > -#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 > > -#define PCI_CLASS_COMMUNICATION_OTHER 0x0780 > > - > > -#define PCI_CLASS_PROCESSOR_CO 0x0b40 > > -#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20 > > - > > -#define PCI_CLASS_OTHERS 0xff > > - > > -/* Vendors and devices. Sort key: vendor first, device next. */ > > - > > -#define PCI_VENDOR_ID_LSI_LOGIC 0x1000 > > -#define PCI_DEVICE_ID_LSI_53C895A 0x0012 > > -#define PCI_DEVICE_ID_LSI_SAS1078 0x0060 > > - > > -#define PCI_VENDOR_ID_DEC 0x1011 > > -#define PCI_DEVICE_ID_DEC_21154 0x0026 > > - > > -#define PCI_VENDOR_ID_CIRRUS 0x1013 > > - > > -#define PCI_VENDOR_ID_IBM 0x1014 > > - > > -#define PCI_VENDOR_ID_AMD 0x1022 > > -#define PCI_DEVICE_ID_AMD_LANCE 0x2000 > > -#define PCI_DEVICE_ID_AMD_SCSI 0x2020 > > - > > -#define PCI_VENDOR_ID_TI 0x104c > > - > > -#define PCI_VENDOR_ID_MOTOROLA 0x1057 > > -#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 > > -#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 > > - > > -#define PCI_VENDOR_ID_APPLE 0x106b > > -#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 > > -#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b > > - > > -#define PCI_VENDOR_ID_SUN 0x108e > > -#define PCI_DEVICE_ID_SUN_EBUS 0x1000 > > -#define PCI_DEVICE_ID_SUN_SIMBA 0x5000 > > -#define PCI_DEVICE_ID_SUN_SABRE 0xa000 > > - > > -#define PCI_VENDOR_ID_CMD 0x1095 > > -#define PCI_DEVICE_ID_CMD_646 0x0646 > > - > > -#define PCI_VENDOR_ID_REALTEK 0x10ec > > -#define PCI_DEVICE_ID_REALTEK_8139 0x8139 > > - > > -#define PCI_VENDOR_ID_XILINX 0x10ee > > - > > -#define PCI_VENDOR_ID_VIA 0x1106 > > -#define PCI_DEVICE_ID_VIA_ISA_BRIDGE 0x0686 > > -#define PCI_DEVICE_ID_VIA_IDE 0x0571 > > -#define PCI_DEVICE_ID_VIA_UHCI 0x3038 > > -#define PCI_DEVICE_ID_VIA_ACPI 0x3057 > > -#define PCI_DEVICE_ID_VIA_AC97 0x3058 > > -#define PCI_DEVICE_ID_VIA_MC97 0x3068 > > - > > -#define PCI_VENDOR_ID_MARVELL 0x11ab > > - > > -#define PCI_VENDOR_ID_ENSONIQ 0x1274 > > -#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 > > - > > -#define PCI_VENDOR_ID_FREESCALE 0x1957 > > -#define PCI_DEVICE_ID_MPC8533E 0x0030 > > - > > -#define PCI_VENDOR_ID_INTEL 0x8086 > > -#define PCI_DEVICE_ID_INTEL_82378 0x0484 > > -#define PCI_DEVICE_ID_INTEL_82441 0x1237 > > -#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 > > -#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e > > -#define PCI_DEVICE_ID_INTEL_82801D 0x24CD > > -#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab > > -#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 > > -#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 > > -#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 > > -#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 > > -#define PCI_DEVICE_ID_INTEL_82371AB 0x7111 > > -#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 > > -#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 > > - > > -#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 > > -#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 > > -#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 > > -#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 > > -#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 > > -#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 > > -#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 > > -#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 > > -#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 > > - > > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934 > > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935 > > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936 > > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937 > > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938 > > -#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939 > > -#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a > > -#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c > > -#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed > > - > > -#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 > > - > > -#define PCI_VENDOR_ID_XEN 0x5853 > > -#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 > > - > > -#define PCI_VENDOR_ID_NEC 0x1033 > > -#define PCI_DEVICE_ID_NEC_UPD720200 0x0194 > > diff --git a/hw/pci_internals.h b/hw/pci_internals.h > > deleted file mode 100644 > > index 21d0ce6..0000000 > > --- a/hw/pci_internals.h > > +++ /dev/null > > @@ -1,78 +0,0 @@ > > -#ifndef QEMU_PCI_INTERNALS_H > > -#define QEMU_PCI_INTERNALS_H > > - > > -/* > > - * This header files is private to pci.c and pci_bridge.c > > - * So following structures are opaque to others and shouldn't be > > - * accessed. > > - * > > - * For pci-to-pci bridge needs to include this header file to embed > > - * PCIBridge in its structure or to get sizeof(PCIBridge), > > - * However, they shouldn't access those following members directly. > > - * Use accessor function in pci.h, pci_bridge.h > > - */ > > - > > -#define TYPE_PCI_BUS "PCI" > > -#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) > > - > > -struct PCIBus { > > - BusState qbus; > > - PCIDMAContextFunc dma_context_fn; > > - void *dma_context_opaque; > > - uint8_t devfn_min; > > - pci_set_irq_fn set_irq; > > - pci_map_irq_fn map_irq; > > - pci_route_irq_fn route_intx_to_irq; > > - pci_hotplug_fn hotplug; > > - DeviceState *hotplug_qdev; > > - void *irq_opaque; > > - PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; > > - PCIDevice *parent_dev; > > - MemoryRegion *address_space_mem; > > - MemoryRegion *address_space_io; > > - > > - QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ > > - QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ > > - > > - /* The bus IRQ state is the logical OR of the connected devices. > > - Keep a count of the number of devices with raised IRQs. */ > > - int nirq; > > - int *irq_count; > > -}; > > - > > -typedef struct PCIBridgeWindows PCIBridgeWindows; > > - > > -/* > > - * Aliases for each of the address space windows that the bridge > > - * can forward. Mapped into the bridge's parent's address space, > > - * as subregions. > > - */ > > -struct PCIBridgeWindows { > > - MemoryRegion alias_pref_mem; > > - MemoryRegion alias_mem; > > - MemoryRegion alias_io; > > -}; > > - > > -struct PCIBridge { > > - PCIDevice dev; > > - > > - /* private member */ > > - PCIBus sec_bus; > > - /* > > - * Memory regions for the bridge's address spaces. These regions are not > > - * directly added to system_memory/system_io or its descendants. > > - * Bridge's secondary bus points to these, so that devices > > - * under the bridge see these regions as its address spaces. > > - * The regions are as large as the entire address space - > > - * they don't take into account any windows. > > - */ > > - MemoryRegion address_space_mem; > > - MemoryRegion address_space_io; > > - > > - PCIBridgeWindows *windows; > > - > > - pci_map_irq_fn map_irq; > > - const char *bus_name; > > -}; > > - > > -#endif /* QEMU_PCI_INTERNALS_H */ > > diff --git a/hw/pci_regs.h b/hw/pci_regs.h > > deleted file mode 100644 > > index 56a404b..0000000 > > --- a/hw/pci_regs.h > > +++ /dev/null > > @@ -1,717 +0,0 @@ > > -/* > > - * pci_regs.h > > - * > > - * PCI standard defines > > - * Copyright 1994, Drew Eckhardt > > - * Copyright 1997--1999 Martin Mares <mj@ucw.cz> > > - * > > - * For more information, please consult the following manuals (look at > > - * http://www.pcisig.com/ for how to get them): > > - * > > - * PCI BIOS Specification > > - * PCI Local Bus Specification > > - * PCI to PCI Bridge Specification > > - * PCI System Design Guide > > - * > > - * For hypertransport information, please consult the following manuals > > - * from http://www.hypertransport.org > > - * > > - * The Hypertransport I/O Link Specification > > - */ > > - > > -#ifndef LINUX_PCI_REGS_H > > -#define LINUX_PCI_REGS_H > > - > > -/* > > - * Under PCI, each device has 256 bytes of configuration address space, > > - * of which the first 64 bytes are standardized as follows: > > - */ > > -#define PCI_VENDOR_ID 0x00 /* 16 bits */ > > -#define PCI_DEVICE_ID 0x02 /* 16 bits */ > > -#define PCI_COMMAND 0x04 /* 16 bits */ > > -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ > > -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ > > -#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ > > -#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ > > -#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ > > -#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ > > -#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ > > -#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ > > -#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ > > -#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ > > -#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ > > - > > -#define PCI_STATUS 0x06 /* 16 bits */ > > -#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */ > > -#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ > > -#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ > > -#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ > > -#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ > > -#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ > > -#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ > > -#define PCI_STATUS_DEVSEL_FAST 0x000 > > -#define PCI_STATUS_DEVSEL_MEDIUM 0x200 > > -#define PCI_STATUS_DEVSEL_SLOW 0x400 > > -#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ > > -#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ > > -#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ > > -#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ > > -#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ > > - > > -#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ > > -#define PCI_REVISION_ID 0x08 /* Revision ID */ > > -#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ > > -#define PCI_CLASS_DEVICE 0x0a /* Device class */ > > - > > -#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ > > -#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ > > -#define PCI_HEADER_TYPE 0x0e /* 8 bits */ > > -#define PCI_HEADER_TYPE_NORMAL 0 > > -#define PCI_HEADER_TYPE_BRIDGE 1 > > -#define PCI_HEADER_TYPE_CARDBUS 2 > > - > > -#define PCI_BIST 0x0f /* 8 bits */ > > -#define PCI_BIST_CODE_MASK 0x0f /* Return result */ > > -#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ > > -#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ > > - > > -/* > > - * Base addresses specify locations in memory or I/O space. > > - * Decoded size can be determined by writing a value of > > - * 0xffffffff to the register, and reading it back. Only > > - * 1 bits are decoded. > > - */ > > -#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ > > -#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ > > -#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ > > -#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ > > -#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ > > -#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ > > -#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ > > -#define PCI_BASE_ADDRESS_SPACE_IO 0x01 > > -#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 > > -#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 > > -#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ > > -#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ > > -#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ > > -#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ > > -#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) > > -#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) > > -/* bit 1 is reserved if address_space = 1 */ > > - > > -/* Header type 0 (normal devices) */ > > -#define PCI_CARDBUS_CIS 0x28 > > -#define PCI_SUBSYSTEM_VENDOR_ID 0x2c > > -#define PCI_SUBSYSTEM_ID 0x2e > > -#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ > > -#define PCI_ROM_ADDRESS_ENABLE 0x01 > > -#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) > > - > > -#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ > > - > > -/* 0x35-0x3b are reserved */ > > -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ > > -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ > > -#define PCI_MIN_GNT 0x3e /* 8 bits */ > > -#define PCI_MAX_LAT 0x3f /* 8 bits */ > > - > > -/* Header type 1 (PCI-to-PCI bridges) */ > > -#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ > > -#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ > > -#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ > > -#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ > > -#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ > > -#define PCI_IO_LIMIT 0x1d > > -#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ > > -#define PCI_IO_RANGE_TYPE_16 0x00 > > -#define PCI_IO_RANGE_TYPE_32 0x01 > > -#define PCI_IO_RANGE_MASK (~0x0fUL) > > -#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ > > -#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ > > -#define PCI_MEMORY_LIMIT 0x22 > > -#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL > > -#define PCI_MEMORY_RANGE_MASK (~0x0fUL) > > -#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ > > -#define PCI_PREF_MEMORY_LIMIT 0x26 > > -#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL > > -#define PCI_PREF_RANGE_TYPE_32 0x00 > > -#define PCI_PREF_RANGE_TYPE_64 0x01 > > -#define PCI_PREF_RANGE_MASK (~0x0fUL) > > -#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ > > -#define PCI_PREF_LIMIT_UPPER32 0x2c > > -#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ > > -#define PCI_IO_LIMIT_UPPER16 0x32 > > -/* 0x34 same as for htype 0 */ > > -/* 0x35-0x3b is reserved */ > > -#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ > > -/* 0x3c-0x3d are same as for htype 0 */ > > -#define PCI_BRIDGE_CONTROL 0x3e > > -#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ > > -#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ > > -#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */ > > -#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ > > -#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ > > -#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ > > -#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ > > - > > -/* Header type 2 (CardBus bridges) */ > > -#define PCI_CB_CAPABILITY_LIST 0x14 > > -/* 0x15 reserved */ > > -#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */ > > -#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */ > > -#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */ > > -#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */ > > -#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ > > -#define PCI_CB_MEMORY_BASE_0 0x1c > > -#define PCI_CB_MEMORY_LIMIT_0 0x20 > > -#define PCI_CB_MEMORY_BASE_1 0x24 > > -#define PCI_CB_MEMORY_LIMIT_1 0x28 > > -#define PCI_CB_IO_BASE_0 0x2c > > -#define PCI_CB_IO_BASE_0_HI 0x2e > > -#define PCI_CB_IO_LIMIT_0 0x30 > > -#define PCI_CB_IO_LIMIT_0_HI 0x32 > > -#define PCI_CB_IO_BASE_1 0x34 > > -#define PCI_CB_IO_BASE_1_HI 0x36 > > -#define PCI_CB_IO_LIMIT_1 0x38 > > -#define PCI_CB_IO_LIMIT_1_HI 0x3a > > -#define PCI_CB_IO_RANGE_MASK (~0x03UL) > > -/* 0x3c-0x3d are same as for htype 0 */ > > -#define PCI_CB_BRIDGE_CONTROL 0x3e > > -#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */ > > -#define PCI_CB_BRIDGE_CTL_SERR 0x02 > > -#define PCI_CB_BRIDGE_CTL_ISA 0x04 > > -#define PCI_CB_BRIDGE_CTL_VGA 0x08 > > -#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20 > > -#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */ > > -#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */ > > -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */ > > -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200 > > -#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400 > > -#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 > > -#define PCI_CB_SUBSYSTEM_ID 0x42 > > -#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */ > > -/* 0x48-0x7f reserved */ > > - > > -/* Capability lists */ > > - > > -#define PCI_CAP_LIST_ID 0 /* Capability ID */ > > -#define PCI_CAP_ID_PM 0x01 /* Power Management */ > > -#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ > > -#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ > > -#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ > > -#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ > > -#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ > > -#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ > > -#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ > > -#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */ > > -#define PCI_CAP_ID_DBG 0x0A /* Debug port */ > > -#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ > > -#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ > > -#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ > > -#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ > > -#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ > > -#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ > > -#define PCI_CAP_ID_SATA 0x12 /* Serial ATA */ > > -#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ > > -#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ > > -#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ > > -#define PCI_CAP_SIZEOF 4 > > - > > -/* Power Management Registers */ > > - > > -#define PCI_PM_PMC 2 /* PM Capabilities Register */ > > -#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ > > -#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ > > -#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ > > -#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ > > -#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */ > > -#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ > > -#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ > > -#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ > > -#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ > > -#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ > > -#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ > > -#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ > > -#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ > > -#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ > > -#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */ > > -#define PCI_PM_CTRL 4 /* PM control and status register */ > > -#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ > > -#define PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */ > > -#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ > > -#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ > > -#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ > > -#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ > > -#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ > > -#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ > > -#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ > > -#define PCI_PM_DATA_REGISTER 7 /* (??) */ > > -#define PCI_PM_SIZEOF 8 > > - > > -/* AGP registers */ > > - > > -#define PCI_AGP_VERSION 2 /* BCD version number */ > > -#define PCI_AGP_RFU 3 /* Rest of capability flags */ > > -#define PCI_AGP_STATUS 4 /* Status register */ > > -#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ > > -#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ > > -#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ > > -#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ > > -#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ > > -#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ > > -#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ > > -#define PCI_AGP_COMMAND 8 /* Control register */ > > -#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ > > -#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ > > -#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ > > -#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ > > -#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ > > -#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ > > -#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ > > -#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ > > -#define PCI_AGP_SIZEOF 12 > > - > > -/* Vital Product Data */ > > - > > -#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */ > > -#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */ > > -#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */ > > -#define PCI_VPD_DATA 4 /* 32-bits of data returned here */ > > - > > -/* Slot Identification */ > > - > > -#define PCI_SID_ESR 2 /* Expansion Slot Register */ > > -#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ > > -#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ > > -#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ > > - > > -/* Message Signalled Interrupts registers */ > > - > > -#define PCI_MSI_FLAGS 2 /* Various flags */ > > -#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */ > > -#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */ > > -#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */ > > -#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */ > > -#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */ > > -#define PCI_MSI_RFU 3 /* Rest of capability flags */ > > -#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ > > -#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ > > -#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ > > -#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */ > > -#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ > > -#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ > > - > > -/* MSI-X registers */ > > -#define PCI_MSIX_FLAGS 2 > > -#define PCI_MSIX_FLAGS_QSIZE 0x7FF > > -#define PCI_MSIX_FLAGS_ENABLE (1 << 15) > > -#define PCI_MSIX_FLAGS_MASKALL (1 << 14) > > -#define PCI_MSIX_TABLE 4 > > -#define PCI_MSIX_PBA 8 > > -#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) > > - > > -/* MSI-X entry's format */ > > -#define PCI_MSIX_ENTRY_SIZE 16 > > -#define PCI_MSIX_ENTRY_LOWER_ADDR 0 > > -#define PCI_MSIX_ENTRY_UPPER_ADDR 4 > > -#define PCI_MSIX_ENTRY_DATA 8 > > -#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 > > -#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 > > - > > -/* CompactPCI Hotswap Register */ > > - > > -#define PCI_CHSWP_CSR 2 /* Control and Status Register */ > > -#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */ > > -#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */ > > -#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */ > > -#define PCI_CHSWP_LOO 0x08 /* LED On / Off */ > > -#define PCI_CHSWP_PI 0x30 /* Programming Interface */ > > -#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ > > -#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ > > - > > -/* PCI Advanced Feature registers */ > > - > > -#define PCI_AF_LENGTH 2 > > -#define PCI_AF_CAP 3 > > -#define PCI_AF_CAP_TP 0x01 > > -#define PCI_AF_CAP_FLR 0x02 > > -#define PCI_AF_CTRL 4 > > -#define PCI_AF_CTRL_FLR 0x01 > > -#define PCI_AF_STATUS 5 > > -#define PCI_AF_STATUS_TP 0x01 > > - > > -/* PCI-X registers */ > > - > > -#define PCI_X_CMD 2 /* Modes & Features */ > > -#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ > > -#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ > > -#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ > > -#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ > > -#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ > > -#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ > > -#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ > > - /* Max # of outstanding split transactions */ > > -#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */ > > -#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */ > > -#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */ > > -#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */ > > -#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */ > > -#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */ > > -#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */ > > -#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */ > > -#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ > > -#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */ > > -#define PCI_X_STATUS 4 /* PCI-X capabilities */ > > -#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */ > > -#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */ > > -#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */ > > -#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */ > > -#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */ > > -#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */ > > -#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */ > > -#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count */ > > -#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */ > > -#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */ > > -#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ > > -#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ > > -#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ > > - > > -/* PCI Bridge Subsystem ID registers */ > > - > > -#define PCI_SSVID_VENDOR_ID 4 /* PCI-Bridge subsystem vendor id register */ > > -#define PCI_SSVID_DEVICE_ID 6 /* PCI-Bridge subsystem device id register */ > > - > > -/* PCI Express capability registers */ > > - > > -#define PCI_EXP_FLAGS 2 /* Capabilities register */ > > -#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ > > -#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ > > -#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ > > -#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ > > -#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ > > -#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ > > -#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ > > -#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ > > -#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */ > > -#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ > > -#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ > > -#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ > > -#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ > > -#define PCI_EXP_DEVCAP 4 /* Device capabilities */ > > -#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */ > > -#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */ > > -#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */ > > -#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */ > > -#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */ > > -#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ > > -#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ > > -#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ > > -#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ > > -#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ > > -#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ > > -#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ > > -#define PCI_EXP_DEVCTL 8 /* Device Control */ > > -#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ > > -#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ > > -#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ > > -#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ > > -#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */ > > -#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ > > -#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ > > -#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ > > -#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ > > -#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ > > -#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ > > -#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ > > -#define PCI_EXP_DEVSTA 10 /* Device Status */ > > -#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ > > -#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ > > -#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */ > > -#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */ > > -#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ > > -#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ > > -#define PCI_EXP_LNKCAP 12 /* Link Capabilities */ > > -#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */ > > -#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */ > > -#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */ > > -#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */ > > -#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */ > > -#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* L1 Clock Power Management */ > > -#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Reporting Capable */ > > -#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link Active Reporting Capable */ > > -#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notification Capability */ > > -#define PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */ > > -#define PCI_EXP_LNKCTL 16 /* Link Control */ > > -#define PCI_EXP_LNKCTL_ASPMC 0x0003 /* ASPM Control */ > > -#define PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */ > > -#define PCI_EXP_LNKCTL_LD 0x0010 /* Link Disable */ > > -#define PCI_EXP_LNKCTL_RL 0x0020 /* Retrain Link */ > > -#define PCI_EXP_LNKCTL_CCC 0x0040 /* Common Clock Configuration */ > > -#define PCI_EXP_LNKCTL_ES 0x0080 /* Extended Synch */ > > -#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ > > -#define PCI_EXP_LNKCTL_HAWD 0x0200 /* Hardware Autonomous Width Disable */ > > -#define PCI_EXP_LNKCTL_LBMIE 0x0400 /* Link Bandwidth Management Interrupt Enable */ > > -#define PCI_EXP_LNKCTL_LABIE 0x0800 /* Lnk Autonomous Bandwidth Interrupt Enable */ > > -#define PCI_EXP_LNKSTA 18 /* Link Status */ > > -#define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */ > > -#define PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */ > > -#define PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */ > > -#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Nogotiated Link Width */ > > -#define PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */ > > -#define PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */ > > -#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ > > -#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ > > -#define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ > > -#define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */ > > -#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ > > -#define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */ > > -#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */ > > -#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */ > > -#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Present */ > > -#define PCI_EXP_SLTCAP_PIP 0x00000010 /* Power Indicator Present */ > > -#define PCI_EXP_SLTCAP_HPS 0x00000020 /* Hot-Plug Surprise */ > > -#define PCI_EXP_SLTCAP_HPC 0x00000040 /* Hot-Plug Capable */ > > -#define PCI_EXP_SLTCAP_SPLV 0x00007f80 /* Slot Power Limit Value */ > > -#define PCI_EXP_SLTCAP_SPLS 0x00018000 /* Slot Power Limit Scale */ > > -#define PCI_EXP_SLTCAP_EIP 0x00020000 /* Electromechanical Interlock Present */ > > -#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Support */ > > -#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ > > -#define PCI_EXP_SLTCTL 24 /* Slot Control */ > > -#define PCI_EXP_SLTCTL_ABPE 0x0001 /* Attention Button Pressed Enable */ > > -#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enable */ > > -#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable */ > > -#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed Enable */ > > -#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable */ > > -#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */ > > -#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */ > > -#define PCI_EXP_SLTCTL_PIC 0x0300 /* Power Indicator Control */ > > -#define PCI_EXP_SLTCTL_PCC 0x0400 /* Power Controller Control */ > > -#define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */ > > -#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */ > > -#define PCI_EXP_SLTSTA 26 /* Slot Status */ > > -#define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */ > > -#define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */ > > -#define PCI_EXP_SLTSTA_MRLSC 0x0004 /* MRL Sensor Changed */ > > -#define PCI_EXP_SLTSTA_PDC 0x0008 /* Presence Detect Changed */ > > -#define PCI_EXP_SLTSTA_CC 0x0010 /* Command Completed */ > > -#define PCI_EXP_SLTSTA_MRLSS 0x0020 /* MRL Sensor State */ > > -#define PCI_EXP_SLTSTA_PDS 0x0040 /* Presence Detect State */ > > -#define PCI_EXP_SLTSTA_EIS 0x0080 /* Electromechanical Interlock Status */ > > -#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Changed */ > > -#define PCI_EXP_RTCTL 28 /* Root Control */ > > -#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctable Error */ > > -#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal Error */ > > -#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Error */ > > -#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */ > > -#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */ > > -#define PCI_EXP_RTCAP 30 /* Root Capabilities */ > > -#define PCI_EXP_RTSTA 32 /* Root Status */ > > -#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ > > -#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ > > -#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ > > -#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ > > -#define PCI_EXP_DEVCAP2_LTR 0x800 /* Latency tolerance reporting */ > > -#define PCI_EXP_OBFF_MASK 0xc0000 /* OBFF support mechanism */ > > -#define PCI_EXP_OBFF_MSG 0x40000 /* New message signaling */ > > -#define PCI_EXP_OBFF_WAKE 0x80000 /* Re-use WAKE# for OBFF */ > > -#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ > > -#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */ > > -#define PCI_EXP_IDO_REQ_EN 0x100 /* ID-based ordering request enable */ > > -#define PCI_EXP_IDO_CMP_EN 0x200 /* ID-based ordering completion enable */ > > -#define PCI_EXP_LTR_EN 0x400 /* Latency tolerance reporting */ > > -#define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message type A */ > > -#define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message type B */ > > -#define PCI_EXP_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ > > -#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ > > -#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ > > - > > -/* Extended Capabilities (PCI-X 2.0 and Express) */ > > -#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff) > > -#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf) > > -#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc) > > - > > -#define PCI_EXT_CAP_ID_ERR 1 > > -#define PCI_EXT_CAP_ID_VC 2 > > -#define PCI_EXT_CAP_ID_DSN 3 > > -#define PCI_EXT_CAP_ID_PWR 4 > > -#define PCI_EXT_CAP_ID_VNDR 11 > > -#define PCI_EXT_CAP_ID_ACS 13 > > -#define PCI_EXT_CAP_ID_ARI 14 > > -#define PCI_EXT_CAP_ID_ATS 15 > > -#define PCI_EXT_CAP_ID_SRIOV 16 > > -#define PCI_EXT_CAP_ID_LTR 24 > > - > > -/* Advanced Error Reporting */ > > -#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ > > -#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */ > > -#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ > > -#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */ > > -#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */ > > -#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */ > > -#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */ > > -#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */ > > -#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */ > > -#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */ > > -#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */ > > -#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */ > > -#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */ > > - /* Same bits as above */ > > -#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */ > > - /* Same bits as above */ > > -#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */ > > -#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */ > > -#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */ > > -#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */ > > -#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */ > > -#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */ > > -#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ > > - /* Same bits as above */ > > -#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ > > -#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */ > > -#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */ > > -#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */ > > -#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */ > > -#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ > > -#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */ > > -#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */ > > -/* Correctable Err Reporting Enable */ > > -#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 > > -/* Non-fatal Err Reporting Enable */ > > -#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 > > -/* Fatal Err Reporting Enable */ > > -#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 > > -#define PCI_ERR_ROOT_STATUS 48 > > -#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ > > -/* Multi ERR_COR Received */ > > -#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 > > -/* ERR_FATAL/NONFATAL Recevied */ > > -#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 > > -/* Multi ERR_FATAL/NONFATAL Recevied */ > > -#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 > > -#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */ > > -#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ > > -#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ > > -#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */ > > - > > -/* Virtual Channel */ > > -#define PCI_VC_PORT_REG1 4 > > -#define PCI_VC_PORT_REG2 8 > > -#define PCI_VC_PORT_CTRL 12 > > -#define PCI_VC_PORT_STATUS 14 > > -#define PCI_VC_RES_CAP 16 > > -#define PCI_VC_RES_CTRL 20 > > -#define PCI_VC_RES_STATUS 26 > > - > > -/* Power Budgeting */ > > -#define PCI_PWR_DSR 4 /* Data Select Register */ > > -#define PCI_PWR_DATA 8 /* Data Register */ > > -#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */ > > -#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */ > > -#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */ > > -#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */ > > -#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */ > > -#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */ > > -#define PCI_PWR_CAP 12 /* Capability */ > > -#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ > > - > > -/* > > - * Hypertransport sub capability types > > - * > > - * Unfortunately there are both 3 bit and 5 bit capability types defined > > - * in the HT spec, catering for that is a little messy. You probably don't > > - * want to use these directly, just use pci_find_ht_capability() and it > > - * will do the right thing for you. > > - */ > > -#define HT_3BIT_CAP_MASK 0xE0 > > -#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ > > -#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ > > - > > -#define HT_5BIT_CAP_MASK 0xF8 > > -#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ > > -#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ > > -#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ > > -#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */ > > -#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */ > > -#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */ > > -#define HT_MSI_FLAGS 0x02 /* Offset to flags */ > > -#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */ > > -#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */ > > -#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */ > > -#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */ > > -#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */ > > -#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */ > > -#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */ > > -#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */ > > -#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */ > > -#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */ > > -#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */ > > - > > -/* Alternative Routing-ID Interpretation */ > > -#define PCI_ARI_CAP 0x04 /* ARI Capability Register */ > > -#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */ > > -#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */ > > -#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */ > > -#define PCI_ARI_CTRL 0x06 /* ARI Control Register */ > > -#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */ > > -#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ > > -#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ > > - > > -/* Address Translation Service */ > > -#define PCI_ATS_CAP 0x04 /* ATS Capability Register */ > > -#define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f) /* Invalidate Queue Depth */ > > -#define PCI_ATS_MAX_QDEP 32 /* Max Invalidate Queue Depth */ > > -#define PCI_ATS_CTRL 0x06 /* ATS Control Register */ > > -#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */ > > -#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */ > > -#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */ > > - > > -/* Single Root I/O Virtualization */ > > -#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ > > -#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ > > -#define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */ > > -#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */ > > -#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */ > > -#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */ > > -#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */ > > -#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */ > > -#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */ > > -#define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */ > > -#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */ > > -#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */ > > -#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */ > > -#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */ > > -#define PCI_SRIOV_FUNC_LINK 0x12 /* Function Dependency Link */ > > -#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */ > > -#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */ > > -#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */ > > -#define PCI_SRIOV_SUP_PGSIZE 0x1c /* Supported Page Sizes */ > > -#define PCI_SRIOV_SYS_PGSIZE 0x20 /* System Page Size */ > > -#define PCI_SRIOV_BAR 0x24 /* VF BAR0 */ > > -#define PCI_SRIOV_NUM_BARS 6 /* Number of VF BARs */ > > -#define PCI_SRIOV_VFM 0x3c /* VF Migration State Array Offset*/ > > -#define PCI_SRIOV_VFM_BIR(x) ((x) & 7) /* State BIR */ > > -#define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7) /* State Offset */ > > -#define PCI_SRIOV_VFM_UA 0x0 /* Inactive.Unavailable */ > > -#define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */ > > -#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ > > -#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ > > - > > -#define PCI_LTR_MAX_SNOOP_LAT 0x4 > > -#define PCI_LTR_MAX_NOSNOOP_LAT 0x6 > > -#define PCI_LTR_VALUE_MASK 0x000003ff > > -#define PCI_LTR_SCALE_MASK 0x00001c00 > > -#define PCI_LTR_SCALE_SHIFT 10 > > - > > -/* Access Control Service */ > > -#define PCI_ACS_CAP 0x04 /* ACS Capability Register */ > > -#define PCI_ACS_SV 0x01 /* Source Validation */ > > -#define PCI_ACS_TB 0x02 /* Translation Blocking */ > > -#define PCI_ACS_RR 0x04 /* P2P Request Redirect */ > > -#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */ > > -#define PCI_ACS_UF 0x10 /* Upstream Forwarding */ > > -#define PCI_ACS_EC 0x20 /* P2P Egress Control */ > > -#define PCI_ACS_DT 0x40 /* Direct Translated P2P */ > > -#define PCI_ACS_CTRL 0x06 /* ACS Control Register */ > > -#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ > > - > > -#endif /* LINUX_PCI_REGS_H */ > > diff --git a/hw/pcie.c b/hw/pcie.c > > deleted file mode 100644 > > index 7c92f19..0000000 > > --- a/hw/pcie.c > > +++ /dev/null > > @@ -1,555 +0,0 @@ > > -/* > > - * pcie.c > > - * > > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - * > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - * > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#include "qemu-common.h" > > -#include "pci_bridge.h" > > -#include "pcie.h" > > -#include "msix.h" > > -#include "msi.h" > > -#include "pci_internals.h" > > -#include "pcie_regs.h" > > -#include "range.h" > > - > > -//#define DEBUG_PCIE > > -#ifdef DEBUG_PCIE > > -# define PCIE_DPRINTF(fmt, ...) \ > > - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > > -#else > > -# define PCIE_DPRINTF(fmt, ...) do {} while (0) > > -#endif > > -#define PCIE_DEV_PRINTF(dev, fmt, ...) \ > > - PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > > - > > - > > -/*************************************************************************** > > - * pci express capability helper functions > > - */ > > -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) > > -{ > > - int pos; > > - uint8_t *exp_cap; > > - > > - assert(pci_is_express(dev)); > > - > > - pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, > > - PCI_EXP_VER2_SIZEOF); > > - if (pos < 0) { > > - return pos; > > - } > > - dev->exp.exp_cap = pos; > > - exp_cap = dev->config + pos; > > - > > - /* capability register > > - interrupt message number defaults to 0 */ > > - pci_set_word(exp_cap + PCI_EXP_FLAGS, > > - ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) | > > - PCI_EXP_FLAGS_VER2); > > - > > - /* device capability register > > - * table 7-12: > > - * roll based error reporting bit must be set by all > > - * Functions conforming to the ECN, PCI Express Base > > - * Specification, Revision 1.1., or subsequent PCI Express Base > > - * Specification revisions. > > - */ > > - pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER); > > - > > - pci_set_long(exp_cap + PCI_EXP_LNKCAP, > > - (port << PCI_EXP_LNKCAP_PN_SHIFT) | > > - PCI_EXP_LNKCAP_ASPMS_0S | > > - PCI_EXP_LNK_MLW_1 | > > - PCI_EXP_LNK_LS_25); > > - > > - pci_set_word(exp_cap + PCI_EXP_LNKSTA, > > - PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25); > > - > > - pci_set_long(exp_cap + PCI_EXP_DEVCAP2, > > - PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP); > > - > > - pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB); > > - return pos; > > -} > > - > > -void pcie_cap_exit(PCIDevice *dev) > > -{ > > - pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF); > > -} > > - > > -uint8_t pcie_cap_get_type(const PCIDevice *dev) > > -{ > > - uint32_t pos = dev->exp.exp_cap; > > - assert(pos > 0); > > - return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) & > > - PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT; > > -} > > - > > -/* MSI/MSI-X */ > > -/* pci express interrupt message number */ > > -/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */ > > -void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector) > > -{ > > - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > > - assert(vector < 32); > > - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ); > > - pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS, > > - vector << PCI_EXP_FLAGS_IRQ_SHIFT); > > -} > > - > > -uint8_t pcie_cap_flags_get_vector(PCIDevice *dev) > > -{ > > - return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) & > > - PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT; > > -} > > - > > -void pcie_cap_deverr_init(PCIDevice *dev) > > -{ > > - uint32_t pos = dev->exp.exp_cap; > > - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP, > > - PCI_EXP_DEVCAP_RBER); > > - pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL, > > - PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | > > - PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); > > - pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA, > > - PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED | > > - PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD); > > -} > > - > > -void pcie_cap_deverr_reset(PCIDevice *dev) > > -{ > > - uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; > > - pci_long_test_and_clear_mask(devctl, > > - PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | > > - PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); > > -} > > - > > -static void hotplug_event_update_event_status(PCIDevice *dev) > > -{ > > - uint32_t pos = dev->exp.exp_cap; > > - uint8_t *exp_cap = dev->config + pos; > > - uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL); > > - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > > - > > - dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) && > > - (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED); > > -} > > - > > -static void hotplug_event_notify(PCIDevice *dev) > > -{ > > - bool prev = dev->exp.hpev_notified; > > - > > - hotplug_event_update_event_status(dev); > > - > > - if (prev == dev->exp.hpev_notified) { > > - return; > > - } > > - > > - /* Note: the logic above does not take into account whether interrupts > > - * are masked. The result is that interrupt will be sent when it is > > - * subsequently unmasked. This appears to be legal: Section 6.7.3.4: > > - * The Port may optionally send an MSI when there are hot-plug events that > > - * occur while interrupt generation is disabled, and interrupt generation is > > - * subsequently enabled. */ > > - if (msix_enabled(dev)) { > > - msix_notify(dev, pcie_cap_flags_get_vector(dev)); > > - } else if (msi_enabled(dev)) { > > - msi_notify(dev, pcie_cap_flags_get_vector(dev)); > > - } else { > > - qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified); > > - } > > -} > > - > > -static void hotplug_event_clear(PCIDevice *dev) > > -{ > > - hotplug_event_update_event_status(dev); > > - if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) { > > - qemu_set_irq(dev->irq[dev->exp.hpev_intx], 0); > > - } > > -} > > - > > -/* > > - * A PCI Express Hot-Plug Event has occurred, so update slot status register > > - * and notify OS of the event if necessary. > > - * > > - * 6.7.3 PCI Express Hot-Plug Events > > - * 6.7.3.4 Software Notification of Hot-Plug Events > > - */ > > -static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) > > -{ > > - /* Minor optimization: if nothing changed - no event is needed. */ > > - if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap + > > - PCI_EXP_SLTSTA, event)) { > > - return; > > - } > > - hotplug_event_notify(dev); > > -} > > - > > -static int pcie_cap_slot_hotplug(DeviceState *qdev, > > - PCIDevice *pci_dev, PCIHotplugState state) > > -{ > > - PCIDevice *d = PCI_DEVICE(qdev); > > - uint8_t *exp_cap = d->config + d->exp.exp_cap; > > - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > > - > > - /* Don't send event when device is enabled during qemu machine creation: > > - * it is present on boot, no hotplug event is necessary. We do send an > > - * event when the device is disabled later. */ > > - if (state == PCI_COLDPLUG_ENABLED) { > > - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, > > - PCI_EXP_SLTSTA_PDS); > > - return 0; > > - } > > - > > - PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state); > > - if (sltsta & PCI_EXP_SLTSTA_EIS) { > > - /* the slot is electromechanically locked. > > - * This error is propagated up to qdev and then to HMP/QMP. > > - */ > > - return -EBUSY; > > - } > > - > > - /* TODO: multifunction hot-plug. > > - * Right now, only a device of function = 0 is allowed to be > > - * hot plugged/unplugged. > > - */ > > - assert(PCI_FUNC(pci_dev->devfn) == 0); > > - > > - if (state == PCI_HOTPLUG_ENABLED) { > > - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, > > - PCI_EXP_SLTSTA_PDS); > > - pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); > > - } else { > > - qdev_free(&pci_dev->qdev); > > - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, > > - PCI_EXP_SLTSTA_PDS); > > - pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); > > - } > > - return 0; > > -} > > - > > -/* pci express slot for pci express root/downstream port > > - PCI express capability slot registers */ > > -void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot) > > -{ > > - uint32_t pos = dev->exp.exp_cap; > > - > > - pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS, > > - PCI_EXP_FLAGS_SLOT); > > - > > - pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP, > > - ~PCI_EXP_SLTCAP_PSN); > > - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP, > > - (slot << PCI_EXP_SLTCAP_PSN_SHIFT) | > > - PCI_EXP_SLTCAP_EIP | > > - PCI_EXP_SLTCAP_HPS | > > - PCI_EXP_SLTCAP_HPC | > > - PCI_EXP_SLTCAP_PIP | > > - PCI_EXP_SLTCAP_AIP | > > - PCI_EXP_SLTCAP_ABP); > > - > > - pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL, > > - PCI_EXP_SLTCTL_PIC | > > - PCI_EXP_SLTCTL_AIC); > > - pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL, > > - PCI_EXP_SLTCTL_PIC_OFF | > > - PCI_EXP_SLTCTL_AIC_OFF); > > - pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, > > - PCI_EXP_SLTCTL_PIC | > > - PCI_EXP_SLTCTL_AIC | > > - PCI_EXP_SLTCTL_HPIE | > > - PCI_EXP_SLTCTL_CCIE | > > - PCI_EXP_SLTCTL_PDCE | > > - PCI_EXP_SLTCTL_ABPE); > > - /* Although reading PCI_EXP_SLTCTL_EIC returns always 0, > > - * make the bit writable here in order to detect 1b is written. > > - * pcie_cap_slot_write_config() test-and-clear the bit, so > > - * this bit always returns 0 to the guest. > > - */ > > - pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, > > - PCI_EXP_SLTCTL_EIC); > > - > > - pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA, > > - PCI_EXP_HP_EV_SUPPORTED); > > - > > - dev->exp.hpev_notified = false; > > - > > - pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)), > > - pcie_cap_slot_hotplug, &dev->qdev); > > -} > > - > > -void pcie_cap_slot_reset(PCIDevice *dev) > > -{ > > - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > > - > > - PCIE_DEV_PRINTF(dev, "reset\n"); > > - > > - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, > > - PCI_EXP_SLTCTL_EIC | > > - PCI_EXP_SLTCTL_PIC | > > - PCI_EXP_SLTCTL_AIC | > > - PCI_EXP_SLTCTL_HPIE | > > - PCI_EXP_SLTCTL_CCIE | > > - PCI_EXP_SLTCTL_PDCE | > > - PCI_EXP_SLTCTL_ABPE); > > - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL, > > - PCI_EXP_SLTCTL_PIC_OFF | > > - PCI_EXP_SLTCTL_AIC_OFF); > > - > > - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, > > - PCI_EXP_SLTSTA_EIS |/* on reset, > > - the lock is released */ > > - PCI_EXP_SLTSTA_CC | > > - PCI_EXP_SLTSTA_PDC | > > - PCI_EXP_SLTSTA_ABP); > > - > > - hotplug_event_update_event_status(dev); > > -} > > - > > -void pcie_cap_slot_write_config(PCIDevice *dev, > > - uint32_t addr, uint32_t val, int len) > > -{ > > - uint32_t pos = dev->exp.exp_cap; > > - uint8_t *exp_cap = dev->config + pos; > > - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); > > - > > - if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) { > > - hotplug_event_clear(dev); > > - } > > - > > - if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) { > > - return; > > - } > > - > > - if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, > > - PCI_EXP_SLTCTL_EIC)) { > > - sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */ > > - pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta); > > - PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: " > > - "sltsta -> 0x%02"PRIx16"\n", > > - sltsta); > > - } > > - > > - hotplug_event_notify(dev); > > - > > - /* > > - * 6.7.3.2 Command Completed Events > > - * > > - * Software issues a command to a hot-plug capable Downstream Port by > > - * issuing a write transaction that targets any portion of the Port’s Slot > > - * Control register. A single write to the Slot Control register is > > - * considered to be a single command, even if the write affects more than > > - * one field in the Slot Control register. In response to this transaction, > > - * the Port must carry out the requested actions and then set the > > - * associated status field for the command completed event. */ > > - > > - /* Real hardware might take a while to complete requested command because > > - * physical movement would be involved like locking the electromechanical > > - * lock. However in our case, command is completed instantaneously above, > > - * so send a command completion event right now. > > - */ > > - pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI); > > -} > > - > > -int pcie_cap_slot_post_load(void *opaque, int version_id) > > -{ > > - PCIDevice *dev = opaque; > > - hotplug_event_update_event_status(dev); > > - return 0; > > -} > > - > > -void pcie_cap_slot_push_attention_button(PCIDevice *dev) > > -{ > > - pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP); > > -} > > - > > -/* root control/capabilities/status. PME isn't emulated for now */ > > -void pcie_cap_root_init(PCIDevice *dev) > > -{ > > - pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL, > > - PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | > > - PCI_EXP_RTCTL_SEFEE); > > -} > > - > > -void pcie_cap_root_reset(PCIDevice *dev) > > -{ > > - pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0); > > -} > > - > > -/* function level reset(FLR) */ > > -void pcie_cap_flr_init(PCIDevice *dev) > > -{ > > - pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP, > > - PCI_EXP_DEVCAP_FLR); > > - > > - /* Although reading BCR_FLR returns always 0, > > - * the bit is made writable here in order to detect the 1b is written > > - * pcie_cap_flr_write_config() test-and-clear the bit, so > > - * this bit always returns 0 to the guest. > > - */ > > - pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL, > > - PCI_EXP_DEVCTL_BCR_FLR); > > -} > > - > > -void pcie_cap_flr_write_config(PCIDevice *dev, > > - uint32_t addr, uint32_t val, int len) > > -{ > > - uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; > > - if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) { > > - /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler > > - so the handler can detect FLR by looking at this bit. */ > > - pci_device_reset(dev); > > - pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR); > > - } > > -} > > - > > -/* Alternative Routing-ID Interpretation (ARI) */ > > -/* ari forwarding support for down stream port */ > > -void pcie_cap_ari_init(PCIDevice *dev) > > -{ > > - uint32_t pos = dev->exp.exp_cap; > > - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2, > > - PCI_EXP_DEVCAP2_ARI); > > - pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2, > > - PCI_EXP_DEVCTL2_ARI); > > -} > > - > > -void pcie_cap_ari_reset(PCIDevice *dev) > > -{ > > - uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2; > > - pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI); > > -} > > - > > -bool pcie_cap_is_ari_enabled(const PCIDevice *dev) > > -{ > > - if (!pci_is_express(dev)) { > > - return false; > > - } > > - if (!dev->exp.exp_cap) { > > - return false; > > - } > > - > > - return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & > > - PCI_EXP_DEVCTL2_ARI; > > -} > > - > > -/************************************************************************** > > - * pci express extended capability allocation functions > > - * uint16_t ext_cap_id (16 bit) > > - * uint8_t cap_ver (4 bit) > > - * uint16_t cap_offset (12 bit) > > - * uint16_t ext_cap_size > > - */ > > - > > -static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id, > > - uint16_t *prev_p) > > -{ > > - uint16_t prev = 0; > > - uint16_t next; > > - uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE); > > - > > - if (!header) { > > - /* no extended capability */ > > - next = 0; > > - goto out; > > - } > > - for (next = PCI_CONFIG_SPACE_SIZE; next; > > - prev = next, next = PCI_EXT_CAP_NEXT(header)) { > > - > > - assert(next >= PCI_CONFIG_SPACE_SIZE); > > - assert(next <= PCIE_CONFIG_SPACE_SIZE - 8); > > - > > - header = pci_get_long(dev->config + next); > > - if (PCI_EXT_CAP_ID(header) == cap_id) { > > - break; > > - } > > - } > > - > > -out: > > - if (prev_p) { > > - *prev_p = prev; > > - } > > - return next; > > -} > > - > > -uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id) > > -{ > > - return pcie_find_capability_list(dev, cap_id, NULL); > > -} > > - > > -static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next) > > -{ > > - uint16_t header = pci_get_long(dev->config + pos); > > - assert(!(next & (PCI_EXT_CAP_ALIGN - 1))); > > - header = (header & ~PCI_EXT_CAP_NEXT_MASK) | > > - ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK); > > - pci_set_long(dev->config + pos, header); > > -} > > - > > -/* > > - * caller must supply valid (offset, size) * such that the range shouldn't > > - * overlap with other capability or other registers. > > - * This function doesn't check it. > > - */ > > -void pcie_add_capability(PCIDevice *dev, > > - uint16_t cap_id, uint8_t cap_ver, > > - uint16_t offset, uint16_t size) > > -{ > > - uint32_t header; > > - uint16_t next; > > - > > - assert(offset >= PCI_CONFIG_SPACE_SIZE); > > - assert(offset < offset + size); > > - assert(offset + size < PCIE_CONFIG_SPACE_SIZE); > > - assert(size >= 8); > > - assert(pci_is_express(dev)); > > - > > - if (offset == PCI_CONFIG_SPACE_SIZE) { > > - header = pci_get_long(dev->config + offset); > > - next = PCI_EXT_CAP_NEXT(header); > > - } else { > > - uint16_t prev; > > - > > - /* 0 is reserved cap id. use internally to find the last capability > > - in the linked list */ > > - next = pcie_find_capability_list(dev, 0, &prev); > > - > > - assert(prev >= PCI_CONFIG_SPACE_SIZE); > > - assert(next == 0); > > - pcie_ext_cap_set_next(dev, prev, offset); > > - } > > - pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next)); > > - > > - /* Make capability read-only by default */ > > - memset(dev->wmask + offset, 0, size); > > - memset(dev->w1cmask + offset, 0, size); > > - /* Check capability by default */ > > - memset(dev->cmask + offset, 0xFF, size); > > -} > > - > > -/************************************************************************** > > - * pci express extended capability helper functions > > - */ > > - > > -/* ARI */ > > -void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn) > > -{ > > - pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER, > > - offset, PCI_ARI_SIZEOF); > > - pci_set_long(dev->config + offset + PCI_ARI_CAP, PCI_ARI_CAP_NFN(nextfn)); > > -} > > diff --git a/hw/pcie.h b/hw/pcie.h > > deleted file mode 100644 > > index 4889194..0000000 > > --- a/hw/pcie.h > > +++ /dev/null > > @@ -1,142 +0,0 @@ > > -/* > > - * pcie.h > > - * > > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - * > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - * > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#ifndef QEMU_PCIE_H > > -#define QEMU_PCIE_H > > - > > -#include "hw.h" > > -#include "pci_regs.h" > > -#include "pcie_regs.h" > > -#include "pcie_aer.h" > > - > > -typedef enum { > > - /* for attention and power indicator */ > > - PCI_EXP_HP_IND_RESERVED = PCI_EXP_SLTCTL_IND_RESERVED, > > - PCI_EXP_HP_IND_ON = PCI_EXP_SLTCTL_IND_ON, > > - PCI_EXP_HP_IND_BLINK = PCI_EXP_SLTCTL_IND_BLINK, > > - PCI_EXP_HP_IND_OFF = PCI_EXP_SLTCTL_IND_OFF, > > -} PCIExpressIndicator; > > - > > -typedef enum { > > - /* these bits must match the bits in Slot Control/Status registers. > > - * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx > > - * > > - * Not all the bits of slot control register match with the ones of > > - * slot status. Not some bits of slot status register is used to > > - * show status, not to report event occurrence. > > - * So such bits must be masked out when checking the software > > - * notification condition. > > - */ > > - PCI_EXP_HP_EV_ABP = PCI_EXP_SLTCTL_ABPE, > > - /* attention button pressed */ > > - PCI_EXP_HP_EV_PDC = PCI_EXP_SLTCTL_PDCE, > > - /* presence detect changed */ > > - PCI_EXP_HP_EV_CCI = PCI_EXP_SLTCTL_CCIE, > > - /* command completed */ > > - > > - PCI_EXP_HP_EV_SUPPORTED = PCI_EXP_HP_EV_ABP | > > - PCI_EXP_HP_EV_PDC | > > - PCI_EXP_HP_EV_CCI, > > - /* supported event mask */ > > - > > - /* events not listed aren't supported */ > > -} PCIExpressHotPlugEvent; > > - > > -struct PCIExpressDevice { > > - /* Offset of express capability in config space */ > > - uint8_t exp_cap; > > - > > - /* SLOT */ > > - unsigned int hpev_intx; /* INTx for hot plug event (0-3:INT[A-D]#) > > - * default is 0 = INTA# > > - * If the chip wants to use other interrupt > > - * line, initialize this member with the > > - * desired number. > > - * If the chip dynamically changes this member, > > - * also initialize it when loaded as > > - * appropreately. > > - */ > > - bool hpev_notified; /* Logical AND of conditions for hot plug event. > > - Following 6.7.3.4: > > - Software Notification of Hot-Plug Events, an interrupt > > - is sent whenever the logical and of these conditions > > - transitions from false to true. */ > > - > > - /* AER */ > > - uint16_t aer_cap; > > - PCIEAERLog aer_log; > > - unsigned int aer_intx; /* INTx for error reporting > > - * default is 0 = INTA# > > - * If the chip wants to use other interrupt > > - * line, initialize this member with the > > - * desired number. > > - * If the chip dynamically changes this member, > > - * also initialize it when loaded as > > - * appropreately. > > - */ > > -}; > > - > > -/* PCI express capability helper functions */ > > -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port); > > -void pcie_cap_exit(PCIDevice *dev); > > -uint8_t pcie_cap_get_type(const PCIDevice *dev); > > -void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector); > > -uint8_t pcie_cap_flags_get_vector(PCIDevice *dev); > > - > > -void pcie_cap_deverr_init(PCIDevice *dev); > > -void pcie_cap_deverr_reset(PCIDevice *dev); > > - > > -void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot); > > -void pcie_cap_slot_reset(PCIDevice *dev); > > -void pcie_cap_slot_write_config(PCIDevice *dev, > > - uint32_t addr, uint32_t val, int len); > > -int pcie_cap_slot_post_load(void *opaque, int version_id); > > -void pcie_cap_slot_push_attention_button(PCIDevice *dev); > > - > > -void pcie_cap_root_init(PCIDevice *dev); > > -void pcie_cap_root_reset(PCIDevice *dev); > > - > > -void pcie_cap_flr_init(PCIDevice *dev); > > -void pcie_cap_flr_write_config(PCIDevice *dev, > > - uint32_t addr, uint32_t val, int len); > > - > > -void pcie_cap_ari_init(PCIDevice *dev); > > -void pcie_cap_ari_reset(PCIDevice *dev); > > -bool pcie_cap_is_ari_enabled(const PCIDevice *dev); > > - > > -/* PCI express extended capability helper functions */ > > -uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id); > > -void pcie_add_capability(PCIDevice *dev, > > - uint16_t cap_id, uint8_t cap_ver, > > - uint16_t offset, uint16_t size); > > - > > -void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn); > > - > > -extern const VMStateDescription vmstate_pcie_device; > > - > > -#define VMSTATE_PCIE_DEVICE(_field, _state) { \ > > - .name = (stringify(_field)), \ > > - .size = sizeof(PCIDevice), \ > > - .vmsd = &vmstate_pcie_device, \ > > - .flags = VMS_STRUCT, \ > > - .offset = vmstate_offset_value(_state, _field, PCIDevice), \ > > -} > > - > > -#endif /* QEMU_PCIE_H */ > > diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c > > deleted file mode 100644 > > index b04c164..0000000 > > --- a/hw/pcie_aer.c > > +++ /dev/null > > @@ -1,1032 +0,0 @@ > > -/* > > - * pcie_aer.c > > - * > > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - * > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - * > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#include "sysemu.h" > > -#include "qemu-objects.h" > > -#include "monitor.h" > > -#include "pci_bridge.h" > > -#include "pcie.h" > > -#include "msix.h" > > -#include "msi.h" > > -#include "pci_internals.h" > > -#include "pcie_regs.h" > > - > > -//#define DEBUG_PCIE > > -#ifdef DEBUG_PCIE > > -# define PCIE_DPRINTF(fmt, ...) \ > > - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) > > -#else > > -# define PCIE_DPRINTF(fmt, ...) do {} while (0) > > -#endif > > -#define PCIE_DEV_PRINTF(dev, fmt, ...) \ > > - PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) > > - > > -#define PCI_ERR_SRC_COR_OFFS 0 > > -#define PCI_ERR_SRC_UNCOR_OFFS 2 > > - > > -/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */ > > -static uint32_t pcie_aer_uncor_default_severity(uint32_t status) > > -{ > > - switch (status) { > > - case PCI_ERR_UNC_INTN: > > - case PCI_ERR_UNC_DLP: > > - case PCI_ERR_UNC_SDN: > > - case PCI_ERR_UNC_RX_OVER: > > - case PCI_ERR_UNC_FCP: > > - case PCI_ERR_UNC_MALF_TLP: > > - return PCI_ERR_ROOT_CMD_FATAL_EN; > > - case PCI_ERR_UNC_POISON_TLP: > > - case PCI_ERR_UNC_ECRC: > > - case PCI_ERR_UNC_UNSUP: > > - case PCI_ERR_UNC_COMP_TIME: > > - case PCI_ERR_UNC_COMP_ABORT: > > - case PCI_ERR_UNC_UNX_COMP: > > - case PCI_ERR_UNC_ACSV: > > - case PCI_ERR_UNC_MCBTLP: > > - case PCI_ERR_UNC_ATOP_EBLOCKED: > > - case PCI_ERR_UNC_TLP_PRF_BLOCKED: > > - return PCI_ERR_ROOT_CMD_NONFATAL_EN; > > - default: > > - abort(); > > - break; > > - } > > - return PCI_ERR_ROOT_CMD_FATAL_EN; > > -} > > - > > -static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err) > > -{ > > - if (aer_log->log_num == aer_log->log_max) { > > - return -1; > > - } > > - memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err); > > - aer_log->log_num++; > > - return 0; > > -} > > - > > -static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err) > > -{ > > - assert(aer_log->log_num); > > - *err = aer_log->log[0]; > > - aer_log->log_num--; > > - memmove(&aer_log->log[0], &aer_log->log[1], > > - aer_log->log_num * sizeof *err); > > -} > > - > > -static void aer_log_clear_all_err(PCIEAERLog *aer_log) > > -{ > > - aer_log->log_num = 0; > > -} > > - > > -int pcie_aer_init(PCIDevice *dev, uint16_t offset) > > -{ > > - PCIExpressDevice *exp; > > - > > - pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER, > > - offset, PCI_ERR_SIZEOF); > > - exp = &dev->exp; > > - exp->aer_cap = offset; > > - > > - /* log_max is property */ > > - if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) { > > - dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT; > > - } > > - /* clip down the value to avoid unreasobale memory usage */ > > - if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) { > > - return -EINVAL; > > - } > > - dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] * > > - dev->exp.aer_log.log_max); > > - > > - pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS, > > - PCI_ERR_UNC_SUPPORTED); > > - > > - pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER, > > - PCI_ERR_UNC_SEVERITY_DEFAULT); > > - pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER, > > - PCI_ERR_UNC_SUPPORTED); > > - > > - pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS, > > - PCI_ERR_COR_STATUS); > > - > > - pci_set_long(dev->config + offset + PCI_ERR_COR_MASK, > > - PCI_ERR_COR_MASK_DEFAULT); > > - pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK, > > - PCI_ERR_COR_SUPPORTED); > > - > > - /* capabilities and control. multiple header logging is supported */ > > - if (dev->exp.aer_log.log_max > 0) { > > - pci_set_long(dev->config + offset + PCI_ERR_CAP, > > - PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC | > > - PCI_ERR_CAP_MHRC); > > - pci_set_long(dev->wmask + offset + PCI_ERR_CAP, > > - PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE | > > - PCI_ERR_CAP_MHRE); > > - } else { > > - pci_set_long(dev->config + offset + PCI_ERR_CAP, > > - PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC); > > - pci_set_long(dev->wmask + offset + PCI_ERR_CAP, > > - PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); > > - } > > - > > - switch (pcie_cap_get_type(dev)) { > > - case PCI_EXP_TYPE_ROOT_PORT: > > - /* this case will be set by pcie_aer_root_init() */ > > - /* fallthrough */ > > - case PCI_EXP_TYPE_DOWNSTREAM: > > - case PCI_EXP_TYPE_UPSTREAM: > > - pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL, > > - PCI_BRIDGE_CTL_SERR); > > - pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS, > > - PCI_SEC_STATUS_RCV_SYSTEM_ERROR); > > - break; > > - default: > > - /* nothing */ > > - break; > > - } > > - return 0; > > -} > > - > > -void pcie_aer_exit(PCIDevice *dev) > > -{ > > - g_free(dev->exp.aer_log.log); > > -} > > - > > -static void pcie_aer_update_uncor_status(PCIDevice *dev) > > -{ > > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > - PCIEAERLog *aer_log = &dev->exp.aer_log; > > - > > - uint16_t i; > > - for (i = 0; i < aer_log->log_num; i++) { > > - pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS, > > - dev->exp.aer_log.log[i].status); > > - } > > -} > > - > > -/* > > - * return value: > > - * true: error message needs to be sent up > > - * false: error message is masked > > - * > > - * 6.2.6 Error Message Control > > - * Figure 6-3 > > - * all pci express devices part > > - */ > > -static bool > > -pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg) > > -{ > > - if (!(pcie_aer_msg_is_uncor(msg) && > > - (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) { > > - return false; > > - } > > - > > - /* Signaled System Error > > - * > > - * 7.5.1.1 Command register > > - * Bit 8 SERR# Enable > > - * > > - * When Set, this bit enables reporting of Non-fatal and Fatal > > - * errors detected by the Function to the Root Complex. Note that > > - * errors are reported if enabled either through this bit or through > > - * the PCI Express specific bits in the Device Control register (see > > - * Section 7.8.4). > > - */ > > - pci_word_test_and_set_mask(dev->config + PCI_STATUS, > > - PCI_STATUS_SIG_SYSTEM_ERROR); > > - > > - if (!(msg->severity & > > - pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) { > > - return false; > > - } > > - > > - /* send up error message */ > > - return true; > > -} > > - > > -/* > > - * return value: > > - * true: error message is sent up > > - * false: error message is masked > > - * > > - * 6.2.6 Error Message Control > > - * Figure 6-3 > > - * virtual pci bridge part > > - */ > > -static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg) > > -{ > > - uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL); > > - > > - if (pcie_aer_msg_is_uncor(msg)) { > > - /* Received System Error */ > > - pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS, > > - PCI_SEC_STATUS_RCV_SYSTEM_ERROR); > > - } > > - > > - if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) { > > - return false; > > - } > > - return true; > > -} > > - > > -void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector) > > -{ > > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > - assert(vector < PCI_ERR_ROOT_IRQ_MAX); > > - pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS, > > - PCI_ERR_ROOT_IRQ); > > - pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS, > > - vector << PCI_ERR_ROOT_IRQ_SHIFT); > > -} > > - > > -static unsigned int pcie_aer_root_get_vector(PCIDevice *dev) > > -{ > > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > - uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > > - return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT; > > -} > > - > > -/* Given a status register, get corresponding bits in the command register */ > > -static uint32_t pcie_aer_status_to_cmd(uint32_t status) > > -{ > > - uint32_t cmd = 0; > > - if (status & PCI_ERR_ROOT_COR_RCV) { > > - cmd |= PCI_ERR_ROOT_CMD_COR_EN; > > - } > > - if (status & PCI_ERR_ROOT_NONFATAL_RCV) { > > - cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN; > > - } > > - if (status & PCI_ERR_ROOT_FATAL_RCV) { > > - cmd |= PCI_ERR_ROOT_CMD_FATAL_EN; > > - } > > - return cmd; > > -} > > - > > -static void pcie_aer_root_notify(PCIDevice *dev) > > -{ > > - if (msix_enabled(dev)) { > > - msix_notify(dev, pcie_aer_root_get_vector(dev)); > > - } else if (msi_enabled(dev)) { > > - msi_notify(dev, pcie_aer_root_get_vector(dev)); > > - } else { > > - qemu_set_irq(dev->irq[dev->exp.aer_intx], 1); > > - } > > -} > > - > > -/* > > - * 6.2.6 Error Message Control > > - * Figure 6-3 > > - * root port part > > - */ > > -static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg) > > -{ > > - uint16_t cmd; > > - uint8_t *aer_cap; > > - uint32_t root_cmd; > > - uint32_t root_status, prev_status; > > - > > - cmd = pci_get_word(dev->config + PCI_COMMAND); > > - aer_cap = dev->config + dev->exp.aer_cap; > > - root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); > > - prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > > - > > - if (cmd & PCI_COMMAND_SERR) { > > - /* System Error. > > - * > > - * The way to report System Error is platform specific and > > - * it isn't implemented in qemu right now. > > - * So just discard the error for now. > > - * OS which cares of aer would receive errors via > > - * native aer mechanims, so this wouldn't matter. > > - */ > > - } > > - > > - /* Errro Message Received: Root Error Status register */ > > - switch (msg->severity) { > > - case PCI_ERR_ROOT_CMD_COR_EN: > > - if (root_status & PCI_ERR_ROOT_COR_RCV) { > > - root_status |= PCI_ERR_ROOT_MULTI_COR_RCV; > > - } else { > > - pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SRC_COR_OFFS, > > - msg->source_id); > > - } > > - root_status |= PCI_ERR_ROOT_COR_RCV; > > - break; > > - case PCI_ERR_ROOT_CMD_NONFATAL_EN: > > - root_status |= PCI_ERR_ROOT_NONFATAL_RCV; > > - break; > > - case PCI_ERR_ROOT_CMD_FATAL_EN: > > - if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) { > > - root_status |= PCI_ERR_ROOT_FIRST_FATAL; > > - } > > - root_status |= PCI_ERR_ROOT_FATAL_RCV; > > - break; > > - default: > > - abort(); > > - break; > > - } > > - if (pcie_aer_msg_is_uncor(msg)) { > > - if (root_status & PCI_ERR_ROOT_UNCOR_RCV) { > > - root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV; > > - } else { > > - pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + > > - PCI_ERR_SRC_UNCOR_OFFS, msg->source_id); > > - } > > - root_status |= PCI_ERR_ROOT_UNCOR_RCV; > > - } > > - pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status); > > - > > - /* 6.2.4.1.2 Interrupt Generation */ > > - /* All the above did was set some bits in the status register. > > - * Specifically these that match message severity. > > - * The below code relies on this fact. */ > > - if (!(root_cmd & msg->severity) || > > - (pcie_aer_status_to_cmd(prev_status) & root_cmd)) { > > - /* Condition is not being set or was already true so nothing to do. */ > > - return; > > - } > > - > > - pcie_aer_root_notify(dev); > > -} > > - > > -/* > > - * 6.2.6 Error Message Control Figure 6-3 > > - * > > - * Walk up the bus tree from the device, propagate the error message. > > - */ > > -static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) > > -{ > > - uint8_t type; > > - > > - while (dev) { > > - if (!pci_is_express(dev)) { > > - /* just ignore it */ > > - /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR? > > - * Consider e.g. a PCI bridge above a PCI Express device. */ > > - return; > > - } > > - > > - type = pcie_cap_get_type(dev); > > - if ((type == PCI_EXP_TYPE_ROOT_PORT || > > - type == PCI_EXP_TYPE_UPSTREAM || > > - type == PCI_EXP_TYPE_DOWNSTREAM) && > > - !pcie_aer_msg_vbridge(dev, msg)) { > > - return; > > - } > > - if (!pcie_aer_msg_alldev(dev, msg)) { > > - return; > > - } > > - if (type == PCI_EXP_TYPE_ROOT_PORT) { > > - pcie_aer_msg_root_port(dev, msg); > > - /* Root port can notify system itself, > > - or send the error message to root complex event collector. */ > > - /* > > - * if root port is associated with an event collector, > > - * return the root complex event collector here. > > - * For now root complex event collector isn't supported. > > - */ > > - return; > > - } > > - dev = pci_bridge_get_device(dev->bus); > > - } > > -} > > - > > -static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err) > > -{ > > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > - uint8_t first_bit = ffs(err->status) - 1; > > - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > > - int i; > > - > > - assert(err->status); > > - assert(!(err->status & (err->status - 1))); > > - > > - errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); > > - errcap |= PCI_ERR_CAP_FEP(first_bit); > > - > > - if (err->flags & PCIE_AER_ERR_HEADER_VALID) { > > - for (i = 0; i < ARRAY_SIZE(err->header); ++i) { > > - /* 7.10.8 Header Log Register */ > > - uint8_t *header_log = > > - aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0]; > > - cpu_to_be32wu((uint32_t*)header_log, err->header[i]); > > - } > > - } else { > > - assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT)); > > - memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); > > - } > > - > > - if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) && > > - (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & > > - PCI_EXP_DEVCAP2_EETLPP)) { > > - for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) { > > - /* 7.10.12 tlp prefix log register */ > > - uint8_t *prefix_log = > > - aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0]; > > - cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]); > > - } > > - errcap |= PCI_ERR_CAP_TLP; > > - } else { > > - memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, > > - PCI_ERR_TLP_PREFIX_LOG_SIZE); > > - } > > - pci_set_long(aer_cap + PCI_ERR_CAP, errcap); > > -} > > - > > -static void pcie_aer_clear_log(PCIDevice *dev) > > -{ > > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > - > > - pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP, > > - PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); > > - > > - memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); > > - memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE); > > -} > > - > > -static void pcie_aer_clear_error(PCIDevice *dev) > > -{ > > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > > - PCIEAERLog *aer_log = &dev->exp.aer_log; > > - PCIEAERErr err; > > - > > - if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) { > > - pcie_aer_clear_log(dev); > > - return; > > - } > > - > > - /* > > - * If more errors are queued, set corresponding bits in uncorrectable > > - * error status. > > - * We emulate uncorrectable error status register as W1CS. > > - * So set bit in uncorrectable error status here again for multiple > > - * error recording support. > > - * > > - * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability) > > - */ > > - pcie_aer_update_uncor_status(dev); > > - > > - aer_log_del_err(aer_log, &err); > > - pcie_aer_update_log(dev, &err); > > -} > > - > > -static int pcie_aer_record_error(PCIDevice *dev, > > - const PCIEAERErr *err) > > -{ > > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > > - int fep = PCI_ERR_CAP_FEP(errcap); > > - > > - assert(err->status); > > - assert(!(err->status & (err->status - 1))); > > - > > - if (errcap & PCI_ERR_CAP_MHRE && > > - (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) { > > - /* Not first error. queue error */ > > - if (aer_log_add_err(&dev->exp.aer_log, err) < 0) { > > - /* overflow */ > > - return -1; > > - } > > - return 0; > > - } > > - > > - pcie_aer_update_log(dev, err); > > - return 0; > > -} > > - > > -typedef struct PCIEAERInject { > > - PCIDevice *dev; > > - uint8_t *aer_cap; > > - const PCIEAERErr *err; > > - uint16_t devctl; > > - uint16_t devsta; > > - uint32_t error_status; > > - bool unsupported_request; > > - bool log_overflow; > > - PCIEAERMsg msg; > > -} PCIEAERInject; > > - > > -static bool pcie_aer_inject_cor_error(PCIEAERInject *inj, > > - uint32_t uncor_status, > > - bool is_advisory_nonfatal) > > -{ > > - PCIDevice *dev = inj->dev; > > - > > - inj->devsta |= PCI_EXP_DEVSTA_CED; > > - if (inj->unsupported_request) { > > - inj->devsta |= PCI_EXP_DEVSTA_URD; > > - } > > - pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); > > - > > - if (inj->aer_cap) { > > - uint32_t mask; > > - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS, > > - inj->error_status); > > - mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK); > > - if (mask & inj->error_status) { > > - return false; > > - } > > - if (is_advisory_nonfatal) { > > - uint32_t uncor_mask = > > - pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); > > - if (!(uncor_mask & uncor_status)) { > > - inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); > > - } > > - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > > - uncor_status); > > - } > > - } > > - > > - if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) { > > - return false; > > - } > > - if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) { > > - return false; > > - } > > - > > - inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN; > > - return true; > > -} > > - > > -static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal) > > -{ > > - PCIDevice *dev = inj->dev; > > - uint16_t cmd; > > - > > - if (is_fatal) { > > - inj->devsta |= PCI_EXP_DEVSTA_FED; > > - } else { > > - inj->devsta |= PCI_EXP_DEVSTA_NFED; > > - } > > - if (inj->unsupported_request) { > > - inj->devsta |= PCI_EXP_DEVSTA_URD; > > - } > > - pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); > > - > > - if (inj->aer_cap) { > > - uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); > > - if (mask & inj->error_status) { > > - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > > - inj->error_status); > > - return false; > > - } > > - > > - inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); > > - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, > > - inj->error_status); > > - } > > - > > - cmd = pci_get_word(dev->config + PCI_COMMAND); > > - if (inj->unsupported_request && > > - !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) { > > - return false; > > - } > > - if (is_fatal) { > > - if (!((cmd & PCI_COMMAND_SERR) || > > - (inj->devctl & PCI_EXP_DEVCTL_FERE))) { > > - return false; > > - } > > - inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN; > > - } else { > > - if (!((cmd & PCI_COMMAND_SERR) || > > - (inj->devctl & PCI_EXP_DEVCTL_NFERE))) { > > - return false; > > - } > > - inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN; > > - } > > - return true; > > -} > > - > > -/* > > - * non-Function specific error must be recorded in all functions. > > - * It is the responsibility of the caller of this function. > > - * It is also caller's responsibility to determine which function should > > - * report the rerror. > > - * > > - * 6.2.4 Error Logging > > - * 6.2.5 Sqeunce of Device Error Signaling and Logging Operations > > - * table 6-2: Flowchard Showing Sequence of Device Error Signaling and Logging > > - * Operations > > - */ > > -int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err) > > -{ > > - uint8_t *aer_cap = NULL; > > - uint16_t devctl = 0; > > - uint16_t devsta = 0; > > - uint32_t error_status = err->status; > > - PCIEAERInject inj; > > - > > - if (!pci_is_express(dev)) { > > - return -ENOSYS; > > - } > > - > > - if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > > - error_status &= PCI_ERR_COR_SUPPORTED; > > - } else { > > - error_status &= PCI_ERR_UNC_SUPPORTED; > > - } > > - > > - /* invalid status bit. one and only one bit must be set */ > > - if (!error_status || (error_status & (error_status - 1))) { > > - return -EINVAL; > > - } > > - > > - if (dev->exp.aer_cap) { > > - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; > > - aer_cap = dev->config + dev->exp.aer_cap; > > - devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL); > > - devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA); > > - } > > - > > - inj.dev = dev; > > - inj.aer_cap = aer_cap; > > - inj.err = err; > > - inj.devctl = devctl; > > - inj.devsta = devsta; > > - inj.error_status = error_status; > > - inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) && > > - err->status == PCI_ERR_UNC_UNSUP; > > - inj.log_overflow = false; > > - > > - if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > > - if (!pcie_aer_inject_cor_error(&inj, 0, false)) { > > - return 0; > > - } > > - } else { > > - bool is_fatal = > > - pcie_aer_uncor_default_severity(error_status) == > > - PCI_ERR_ROOT_CMD_FATAL_EN; > > - if (aer_cap) { > > - is_fatal = > > - error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER); > > - } > > - if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) { > > - inj.error_status = PCI_ERR_COR_ADV_NONFATAL; > > - if (!pcie_aer_inject_cor_error(&inj, error_status, true)) { > > - return 0; > > - } > > - } else { > > - if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) { > > - return 0; > > - } > > - } > > - } > > - > > - /* send up error message */ > > - inj.msg.source_id = err->source_id; > > - pcie_aer_msg(dev, &inj.msg); > > - > > - if (inj.log_overflow) { > > - PCIEAERErr header_log_overflow = { > > - .status = PCI_ERR_COR_HL_OVERFLOW, > > - .flags = PCIE_AER_ERR_IS_CORRECTABLE, > > - }; > > - int ret = pcie_aer_inject_error(dev, &header_log_overflow); > > - assert(!ret); > > - } > > - return 0; > > -} > > - > > -void pcie_aer_write_config(PCIDevice *dev, > > - uint32_t addr, uint32_t val, int len) > > -{ > > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); > > - uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap); > > - uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS); > > - > > - /* uncorrectable error */ > > - if (!(uncorsta & first_error)) { > > - /* the bit that corresponds to the first error is cleared */ > > - pcie_aer_clear_error(dev); > > - } else if (errcap & PCI_ERR_CAP_MHRE) { > > - /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared > > - * nothing should happen. So we have to revert the modification to > > - * the register. > > - */ > > - pcie_aer_update_uncor_status(dev); > > - } else { > > - /* capability & control > > - * PCI_ERR_CAP_MHRE might be cleared, so clear of header log. > > - */ > > - aer_log_clear_all_err(&dev->exp.aer_log); > > - } > > -} > > - > > -void pcie_aer_root_init(PCIDevice *dev) > > -{ > > - uint16_t pos = dev->exp.aer_cap; > > - > > - pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND, > > - PCI_ERR_ROOT_CMD_EN_MASK); > > - pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS, > > - PCI_ERR_ROOT_STATUS_REPORT_MASK); > > - /* PCI_ERR_ROOT_IRQ is RO but devices change it using a > > - * device-specific method. > > - */ > > - pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS, > > - ~PCI_ERR_ROOT_IRQ); > > -} > > - > > -void pcie_aer_root_reset(PCIDevice *dev) > > -{ > > - uint8_t* aer_cap = dev->config + dev->exp.aer_cap; > > - > > - pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0); > > - > > - /* > > - * Advanced Error Interrupt Message Number in Root Error Status Register > > - * must be updated by chip dependent code because it's chip dependent > > - * which number is used. > > - */ > > -} > > - > > -void pcie_aer_root_write_config(PCIDevice *dev, > > - uint32_t addr, uint32_t val, int len, > > - uint32_t root_cmd_prev) > > -{ > > - uint8_t *aer_cap = dev->config + dev->exp.aer_cap; > > - uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); > > - uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status); > > - uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); > > - /* 6.2.4.1.2 Interrupt Generation */ > > - if (!msix_enabled(dev) && !msi_enabled(dev)) { > > - qemu_set_irq(dev->irq[dev->exp.aer_intx], !!(root_cmd & enabled_cmd)); > > - return; > > - } > > - > > - if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) { > > - /* Send MSI on transition from false to true. */ > > - return; > > - } > > - > > - pcie_aer_root_notify(dev); > > -} > > - > > -static const VMStateDescription vmstate_pcie_aer_err = { > > - .name = "PCIE_AER_ERROR", > > - .version_id = 1, > > - .minimum_version_id = 1, > > - .minimum_version_id_old = 1, > > - .fields = (VMStateField[]) { > > - VMSTATE_UINT32(status, PCIEAERErr), > > - VMSTATE_UINT16(source_id, PCIEAERErr), > > - VMSTATE_UINT16(flags, PCIEAERErr), > > - VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4), > > - VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4), > > - VMSTATE_END_OF_LIST() > > - } > > -}; > > - > > -const VMStateDescription vmstate_pcie_aer_log = { > > - .name = "PCIE_AER_ERROR_LOG", > > - .version_id = 1, > > - .minimum_version_id = 1, > > - .minimum_version_id_old = 1, > > - .fields = (VMStateField[]) { > > - VMSTATE_UINT16(log_num, PCIEAERLog), > > - VMSTATE_UINT16(log_max, PCIEAERLog), > > - VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num, > > - vmstate_pcie_aer_err, PCIEAERErr), > > - VMSTATE_END_OF_LIST() > > - } > > -}; > > - > > -void pcie_aer_inject_error_print(Monitor *mon, const QObject *data) > > -{ > > - QDict *qdict; > > - int devfn; > > - assert(qobject_type(data) == QTYPE_QDICT); > > - qdict = qobject_to_qdict(data); > > - > > - devfn = (int)qdict_get_int(qdict, "devfn"); > > - monitor_printf(mon, "OK id: %s domain: %x, bus: %x devfn: %x.%x\n", > > - qdict_get_str(qdict, "id"), > > - (int) qdict_get_int(qdict, "domain"), > > - (int) qdict_get_int(qdict, "bus"), > > - PCI_SLOT(devfn), PCI_FUNC(devfn)); > > -} > > - > > -typedef struct PCIEAERErrorName { > > - const char *name; > > - uint32_t val; > > - bool correctable; > > -} PCIEAERErrorName; > > - > > -/* > > - * AER error name -> value conversion table > > - * This naming scheme is same to linux aer-injection tool. > > - */ > > -static const struct PCIEAERErrorName pcie_aer_error_list[] = { > > - { > > - .name = "TRAIN", > > - .val = PCI_ERR_UNC_TRAIN, > > - .correctable = false, > > - }, { > > - .name = "DLP", > > - .val = PCI_ERR_UNC_DLP, > > - .correctable = false, > > - }, { > > - .name = "SDN", > > - .val = PCI_ERR_UNC_SDN, > > - .correctable = false, > > - }, { > > - .name = "POISON_TLP", > > - .val = PCI_ERR_UNC_POISON_TLP, > > - .correctable = false, > > - }, { > > - .name = "FCP", > > - .val = PCI_ERR_UNC_FCP, > > - .correctable = false, > > - }, { > > - .name = "COMP_TIME", > > - .val = PCI_ERR_UNC_COMP_TIME, > > - .correctable = false, > > - }, { > > - .name = "COMP_ABORT", > > - .val = PCI_ERR_UNC_COMP_ABORT, > > - .correctable = false, > > - }, { > > - .name = "UNX_COMP", > > - .val = PCI_ERR_UNC_UNX_COMP, > > - .correctable = false, > > - }, { > > - .name = "RX_OVER", > > - .val = PCI_ERR_UNC_RX_OVER, > > - .correctable = false, > > - }, { > > - .name = "MALF_TLP", > > - .val = PCI_ERR_UNC_MALF_TLP, > > - .correctable = false, > > - }, { > > - .name = "ECRC", > > - .val = PCI_ERR_UNC_ECRC, > > - .correctable = false, > > - }, { > > - .name = "UNSUP", > > - .val = PCI_ERR_UNC_UNSUP, > > - .correctable = false, > > - }, { > > - .name = "ACSV", > > - .val = PCI_ERR_UNC_ACSV, > > - .correctable = false, > > - }, { > > - .name = "INTN", > > - .val = PCI_ERR_UNC_INTN, > > - .correctable = false, > > - }, { > > - .name = "MCBTLP", > > - .val = PCI_ERR_UNC_MCBTLP, > > - .correctable = false, > > - }, { > > - .name = "ATOP_EBLOCKED", > > - .val = PCI_ERR_UNC_ATOP_EBLOCKED, > > - .correctable = false, > > - }, { > > - .name = "TLP_PRF_BLOCKED", > > - .val = PCI_ERR_UNC_TLP_PRF_BLOCKED, > > - .correctable = false, > > - }, { > > - .name = "RCVR", > > - .val = PCI_ERR_COR_RCVR, > > - .correctable = true, > > - }, { > > - .name = "BAD_TLP", > > - .val = PCI_ERR_COR_BAD_TLP, > > - .correctable = true, > > - }, { > > - .name = "BAD_DLLP", > > - .val = PCI_ERR_COR_BAD_DLLP, > > - .correctable = true, > > - }, { > > - .name = "REP_ROLL", > > - .val = PCI_ERR_COR_REP_ROLL, > > - .correctable = true, > > - }, { > > - .name = "REP_TIMER", > > - .val = PCI_ERR_COR_REP_TIMER, > > - .correctable = true, > > - }, { > > - .name = "ADV_NONFATAL", > > - .val = PCI_ERR_COR_ADV_NONFATAL, > > - .correctable = true, > > - }, { > > - .name = "INTERNAL", > > - .val = PCI_ERR_COR_INTERNAL, > > - .correctable = true, > > - }, { > > - .name = "HL_OVERFLOW", > > - .val = PCI_ERR_COR_HL_OVERFLOW, > > - .correctable = true, > > - }, > > -}; > > - > > -static int pcie_aer_parse_error_string(const char *error_name, > > - uint32_t *status, bool *correctable) > > -{ > > - int i; > > - > > - for (i = 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) { > > - const PCIEAERErrorName *e = &pcie_aer_error_list[i]; > > - if (strcmp(error_name, e->name)) { > > - continue; > > - } > > - > > - *status = e->val; > > - *correctable = e->correctable; > > - return 0; > > - } > > - return -EINVAL; > > -} > > - > > -int do_pcie_aer_inject_error(Monitor *mon, > > - const QDict *qdict, QObject **ret_data) > > -{ > > - const char *id = qdict_get_str(qdict, "id"); > > - const char *error_name; > > - uint32_t error_status; > > - bool correctable; > > - PCIDevice *dev; > > - PCIEAERErr err; > > - int ret; > > - > > - ret = pci_qdev_find_device(id, &dev); > > - if (ret < 0) { > > - monitor_printf(mon, > > - "id or pci device path is invalid or device not " > > - "found. %s\n", id); > > - return ret; > > - } > > - if (!pci_is_express(dev)) { > > - monitor_printf(mon, "the device doesn't support pci express. %s\n", > > - id); > > - return -ENOSYS; > > - } > > - > > - error_name = qdict_get_str(qdict, "error_status"); > > - if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) { > > - char *e = NULL; > > - error_status = strtoul(error_name, &e, 0); > > - correctable = qdict_get_try_bool(qdict, "correctable", 0); > > - if (!e || *e != '\0') { > > - monitor_printf(mon, "invalid error status value. \"%s\"", > > - error_name); > > - return -EINVAL; > > - } > > - } > > - err.status = error_status; > > - err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn; > > - > > - err.flags = 0; > > - if (correctable) { > > - err.flags |= PCIE_AER_ERR_IS_CORRECTABLE; > > - } > > - if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) { > > - err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY; > > - } > > - if (qdict_haskey(qdict, "header0")) { > > - err.flags |= PCIE_AER_ERR_HEADER_VALID; > > - } > > - if (qdict_haskey(qdict, "prefix0")) { > > - err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT; > > - } > > - > > - err.header[0] = qdict_get_try_int(qdict, "header0", 0); > > - err.header[1] = qdict_get_try_int(qdict, "header1", 0); > > - err.header[2] = qdict_get_try_int(qdict, "header2", 0); > > - err.header[3] = qdict_get_try_int(qdict, "header3", 0); > > - > > - err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0); > > - err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0); > > - err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0); > > - err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0); > > - > > - ret = pcie_aer_inject_error(dev, &err); > > - *ret_data = qobject_from_jsonf("{'id': %s, " > > - "'domain': %d, 'bus': %d, 'devfn': %d, " > > - "'ret': %d}", > > - id, > > - pci_find_domain(dev->bus), > > - pci_bus_num(dev->bus), dev->devfn, > > - ret); > > - assert(*ret_data); > > - > > - return 0; > > -} > > diff --git a/hw/pcie_aer.h b/hw/pcie_aer.h > > deleted file mode 100644 > > index 7539500..0000000 > > --- a/hw/pcie_aer.h > > +++ /dev/null > > @@ -1,106 +0,0 @@ > > -/* > > - * pcie_aer.h > > - * > > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - * > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - * > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#ifndef QEMU_PCIE_AER_H > > -#define QEMU_PCIE_AER_H > > - > > -#include "hw.h" > > - > > -/* definitions which PCIExpressDevice uses */ > > - > > -/* AER log */ > > -struct PCIEAERLog { > > - /* This structure is saved/loaded. > > - So explicitly size them instead of unsigned int */ > > - > > - /* the number of currently recorded log in log member */ > > - uint16_t log_num; > > - > > - /* > > - * The maximum number of the log. Errors can be logged up to this. > > - * > > - * This is configurable property. > > - * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT > > - * to avoid unreasonable memory usage. > > - * I bet that 128 log size would be big enough, otherwise too many errors > > - * for system to function normaly. But could consecutive errors occur? > > - */ > > -#define PCIE_AER_LOG_MAX_DEFAULT 8 > > -#define PCIE_AER_LOG_MAX_LIMIT 128 > > -#define PCIE_AER_LOG_MAX_UNSET 0xffff > > - uint16_t log_max; > > - > > - /* Error log. log_max-sized array */ > > - PCIEAERErr *log; > > -}; > > - > > -/* aer error message: error signaling message has only error sevirity and > > - source id. See 2.2.8.3 error signaling messages */ > > -struct PCIEAERMsg { > > - /* > > - * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN > > - * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE} > > - */ > > - uint32_t severity; > > - > > - uint16_t source_id; /* bdf */ > > -}; > > - > > -static inline bool > > -pcie_aer_msg_is_uncor(const PCIEAERMsg *msg) > > -{ > > - return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN || > > - msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN; > > -} > > - > > -/* error */ > > -struct PCIEAERErr { > > - uint32_t status; /* error status bits */ > > - uint16_t source_id; /* bdf */ > > - > > -#define PCIE_AER_ERR_IS_CORRECTABLE 0x1 /* correctable/uncorrectable */ > > -#define PCIE_AER_ERR_MAYBE_ADVISORY 0x2 /* maybe advisory non-fatal */ > > -#define PCIE_AER_ERR_HEADER_VALID 0x4 /* TLP header is logged */ > > -#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8 /* TLP Prefix is logged */ > > - uint16_t flags; > > - > > - uint32_t header[4]; /* TLP header */ > > - uint32_t prefix[4]; /* TLP header prefix */ > > -}; > > - > > -extern const VMStateDescription vmstate_pcie_aer_log; > > - > > -int pcie_aer_init(PCIDevice *dev, uint16_t offset); > > -void pcie_aer_exit(PCIDevice *dev); > > -void pcie_aer_write_config(PCIDevice *dev, > > - uint32_t addr, uint32_t val, int len); > > - > > -/* aer root port */ > > -void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector); > > -void pcie_aer_root_init(PCIDevice *dev); > > -void pcie_aer_root_reset(PCIDevice *dev); > > -void pcie_aer_root_write_config(PCIDevice *dev, > > - uint32_t addr, uint32_t val, int len, > > - uint32_t root_cmd_prev); > > - > > -/* error injection */ > > -int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err); > > - > > -#endif /* QEMU_PCIE_AER_H */ > > diff --git a/hw/pcie_host.c b/hw/pcie_host.c > > deleted file mode 100644 > > index c257fb4..0000000 > > --- a/hw/pcie_host.c > > +++ /dev/null > > @@ -1,161 +0,0 @@ > > -/* > > - * pcie_host.c > > - * utility functions for pci express host bridge. > > - * > > - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#include "hw.h" > > -#include "pci.h" > > -#include "pcie_host.h" > > -#include "exec-memory.h" > > - > > -/* > > - * PCI express mmcfig address > > - * bit 20 - 28: bus number > > - * bit 15 - 19: device number > > - * bit 12 - 14: function number > > - * bit 0 - 11: offset in configuration space of a given device > > - */ > > -#define PCIE_MMCFG_SIZE_MAX (1ULL << 28) > > -#define PCIE_MMCFG_SIZE_MIN (1ULL << 20) > > -#define PCIE_MMCFG_BUS_BIT 20 > > -#define PCIE_MMCFG_BUS_MASK 0x1ff > > -#define PCIE_MMCFG_DEVFN_BIT 12 > > -#define PCIE_MMCFG_DEVFN_MASK 0xff > > -#define PCIE_MMCFG_CONFOFFSET_MASK 0xfff > > -#define PCIE_MMCFG_BUS(addr) (((addr) >> PCIE_MMCFG_BUS_BIT) & \ > > - PCIE_MMCFG_BUS_MASK) > > -#define PCIE_MMCFG_DEVFN(addr) (((addr) >> PCIE_MMCFG_DEVFN_BIT) & \ > > - PCIE_MMCFG_DEVFN_MASK) > > -#define PCIE_MMCFG_CONFOFFSET(addr) ((addr) & PCIE_MMCFG_CONFOFFSET_MASK) > > - > > - > > -/* a helper function to get a PCIDevice for a given mmconfig address */ > > -static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, > > - uint32_t mmcfg_addr) > > -{ > > - return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), > > - PCIE_MMCFG_DEVFN(mmcfg_addr)); > > -} > > - > > -static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr, > > - uint64_t val, unsigned len) > > -{ > > - PCIExpressHost *e = opaque; > > - PCIBus *s = e->pci.bus; > > - PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); > > - uint32_t addr; > > - uint32_t limit; > > - > > - if (!pci_dev) { > > - return; > > - } > > - addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > > - limit = pci_config_size(pci_dev); > > - if (limit <= addr) { > > - /* conventional pci device can be behind pcie-to-pci bridge. > > - 256 <= addr < 4K has no effects. */ > > - return; > > - } > > - pci_host_config_write_common(pci_dev, addr, limit, val, len); > > -} > > - > > -static uint64_t pcie_mmcfg_data_read(void *opaque, > > - hwaddr mmcfg_addr, > > - unsigned len) > > -{ > > - PCIExpressHost *e = opaque; > > - PCIBus *s = e->pci.bus; > > - PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); > > - uint32_t addr; > > - uint32_t limit; > > - > > - if (!pci_dev) { > > - return ~0x0; > > - } > > - addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > > - limit = pci_config_size(pci_dev); > > - if (limit <= addr) { > > - /* conventional pci device can be behind pcie-to-pci bridge. > > - 256 <= addr < 4K has no effects. */ > > - return ~0x0; > > - } > > - return pci_host_config_read_common(pci_dev, addr, limit, len); > > -} > > - > > -static const MemoryRegionOps pcie_mmcfg_ops = { > > - .read = pcie_mmcfg_data_read, > > - .write = pcie_mmcfg_data_write, > > - .endianness = DEVICE_NATIVE_ENDIAN, > > -}; > > - > > -/* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */ > > -#define PCIE_BASE_ADDR_UNMAPPED ((hwaddr)-1ULL) > > - > > -int pcie_host_init(PCIExpressHost *e) > > -{ > > - e->base_addr = PCIE_BASE_ADDR_UNMAPPED; > > - > > - return 0; > > -} > > - > > -void pcie_host_mmcfg_unmap(PCIExpressHost *e) > > -{ > > - if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { > > - memory_region_del_subregion(get_system_memory(), &e->mmio); > > - memory_region_destroy(&e->mmio); > > - e->base_addr = PCIE_BASE_ADDR_UNMAPPED; > > - } > > -} > > - > > -void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, > > - uint32_t size) > > -{ > > - assert(!(size & (size - 1))); /* power of 2 */ > > - assert(size >= PCIE_MMCFG_SIZE_MIN); > > - assert(size <= PCIE_MMCFG_SIZE_MAX); > > - e->size = size; > > - memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size); > > - e->base_addr = addr; > > - memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio); > > -} > > - > > -void pcie_host_mmcfg_update(PCIExpressHost *e, > > - int enable, > > - hwaddr addr, > > - uint32_t size) > > -{ > > - pcie_host_mmcfg_unmap(e); > > - if (enable) { > > - pcie_host_mmcfg_map(e, addr, size); > > - } > > -} > > - > > -static const TypeInfo pcie_host_type_info = { > > - .name = TYPE_PCIE_HOST_BRIDGE, > > - .parent = TYPE_PCI_HOST_BRIDGE, > > - .abstract = true, > > - .instance_size = sizeof(PCIExpressHost), > > -}; > > - > > -static void pcie_host_register_types(void) > > -{ > > - type_register_static(&pcie_host_type_info); > > -} > > - > > -type_init(pcie_host_register_types) > > diff --git a/hw/pcie_host.h b/hw/pcie_host.h > > deleted file mode 100644 > > index 3921935..0000000 > > --- a/hw/pcie_host.h > > +++ /dev/null > > @@ -1,54 +0,0 @@ > > -/* > > - * pcie_host.h > > - * > > - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#ifndef PCIE_HOST_H > > -#define PCIE_HOST_H > > - > > -#include "pci_host.h" > > -#include "memory.h" > > - > > -#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge" > > -#define PCIE_HOST_BRIDGE(obj) \ > > - OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE) > > - > > -struct PCIExpressHost { > > - PCIHostState pci; > > - > > - /* express part */ > > - > > - /* base address where MMCONFIG area is mapped. */ > > - hwaddr base_addr; > > - > > - /* the size of MMCONFIG area. It's host bridge dependent */ > > - hwaddr size; > > - > > - /* MMCONFIG mmio area */ > > - MemoryRegion mmio; > > -}; > > - > > -int pcie_host_init(PCIExpressHost *e); > > -void pcie_host_mmcfg_unmap(PCIExpressHost *e); > > -void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size); > > -void pcie_host_mmcfg_update(PCIExpressHost *e, > > - int enable, > > - hwaddr addr, > > - uint32_t size); > > - > > -#endif /* PCIE_HOST_H */ > > diff --git a/hw/pcie_port.c b/hw/pcie_port.c > > deleted file mode 100644 > > index d6350e5..0000000 > > --- a/hw/pcie_port.c > > +++ /dev/null > > @@ -1,114 +0,0 @@ > > -/* > > - * pcie_port.c > > - * > > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - * > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - * > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#include "pcie_port.h" > > - > > -void pcie_port_init_reg(PCIDevice *d) > > -{ > > - /* Unlike pci bridge, > > - 66MHz and fast back to back don't apply to pci express port. */ > > - pci_set_word(d->config + PCI_STATUS, 0); > > - pci_set_word(d->config + PCI_SEC_STATUS, 0); > > - > > - /* Unlike conventional pci bridge, some bits are hardwired to 0. */ > > - pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, > > - PCI_BRIDGE_CTL_PARITY | > > - PCI_BRIDGE_CTL_ISA | > > - PCI_BRIDGE_CTL_VGA | > > - PCI_BRIDGE_CTL_SERR | > > - PCI_BRIDGE_CTL_BUS_RESET); > > -} > > - > > -/************************************************************************** > > - * (chassis number, pcie physical slot number) -> pcie slot conversion > > - */ > > -struct PCIEChassis { > > - uint8_t number; > > - > > - QLIST_HEAD(, PCIESlot) slots; > > - QLIST_ENTRY(PCIEChassis) next; > > -}; > > - > > -static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis); > > - > > -static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number) > > -{ > > - struct PCIEChassis *c; > > - QLIST_FOREACH(c, &chassis, next) { > > - if (c->number == chassis_number) { > > - break; > > - } > > - } > > - return c; > > -} > > - > > -void pcie_chassis_create(uint8_t chassis_number) > > -{ > > - struct PCIEChassis *c; > > - c = pcie_chassis_find(chassis_number); > > - if (c) { > > - return; > > - } > > - c = g_malloc0(sizeof(*c)); > > - c->number = chassis_number; > > - QLIST_INIT(&c->slots); > > - QLIST_INSERT_HEAD(&chassis, c, next); > > -} > > - > > -static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c, > > - uint8_t slot) > > -{ > > - PCIESlot *s; > > - QLIST_FOREACH(s, &c->slots, next) { > > - if (s->slot == slot) { > > - break; > > - } > > - } > > - return s; > > -} > > - > > -PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot) > > -{ > > - struct PCIEChassis *c; > > - c = pcie_chassis_find(chassis_number); > > - if (!c) { > > - return NULL; > > - } > > - return pcie_chassis_find_slot_with_chassis(c, slot); > > -} > > - > > -int pcie_chassis_add_slot(struct PCIESlot *slot) > > -{ > > - struct PCIEChassis *c; > > - c = pcie_chassis_find(slot->chassis); > > - if (!c) { > > - return -ENODEV; > > - } > > - if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) { > > - return -EBUSY; > > - } > > - QLIST_INSERT_HEAD(&c->slots, slot, next); > > - return 0; > > -} > > - > > -void pcie_chassis_del_slot(PCIESlot *s) > > -{ > > - QLIST_REMOVE(s, next); > > -} > > diff --git a/hw/pcie_port.h b/hw/pcie_port.h > > deleted file mode 100644 > > index 3709583..0000000 > > --- a/hw/pcie_port.h > > +++ /dev/null > > @@ -1,51 +0,0 @@ > > -/* > > - * pcie_port.h > > - * > > - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or modify > > - * it under the terms of the GNU General Public License as published by > > - * the Free Software Foundation; either version 2 of the License, or > > - * (at your option) any later version. > > - * > > - * This program is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > - * GNU General Public License for more details. > > - * > > - * You should have received a copy of the GNU General Public License along > > - * with this program; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -#ifndef QEMU_PCIE_PORT_H > > -#define QEMU_PCIE_PORT_H > > - > > -#include "pci_bridge.h" > > -#include "pci_internals.h" > > - > > -struct PCIEPort { > > - PCIBridge br; > > - > > - /* pci express switch port */ > > - uint8_t port; > > -}; > > - > > -void pcie_port_init_reg(PCIDevice *d); > > - > > -struct PCIESlot { > > - PCIEPort port; > > - > > - /* pci express switch port with slot */ > > - uint8_t chassis; > > - uint16_t slot; > > - QLIST_ENTRY(PCIESlot) next; > > -}; > > - > > -void pcie_chassis_create(uint8_t chassis_number); > > -void pcie_main_chassis_create(void); > > -PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot); > > -int pcie_chassis_add_slot(struct PCIESlot *slot); > > -void pcie_chassis_del_slot(PCIESlot *s); > > - > > -#endif /* QEMU_PCIE_PORT_H */ > > diff --git a/hw/pcie_regs.h b/hw/pcie_regs.h > > deleted file mode 100644 > > index 4d123d9..0000000 > > --- a/hw/pcie_regs.h > > +++ /dev/null > > @@ -1,156 +0,0 @@ > > -/* > > - * constants for pcie configurations space from pci express spec. > > - * > > - * TODO: > > - * Those constants and macros should go to Linux pci_regs.h > > - * Once they're merged, they will go away. > > - */ > > -#ifndef QEMU_PCIE_REGS_H > > -#define QEMU_PCIE_REGS_H > > - > > - > > -/* express capability */ > > - > > -#define PCI_EXP_VER2_SIZEOF 0x3c /* express capability of ver. 2 */ > > -#define PCI_EXT_CAP_VER_SHIFT 16 > > -#define PCI_EXT_CAP_NEXT_SHIFT 20 > > -#define PCI_EXT_CAP_NEXT_MASK (0xffc << PCI_EXT_CAP_NEXT_SHIFT) > > - > > -#define PCI_EXT_CAP(id, ver, next) \ > > - ((id) | \ > > - ((ver) << PCI_EXT_CAP_VER_SHIFT) | \ > > - ((next) << PCI_EXT_CAP_NEXT_SHIFT)) > > - > > -#define PCI_EXT_CAP_ALIGN 4 > > -#define PCI_EXT_CAP_ALIGNUP(x) \ > > - (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1)) > > - > > -/* PCI_EXP_FLAGS */ > > -#define PCI_EXP_FLAGS_VER2 2 /* for now, supports only ver. 2 */ > > -#define PCI_EXP_FLAGS_IRQ_SHIFT (ffs(PCI_EXP_FLAGS_IRQ) - 1) > > -#define PCI_EXP_FLAGS_TYPE_SHIFT (ffs(PCI_EXP_FLAGS_TYPE) - 1) > > - > > - > > -/* PCI_EXP_LINK{CAP, STA} */ > > -/* link speed */ > > -#define PCI_EXP_LNK_LS_25 1 > > - > > -#define PCI_EXP_LNK_MLW_SHIFT (ffs(PCI_EXP_LNKCAP_MLW) - 1) > > -#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT) > > - > > -/* PCI_EXP_LINKCAP */ > > -#define PCI_EXP_LNKCAP_ASPMS_SHIFT (ffs(PCI_EXP_LNKCAP_ASPMS) - 1) > > -#define PCI_EXP_LNKCAP_ASPMS_0S (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT) > > - > > -#define PCI_EXP_LNKCAP_PN_SHIFT (ffs(PCI_EXP_LNKCAP_PN) - 1) > > - > > -#define PCI_EXP_SLTCAP_PSN_SHIFT (ffs(PCI_EXP_SLTCAP_PSN) - 1) > > - > > -#define PCI_EXP_SLTCTL_IND_RESERVED 0x0 > > -#define PCI_EXP_SLTCTL_IND_ON 0x1 > > -#define PCI_EXP_SLTCTL_IND_BLINK 0x2 > > -#define PCI_EXP_SLTCTL_IND_OFF 0x3 > > -#define PCI_EXP_SLTCTL_AIC_SHIFT (ffs(PCI_EXP_SLTCTL_AIC) - 1) > > -#define PCI_EXP_SLTCTL_AIC_OFF \ > > - (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT) > > - > > -#define PCI_EXP_SLTCTL_PIC_SHIFT (ffs(PCI_EXP_SLTCTL_PIC) - 1) > > -#define PCI_EXP_SLTCTL_PIC_OFF \ > > - (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT) > > - > > -#define PCI_EXP_SLTCTL_SUPPORTED \ > > - (PCI_EXP_SLTCTL_ABPE | \ > > - PCI_EXP_SLTCTL_PDCE | \ > > - PCI_EXP_SLTCTL_CCIE | \ > > - PCI_EXP_SLTCTL_HPIE | \ > > - PCI_EXP_SLTCTL_AIC | \ > > - PCI_EXP_SLTCTL_PCC | \ > > - PCI_EXP_SLTCTL_EIC) > > - > > -#define PCI_EXP_DEVCAP2_EFF 0x100000 > > -#define PCI_EXP_DEVCAP2_EETLPP 0x200000 > > - > > -#define PCI_EXP_DEVCTL2_EETLPPB 0x80 > > - > > -/* ARI */ > > -#define PCI_ARI_VER 1 > > -#define PCI_ARI_SIZEOF 8 > > - > > -/* AER */ > > -#define PCI_ERR_VER 2 > > -#define PCI_ERR_SIZEOF 0x48 > > - > > -#define PCI_ERR_UNC_SDN 0x00000020 /* surprise down */ > > -#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */ > > -#define PCI_ERR_UNC_INTN 0x00400000 /* Internal Error */ > > -#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC Blcoked TLP */ > > -#define PCI_ERR_UNC_ATOP_EBLOCKED 0x01000000 /* atomic op egress blocked */ > > -#define PCI_ERR_UNC_TLP_PRF_BLOCKED 0x02000000 /* TLP Prefix Blocked */ > > -#define PCI_ERR_COR_ADV_NONFATAL 0x00002000 /* Advisory Non-Fatal */ > > -#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected Internal */ > > -#define PCI_ERR_COR_HL_OVERFLOW 0x00008000 /* Header Long Overflow */ > > -#define PCI_ERR_CAP_FEP_MASK 0x0000001f > > -#define PCI_ERR_CAP_MHRC 0x00000200 > > -#define PCI_ERR_CAP_MHRE 0x00000400 > > -#define PCI_ERR_CAP_TLP 0x00000800 > > - > > -#define PCI_ERR_HEADER_LOG_SIZE 16 > > -#define PCI_ERR_TLP_PREFIX_LOG 0x38 > > -#define PCI_ERR_TLP_PREFIX_LOG_SIZE 16 > > - > > -#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR 0x4000 > > - > > -/* aer root error command/status */ > > -#define PCI_ERR_ROOT_CMD_EN_MASK (PCI_ERR_ROOT_CMD_COR_EN | \ > > - PCI_ERR_ROOT_CMD_NONFATAL_EN | \ > > - PCI_ERR_ROOT_CMD_FATAL_EN) > > - > > -#define PCI_ERR_ROOT_IRQ_MAX 32 > > -#define PCI_ERR_ROOT_IRQ 0xf8000000 > > -#define PCI_ERR_ROOT_IRQ_SHIFT (ffs(PCI_ERR_ROOT_IRQ) - 1) > > -#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV | \ > > - PCI_ERR_ROOT_MULTI_COR_RCV | \ > > - PCI_ERR_ROOT_UNCOR_RCV | \ > > - PCI_ERR_ROOT_MULTI_UNCOR_RCV | \ > > - PCI_ERR_ROOT_FIRST_FATAL | \ > > - PCI_ERR_ROOT_NONFATAL_RCV | \ > > - PCI_ERR_ROOT_FATAL_RCV) > > - > > -#define PCI_ERR_UNC_SUPPORTED (PCI_ERR_UNC_DLP | \ > > - PCI_ERR_UNC_SDN | \ > > - PCI_ERR_UNC_POISON_TLP | \ > > - PCI_ERR_UNC_FCP | \ > > - PCI_ERR_UNC_COMP_TIME | \ > > - PCI_ERR_UNC_COMP_ABORT | \ > > - PCI_ERR_UNC_UNX_COMP | \ > > - PCI_ERR_UNC_RX_OVER | \ > > - PCI_ERR_UNC_MALF_TLP | \ > > - PCI_ERR_UNC_ECRC | \ > > - PCI_ERR_UNC_UNSUP | \ > > - PCI_ERR_UNC_ACSV | \ > > - PCI_ERR_UNC_INTN | \ > > - PCI_ERR_UNC_MCBTLP | \ > > - PCI_ERR_UNC_ATOP_EBLOCKED | \ > > - PCI_ERR_UNC_TLP_PRF_BLOCKED) > > - > > -#define PCI_ERR_UNC_SEVERITY_DEFAULT (PCI_ERR_UNC_DLP | \ > > - PCI_ERR_UNC_SDN | \ > > - PCI_ERR_UNC_FCP | \ > > - PCI_ERR_UNC_RX_OVER | \ > > - PCI_ERR_UNC_MALF_TLP | \ > > - PCI_ERR_UNC_INTN) > > - > > -#define PCI_ERR_COR_SUPPORTED (PCI_ERR_COR_RCVR | \ > > - PCI_ERR_COR_BAD_TLP | \ > > - PCI_ERR_COR_BAD_DLLP | \ > > - PCI_ERR_COR_REP_ROLL | \ > > - PCI_ERR_COR_REP_TIMER | \ > > - PCI_ERR_COR_ADV_NONFATAL | \ > > - PCI_ERR_COR_INTERNAL | \ > > - PCI_ERR_COR_HL_OVERFLOW) > > - > > -#define PCI_ERR_COR_MASK_DEFAULT (PCI_ERR_COR_ADV_NONFATAL | \ > > - PCI_ERR_COR_INTERNAL | \ > > - PCI_ERR_COR_HL_OVERFLOW) > > - > > -#endif /* QEMU_PCIE_REGS_H */ > > diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs > > index 8fe2123..cb7cf8f 100644 > > --- a/hw/ppc/Makefile.objs > > +++ b/hw/ppc/Makefile.objs > > @@ -10,7 +10,7 @@ obj-y += ppc_newworld.o > > # IBM pSeries (sPAPR) > > obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o > > obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o > > -obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o > > +obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o > > obj-$(CONFIG_PSERIES) += spapr_events.o > > # PowerPC 4xx boards > > obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o > > diff --git a/hw/shpc.c b/hw/shpc.c > > deleted file mode 100644 > > index 4597bbd..0000000 > > --- a/hw/shpc.c > > +++ /dev/null > > @@ -1,681 +0,0 @@ > > -#include <strings.h> > > -#include <stdint.h> > > -#include "range.h" > > -#include "range.h" > > -#include "shpc.h" > > -#include "pci.h" > > -#include "pci_internals.h" > > -#include "msi.h" > > - > > -/* TODO: model power only and disabled slot states. */ > > -/* TODO: handle SERR and wakeups */ > > -/* TODO: consider enabling 66MHz support */ > > - > > -/* TODO: remove fully only on state DISABLED and LED off. > > - * track state to properly record this. */ > > - > > -/* SHPC Working Register Set */ > > -#define SHPC_BASE_OFFSET 0x00 /* 4 bytes */ > > -#define SHPC_SLOTS_33 0x04 /* 4 bytes. Also encodes PCI-X slots. */ > > -#define SHPC_SLOTS_66 0x08 /* 4 bytes. */ > > -#define SHPC_NSLOTS 0x0C /* 1 byte */ > > -#define SHPC_FIRST_DEV 0x0D /* 1 byte */ > > -#define SHPC_PHYS_SLOT 0x0E /* 2 byte */ > > -#define SHPC_PHYS_NUM_MAX 0x7ff > > -#define SHPC_PHYS_NUM_UP 0x2000 > > -#define SHPC_PHYS_MRL 0x4000 > > -#define SHPC_PHYS_BUTTON 0x8000 > > -#define SHPC_SEC_BUS 0x10 /* 2 bytes */ > > -#define SHPC_SEC_BUS_33 0x0 > > -#define SHPC_SEC_BUS_66 0x1 /* Unused */ > > -#define SHPC_SEC_BUS_MASK 0x7 > > -#define SHPC_MSI_CTL 0x12 /* 1 byte */ > > -#define SHPC_PROG_IFC 0x13 /* 1 byte */ > > -#define SHPC_PROG_IFC_1_0 0x1 > > -#define SHPC_CMD_CODE 0x14 /* 1 byte */ > > -#define SHPC_CMD_TRGT 0x15 /* 1 byte */ > > -#define SHPC_CMD_TRGT_MIN 0x1 > > -#define SHPC_CMD_TRGT_MAX 0x1f > > -#define SHPC_CMD_STATUS 0x16 /* 2 bytes */ > > -#define SHPC_CMD_STATUS_BUSY 0x1 > > -#define SHPC_CMD_STATUS_MRL_OPEN 0x2 > > -#define SHPC_CMD_STATUS_INVALID_CMD 0x4 > > -#define SHPC_CMD_STATUS_INVALID_MODE 0x8 > > -#define SHPC_INT_LOCATOR 0x18 /* 4 bytes */ > > -#define SHPC_INT_COMMAND 0x1 > > -#define SHPC_SERR_LOCATOR 0x1C /* 4 bytes */ > > -#define SHPC_SERR_INT 0x20 /* 4 bytes */ > > -#define SHPC_INT_DIS 0x1 > > -#define SHPC_SERR_DIS 0x2 > > -#define SHPC_CMD_INT_DIS 0x4 > > -#define SHPC_ARB_SERR_DIS 0x8 > > -#define SHPC_CMD_DETECTED 0x10000 > > -#define SHPC_ARB_DETECTED 0x20000 > > - /* 4 bytes * slot # (start from 0) */ > > -#define SHPC_SLOT_REG(s) (0x24 + (s) * 4) > > - /* 2 bytes */ > > -#define SHPC_SLOT_STATUS(s) (0x0 + SHPC_SLOT_REG(s)) > > - > > -/* Same slot state masks are used for command and status registers */ > > -#define SHPC_SLOT_STATE_MASK 0x03 > > -#define SHPC_SLOT_STATE_SHIFT \ > > - (ffs(SHPC_SLOT_STATE_MASK) - 1) > > - > > -#define SHPC_STATE_NO 0x0 > > -#define SHPC_STATE_PWRONLY 0x1 > > -#define SHPC_STATE_ENABLED 0x2 > > -#define SHPC_STATE_DISABLED 0x3 > > - > > -#define SHPC_SLOT_PWR_LED_MASK 0xC > > -#define SHPC_SLOT_PWR_LED_SHIFT \ > > - (ffs(SHPC_SLOT_PWR_LED_MASK) - 1) > > -#define SHPC_SLOT_ATTN_LED_MASK 0x30 > > -#define SHPC_SLOT_ATTN_LED_SHIFT \ > > - (ffs(SHPC_SLOT_ATTN_LED_MASK) - 1) > > - > > -#define SHPC_LED_NO 0x0 > > -#define SHPC_LED_ON 0x1 > > -#define SHPC_LED_BLINK 0x2 > > -#define SHPC_LED_OFF 0x3 > > - > > -#define SHPC_SLOT_STATUS_PWR_FAULT 0x40 > > -#define SHPC_SLOT_STATUS_BUTTON 0x80 > > -#define SHPC_SLOT_STATUS_MRL_OPEN 0x100 > > -#define SHPC_SLOT_STATUS_66 0x200 > > -#define SHPC_SLOT_STATUS_PRSNT_MASK 0xC00 > > -#define SHPC_SLOT_STATUS_PRSNT_EMPTY 0x3 > > -#define SHPC_SLOT_STATUS_PRSNT_25W 0x1 > > -#define SHPC_SLOT_STATUS_PRSNT_15W 0x2 > > -#define SHPC_SLOT_STATUS_PRSNT_7_5W 0x0 > > - > > -#define SHPC_SLOT_STATUS_PRSNT_PCIX 0x3000 > > - > > - > > - /* 1 byte */ > > -#define SHPC_SLOT_EVENT_LATCH(s) (0x2 + SHPC_SLOT_REG(s)) > > - /* 1 byte */ > > -#define SHPC_SLOT_EVENT_SERR_INT_DIS(d, s) (0x3 + SHPC_SLOT_REG(s)) > > -#define SHPC_SLOT_EVENT_PRESENCE 0x01 > > -#define SHPC_SLOT_EVENT_ISOLATED_FAULT 0x02 > > -#define SHPC_SLOT_EVENT_BUTTON 0x04 > > -#define SHPC_SLOT_EVENT_MRL 0x08 > > -#define SHPC_SLOT_EVENT_CONNECTED_FAULT 0x10 > > -/* Bits below are used for Serr/Int disable only */ > > -#define SHPC_SLOT_EVENT_MRL_SERR_DIS 0x20 > > -#define SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS 0x40 > > - > > -#define SHPC_MIN_SLOTS 1 > > -#define SHPC_MAX_SLOTS 31 > > -#define SHPC_SIZEOF(d) SHPC_SLOT_REG((d)->shpc->nslots) > > - > > -/* SHPC Slot identifiers */ > > - > > -/* Hotplug supported at 31 slots out of the total 32. We reserve slot 0, > > - and give the rest of them physical *and* pci numbers starting from 1, so > > - they match logical numbers. Note: this means that multiple slots must have > > - different chassis number values, to make chassis+physical slot unique. > > - TODO: make this configurable? */ > > -#define SHPC_IDX_TO_LOGICAL(slot) ((slot) + 1) > > -#define SHPC_LOGICAL_TO_IDX(target) ((target) - 1) > > -#define SHPC_IDX_TO_PCI(slot) ((slot) + 1) > > -#define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1) > > -#define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1) > > - > > -static int roundup_pow_of_two(int x) > > -{ > > - x |= (x >> 1); > > - x |= (x >> 2); > > - x |= (x >> 4); > > - x |= (x >> 8); > > - x |= (x >> 16); > > - return x + 1; > > -} > > - > > -static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk) > > -{ > > - uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); > > - return (pci_get_word(status) & msk) >> (ffs(msk) - 1); > > -} > > - > > -static void shpc_set_status(SHPCDevice *shpc, > > - int slot, uint8_t value, uint16_t msk) > > -{ > > - uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot); > > - pci_word_test_and_clear_mask(status, msk); > > - pci_word_test_and_set_mask(status, value << (ffs(msk) - 1)); > > -} > > - > > -static void shpc_interrupt_update(PCIDevice *d) > > -{ > > - SHPCDevice *shpc = d->shpc; > > - int slot; > > - int level = 0; > > - uint32_t serr_int; > > - uint32_t int_locator = 0; > > - > > - /* Update interrupt locator register */ > > - for (slot = 0; slot < shpc->nslots; ++slot) { > > - uint8_t event = shpc->config[SHPC_SLOT_EVENT_LATCH(slot)]; > > - uint8_t disable = shpc->config[SHPC_SLOT_EVENT_SERR_INT_DIS(d, slot)]; > > - uint32_t mask = 1 << SHPC_IDX_TO_LOGICAL(slot); > > - if (event & ~disable) { > > - int_locator |= mask; > > - } > > - } > > - serr_int = pci_get_long(shpc->config + SHPC_SERR_INT); > > - if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_DIS)) { > > - int_locator |= SHPC_INT_COMMAND; > > - } > > - pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator); > > - level = (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0; > > - if (msi_enabled(d) && shpc->msi_requested != level) > > - msi_notify(d, 0); > > - else > > - qemu_set_irq(d->irq[0], level); > > - shpc->msi_requested = level; > > -} > > - > > -static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed) > > -{ > > - switch (speed) { > > - case SHPC_SEC_BUS_33: > > - shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK; > > - shpc->config[SHPC_SEC_BUS] |= speed; > > - break; > > - default: > > - pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, > > - SHPC_CMD_STATUS_INVALID_MODE); > > - } > > -} > > - > > -void shpc_reset(PCIDevice *d) > > -{ > > - SHPCDevice *shpc = d->shpc; > > - int nslots = shpc->nslots; > > - int i; > > - memset(shpc->config, 0, SHPC_SIZEOF(d)); > > - pci_set_byte(shpc->config + SHPC_NSLOTS, nslots); > > - pci_set_long(shpc->config + SHPC_SLOTS_33, nslots); > > - pci_set_long(shpc->config + SHPC_SLOTS_66, 0); > > - pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0)); > > - pci_set_word(shpc->config + SHPC_PHYS_SLOT, > > - SHPC_IDX_TO_PHYSICAL(0) | > > - SHPC_PHYS_NUM_UP | > > - SHPC_PHYS_MRL | > > - SHPC_PHYS_BUTTON); > > - pci_set_long(shpc->config + SHPC_SERR_INT, SHPC_INT_DIS | > > - SHPC_SERR_DIS | > > - SHPC_CMD_INT_DIS | > > - SHPC_ARB_SERR_DIS); > > - pci_set_byte(shpc->config + SHPC_PROG_IFC, SHPC_PROG_IFC_1_0); > > - pci_set_word(shpc->config + SHPC_SEC_BUS, SHPC_SEC_BUS_33); > > - for (i = 0; i < shpc->nslots; ++i) { > > - pci_set_byte(shpc->config + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), > > - SHPC_SLOT_EVENT_PRESENCE | > > - SHPC_SLOT_EVENT_ISOLATED_FAULT | > > - SHPC_SLOT_EVENT_BUTTON | > > - SHPC_SLOT_EVENT_MRL | > > - SHPC_SLOT_EVENT_CONNECTED_FAULT | > > - SHPC_SLOT_EVENT_MRL_SERR_DIS | > > - SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); > > - if (shpc->sec_bus->devices[PCI_DEVFN(SHPC_IDX_TO_PCI(i), 0)]) { > > - shpc_set_status(shpc, i, SHPC_STATE_ENABLED, SHPC_SLOT_STATE_MASK); > > - shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_MRL_OPEN); > > - shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_7_5W, > > - SHPC_SLOT_STATUS_PRSNT_MASK); > > - shpc_set_status(shpc, i, SHPC_LED_ON, SHPC_SLOT_PWR_LED_MASK); > > - } else { > > - shpc_set_status(shpc, i, SHPC_STATE_DISABLED, SHPC_SLOT_STATE_MASK); > > - shpc_set_status(shpc, i, 1, SHPC_SLOT_STATUS_MRL_OPEN); > > - shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_EMPTY, > > - SHPC_SLOT_STATUS_PRSNT_MASK); > > - shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK); > > - } > > - shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66); > > - } > > - shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33); > > - shpc->msi_requested = 0; > > - shpc_interrupt_update(d); > > -} > > - > > -static void shpc_invalid_command(SHPCDevice *shpc) > > -{ > > - pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS, > > - SHPC_CMD_STATUS_INVALID_CMD); > > -} > > - > > -static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot) > > -{ > > - int devfn; > > - int pci_slot = SHPC_IDX_TO_PCI(slot); > > - for (devfn = PCI_DEVFN(pci_slot, 0); > > - devfn <= PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1); > > - ++devfn) { > > - PCIDevice *affected_dev = shpc->sec_bus->devices[devfn]; > > - if (affected_dev) { > > - qdev_free(&affected_dev->qdev); > > - } > > - } > > -} > > - > > -static void shpc_slot_command(SHPCDevice *shpc, uint8_t target, > > - uint8_t state, uint8_t power, uint8_t attn) > > -{ > > - uint8_t current_state; > > - int slot = SHPC_LOGICAL_TO_IDX(target); > > - if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) { > > - shpc_invalid_command(shpc); > > - return; > > - } > > - current_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); > > - if (current_state == SHPC_STATE_ENABLED && state == SHPC_STATE_PWRONLY) { > > - shpc_invalid_command(shpc); > > - return; > > - } > > - > > - switch (power) { > > - case SHPC_LED_NO: > > - break; > > - default: > > - /* TODO: send event to monitor */ > > - shpc_set_status(shpc, slot, power, SHPC_SLOT_PWR_LED_MASK); > > - } > > - switch (attn) { > > - case SHPC_LED_NO: > > - break; > > - default: > > - /* TODO: send event to monitor */ > > - shpc_set_status(shpc, slot, attn, SHPC_SLOT_ATTN_LED_MASK); > > - } > > - > > - if ((current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_PWRONLY) || > > - (current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_ENABLED)) { > > - shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > > - } else if ((current_state == SHPC_STATE_ENABLED || > > - current_state == SHPC_STATE_PWRONLY) && > > - state == SHPC_STATE_DISABLED) { > > - shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > > - power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); > > - /* TODO: track what monitor requested. */ > > - /* Look at LED to figure out whether it's ok to remove the device. */ > > - if (power == SHPC_LED_OFF) { > > - shpc_free_devices_in_slot(shpc, slot); > > - shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); > > - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, > > - SHPC_SLOT_STATUS_PRSNT_MASK); > > - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > > - SHPC_SLOT_EVENT_BUTTON | > > - SHPC_SLOT_EVENT_MRL | > > - SHPC_SLOT_EVENT_PRESENCE; > > - } > > - } > > -} > > - > > -static void shpc_command(SHPCDevice *shpc) > > -{ > > - uint8_t code = pci_get_byte(shpc->config + SHPC_CMD_CODE); > > - uint8_t speed; > > - uint8_t target; > > - uint8_t attn; > > - uint8_t power; > > - uint8_t state; > > - int i; > > - > > - /* Clear status from the previous command. */ > > - pci_word_test_and_clear_mask(shpc->config + SHPC_CMD_STATUS, > > - SHPC_CMD_STATUS_BUSY | > > - SHPC_CMD_STATUS_MRL_OPEN | > > - SHPC_CMD_STATUS_INVALID_CMD | > > - SHPC_CMD_STATUS_INVALID_MODE); > > - switch (code) { > > - case 0x00 ... 0x3f: > > - target = shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX; > > - state = (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_SHIFT; > > - power = (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_LED_SHIFT; > > - attn = (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_LED_SHIFT; > > - shpc_slot_command(shpc, target, state, power, attn); > > - break; > > - case 0x40 ... 0x47: > > - speed = code & SHPC_SEC_BUS_MASK; > > - shpc_set_sec_bus_speed(shpc, speed); > > - break; > > - case 0x48: > > - /* Power only all slots */ > > - /* first verify no slots are enabled */ > > - for (i = 0; i < shpc->nslots; ++i) { > > - state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); > > - if (state == SHPC_STATE_ENABLED) { > > - shpc_invalid_command(shpc); > > - goto done; > > - } > > - } > > - for (i = 0; i < shpc->nslots; ++i) { > > - if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { > > - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > > - SHPC_STATE_PWRONLY, SHPC_LED_ON, SHPC_LED_NO); > > - } else { > > - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > > - SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); > > - } > > - } > > - break; > > - case 0x49: > > - /* Enable all slots */ > > - /* TODO: Spec says this shall fail if some are already enabled. > > - * This doesn't make sense - why not? a spec bug? */ > > - for (i = 0; i < shpc->nslots; ++i) { > > - state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK); > > - if (state == SHPC_STATE_ENABLED) { > > - shpc_invalid_command(shpc); > > - goto done; > > - } > > - } > > - for (i = 0; i < shpc->nslots; ++i) { > > - if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) { > > - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > > - SHPC_STATE_ENABLED, SHPC_LED_ON, SHPC_LED_NO); > > - } else { > > - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN, > > - SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO); > > - } > > - } > > - break; > > - default: > > - shpc_invalid_command(shpc); > > - break; > > - } > > -done: > > - pci_long_test_and_set_mask(shpc->config + SHPC_SERR_INT, SHPC_CMD_DETECTED); > > -} > > - > > -static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, int l) > > -{ > > - SHPCDevice *shpc = d->shpc; > > - int i; > > - if (addr >= SHPC_SIZEOF(d)) { > > - return; > > - } > > - l = MIN(l, SHPC_SIZEOF(d) - addr); > > - > > - /* TODO: code duplicated from pci.c */ > > - for (i = 0; i < l; val >>= 8, ++i) { > > - unsigned a = addr + i; > > - uint8_t wmask = shpc->wmask[a]; > > - uint8_t w1cmask = shpc->w1cmask[a]; > > - assert(!(wmask & w1cmask)); > > - shpc->config[a] = (shpc->config[a] & ~wmask) | (val & wmask); > > - shpc->config[a] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ > > - } > > - if (ranges_overlap(addr, l, SHPC_CMD_CODE, 2)) { > > - shpc_command(shpc); > > - } > > - shpc_interrupt_update(d); > > -} > > - > > -static uint64_t shpc_read(PCIDevice *d, unsigned addr, int l) > > -{ > > - uint64_t val = 0x0; > > - if (addr >= SHPC_SIZEOF(d)) { > > - return val; > > - } > > - l = MIN(l, SHPC_SIZEOF(d) - addr); > > - memcpy(&val, d->shpc->config + addr, l); > > - return val; > > -} > > - > > -/* SHPC Bridge Capability */ > > -#define SHPC_CAP_LENGTH 0x08 > > -#define SHPC_CAP_DWORD_SELECT 0x2 /* 1 byte */ > > -#define SHPC_CAP_CxP 0x3 /* 1 byte: CSP, CIP */ > > -#define SHPC_CAP_DWORD_DATA 0x4 /* 4 bytes */ > > -#define SHPC_CAP_CSP_MASK 0x4 > > -#define SHPC_CAP_CIP_MASK 0x8 > > - > > -static uint8_t shpc_cap_dword(PCIDevice *d) > > -{ > > - return pci_get_byte(d->config + d->shpc->cap + SHPC_CAP_DWORD_SELECT); > > -} > > - > > -/* Update dword data capability register */ > > -static void shpc_cap_update_dword(PCIDevice *d) > > -{ > > - unsigned data; > > - data = shpc_read(d, shpc_cap_dword(d) * 4, 4); > > - pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, data); > > -} > > - > > -/* Add SHPC capability to the config space for the device. */ > > -static int shpc_cap_add_config(PCIDevice *d) > > -{ > > - uint8_t *config; > > - int config_offset; > > - config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC, > > - 0, SHPC_CAP_LENGTH); > > - if (config_offset < 0) { > > - return config_offset; > > - } > > - config = d->config + config_offset; > > - > > - pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0); > > - pci_set_byte(config + SHPC_CAP_CxP, 0); > > - pci_set_long(config + SHPC_CAP_DWORD_DATA, 0); > > - d->shpc->cap = config_offset; > > - /* Make dword select and data writeable. */ > > - pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff); > > - pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff); > > - return 0; > > -} > > - > > -static uint64_t shpc_mmio_read(void *opaque, hwaddr addr, > > - unsigned size) > > -{ > > - return shpc_read(opaque, addr, size); > > -} > > - > > -static void shpc_mmio_write(void *opaque, hwaddr addr, > > - uint64_t val, unsigned size) > > -{ > > - shpc_write(opaque, addr, val, size); > > -} > > - > > -static const MemoryRegionOps shpc_mmio_ops = { > > - .read = shpc_mmio_read, > > - .write = shpc_mmio_write, > > - .endianness = DEVICE_LITTLE_ENDIAN, > > - .valid = { > > - /* SHPC ECN requires dword accesses, but the original 1.0 spec doesn't. > > - * It's easier to suppport all sizes than worry about it. */ > > - .min_access_size = 1, > > - .max_access_size = 4, > > - }, > > -}; > > - > > -static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev, > > - PCIHotplugState hotplug_state) > > -{ > > - int pci_slot = PCI_SLOT(affected_dev->devfn); > > - uint8_t state; > > - uint8_t led; > > - PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); > > - SHPCDevice *shpc = d->shpc; > > - int slot = SHPC_PCI_TO_IDX(pci_slot); > > - if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) { > > - error_report("Unsupported PCI slot %d for standard hotplug " > > - "controller. Valid slots are between %d and %d.", > > - pci_slot, SHPC_IDX_TO_PCI(0), > > - SHPC_IDX_TO_PCI(shpc->nslots) - 1); > > - return -1; > > - } > > - /* Don't send event when device is enabled during qemu machine creation: > > - * it is present on boot, no hotplug event is necessary. We do send an > > - * event when the device is disabled later. */ > > - if (hotplug_state == PCI_COLDPLUG_ENABLED) { > > - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); > > - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, > > - SHPC_SLOT_STATUS_PRSNT_MASK); > > - return 0; > > - } > > - if (hotplug_state == PCI_HOTPLUG_DISABLED) { > > - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON; > > - state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); > > - led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); > > - if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) { > > - shpc_free_devices_in_slot(shpc, slot); > > - shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); > > - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY, > > - SHPC_SLOT_STATUS_PRSNT_MASK); > > - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > > - SHPC_SLOT_EVENT_MRL | > > - SHPC_SLOT_EVENT_PRESENCE; > > - } > > - } else { > > - /* This could be a cancellation of the previous removal. > > - * We check MRL state to figure out. */ > > - if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) { > > - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN); > > - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W, > > - SHPC_SLOT_STATUS_PRSNT_MASK); > > - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > > - SHPC_SLOT_EVENT_BUTTON | > > - SHPC_SLOT_EVENT_MRL | > > - SHPC_SLOT_EVENT_PRESENCE; > > - } else { > > - /* Press attention button to cancel removal */ > > - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= > > - SHPC_SLOT_EVENT_BUTTON; > > - } > > - } > > - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66); > > - shpc_interrupt_update(d); > > - return 0; > > -} > > - > > -/* Initialize the SHPC structure in bridge's BAR. */ > > -int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset) > > -{ > > - int i, ret; > > - int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */ > > - SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc)); > > - shpc->sec_bus = sec_bus; > > - ret = shpc_cap_add_config(d); > > - if (ret) { > > - g_free(d->shpc); > > - return ret; > > - } > > - if (nslots < SHPC_MIN_SLOTS) { > > - return 0; > > - } > > - if (nslots > SHPC_MAX_SLOTS || > > - SHPC_IDX_TO_PCI(nslots) > PCI_SLOT_MAX) { > > - /* TODO: report an error mesage that makes sense. */ > > - return -EINVAL; > > - } > > - shpc->nslots = nslots; > > - shpc->config = g_malloc0(SHPC_SIZEOF(d)); > > - shpc->cmask = g_malloc0(SHPC_SIZEOF(d)); > > - shpc->wmask = g_malloc0(SHPC_SIZEOF(d)); > > - shpc->w1cmask = g_malloc0(SHPC_SIZEOF(d)); > > - > > - shpc_reset(d); > > - > > - pci_set_long(shpc->config + SHPC_BASE_OFFSET, offset); > > - > > - pci_set_byte(shpc->wmask + SHPC_CMD_CODE, 0xff); > > - pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); > > - pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX); > > - pci_set_long(shpc->wmask + SHPC_SERR_INT, > > - SHPC_INT_DIS | > > - SHPC_SERR_DIS | > > - SHPC_CMD_INT_DIS | > > - SHPC_ARB_SERR_DIS); > > - pci_set_long(shpc->w1cmask + SHPC_SERR_INT, > > - SHPC_CMD_DETECTED | > > - SHPC_ARB_DETECTED); > > - for (i = 0; i < nslots; ++i) { > > - pci_set_byte(shpc->wmask + > > - SHPC_SLOT_EVENT_SERR_INT_DIS(d, i), > > - SHPC_SLOT_EVENT_PRESENCE | > > - SHPC_SLOT_EVENT_ISOLATED_FAULT | > > - SHPC_SLOT_EVENT_BUTTON | > > - SHPC_SLOT_EVENT_MRL | > > - SHPC_SLOT_EVENT_CONNECTED_FAULT | > > - SHPC_SLOT_EVENT_MRL_SERR_DIS | > > - SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS); > > - pci_set_byte(shpc->w1cmask + > > - SHPC_SLOT_EVENT_LATCH(i), > > - SHPC_SLOT_EVENT_PRESENCE | > > - SHPC_SLOT_EVENT_ISOLATED_FAULT | > > - SHPC_SLOT_EVENT_BUTTON | > > - SHPC_SLOT_EVENT_MRL | > > - SHPC_SLOT_EVENT_CONNECTED_FAULT); > > - } > > - > > - /* TODO: init cmask */ > > - memory_region_init_io(&shpc->mmio, &shpc_mmio_ops, d, "shpc-mmio", > > - SHPC_SIZEOF(d)); > > - shpc_cap_update_dword(d); > > - memory_region_add_subregion(bar, offset, &shpc->mmio); > > - pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev); > > - > > - d->cap_present |= QEMU_PCI_CAP_SHPC; > > - return 0; > > -} > > - > > -int shpc_bar_size(PCIDevice *d) > > -{ > > - return roundup_pow_of_two(SHPC_SLOT_REG(SHPC_MAX_SLOTS)); > > -} > > - > > -void shpc_cleanup(PCIDevice *d, MemoryRegion *bar) > > -{ > > - SHPCDevice *shpc = d->shpc; > > - d->cap_present &= ~QEMU_PCI_CAP_SHPC; > > - memory_region_del_subregion(bar, &shpc->mmio); > > - /* TODO: cleanup config space changes? */ > > - g_free(shpc->config); > > - g_free(shpc->cmask); > > - g_free(shpc->wmask); > > - g_free(shpc->w1cmask); > > - memory_region_destroy(&shpc->mmio); > > - g_free(shpc); > > -} > > - > > -void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) > > -{ > > - if (!ranges_overlap(addr, l, d->shpc->cap, SHPC_CAP_LENGTH)) { > > - return; > > - } > > - if (ranges_overlap(addr, l, d->shpc->cap + SHPC_CAP_DWORD_DATA, 4)) { > > - unsigned dword_data; > > - dword_data = pci_get_long(d->shpc->config + d->shpc->cap > > - + SHPC_CAP_DWORD_DATA); > > - shpc_write(d, shpc_cap_dword(d) * 4, dword_data, 4); > > - } > > - /* Update cap dword data in case guest is going to read it. */ > > - shpc_cap_update_dword(d); > > -} > > - > > -static void shpc_save(QEMUFile *f, void *pv, size_t size) > > -{ > > - PCIDevice *d = container_of(pv, PCIDevice, shpc); > > - qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); > > -} > > - > > -static int shpc_load(QEMUFile *f, void *pv, size_t size) > > -{ > > - PCIDevice *d = container_of(pv, PCIDevice, shpc); > > - int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); > > - if (ret != SHPC_SIZEOF(d)) { > > - return -EINVAL; > > - } > > - /* Make sure we don't lose notifications. An extra interrupt is harmless. */ > > - d->shpc->msi_requested = 0; > > - shpc_interrupt_update(d); > > - return 0; > > -} > > - > > -VMStateInfo shpc_vmstate_info = { > > - .name = "shpc", > > - .get = shpc_load, > > - .put = shpc_save, > > -}; > > diff --git a/hw/shpc.h b/hw/shpc.h > > deleted file mode 100644 > > index 130b71d..0000000 > > --- a/hw/shpc.h > > +++ /dev/null > > @@ -1,48 +0,0 @@ > > -#ifndef SHPC_H > > -#define SHPC_H > > - > > -#include "qemu-common.h" > > -#include "memory.h" > > -#include "vmstate.h" > > - > > -struct SHPCDevice { > > - /* Capability offset in device's config space */ > > - int cap; > > - > > - /* # of hot-pluggable slots */ > > - int nslots; > > - > > - /* SHPC WRS: working register set */ > > - uint8_t *config; > > - > > - /* Used to enable checks on load. Note that writable bits are > > - * never checked even if set in cmask. */ > > - uint8_t *cmask; > > - > > - /* Used to implement R/W bytes */ > > - uint8_t *wmask; > > - > > - /* Used to implement RW1C(Write 1 to Clear) bytes */ > > - uint8_t *w1cmask; > > - > > - /* MMIO for the SHPC BAR */ > > - MemoryRegion mmio; > > - > > - /* Bus controlled by this SHPC */ > > - PCIBus *sec_bus; > > - > > - /* MSI already requested for this event */ > > - int msi_requested; > > -}; > > - > > -void shpc_reset(PCIDevice *d); > > -int shpc_bar_size(PCIDevice *dev); > > -int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off); > > -void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar); > > -void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len); > > - > > -extern VMStateInfo shpc_vmstate_info; > > -#define SHPC_VMSTATE(_field, _type) \ > > - VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0) > > - > > -#endif > > diff --git a/hw/slotid_cap.c b/hw/slotid_cap.c > > deleted file mode 100644 > > index 0106452..0000000 > > --- a/hw/slotid_cap.c > > +++ /dev/null > > @@ -1,44 +0,0 @@ > > -#include "slotid_cap.h" > > -#include "pci.h" > > - > > -#define SLOTID_CAP_LENGTH 4 > > -#define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1) > > - > > -int slotid_cap_init(PCIDevice *d, int nslots, > > - uint8_t chassis, > > - unsigned offset) > > -{ > > - int cap; > > - if (!chassis) { > > - error_report("Bridge chassis not specified. Each bridge is required " > > - "to be assigned a unique chassis id > 0."); > > - return -EINVAL; > > - } > > - if (nslots < 0 || nslots > (PCI_SID_ESR_NSLOTS >> SLOTID_NSLOTS_SHIFT)) { > > - /* TODO: error report? */ > > - return -EINVAL; > > - } > > - > > - cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset, SLOTID_CAP_LENGTH); > > - if (cap < 0) { > > - return cap; > > - } > > - /* We make each chassis unique, this way each bridge is First in Chassis */ > > - d->config[cap + PCI_SID_ESR] = PCI_SID_ESR_FIC | > > - (nslots << SLOTID_NSLOTS_SHIFT); > > - d->cmask[cap + PCI_SID_ESR] = 0xff; > > - d->config[cap + PCI_SID_CHASSIS_NR] = chassis; > > - /* Note: Chassis number register is non-volatile, > > - so we don't reset it. */ > > - /* TODO: store in eeprom? */ > > - d->wmask[cap + PCI_SID_CHASSIS_NR] = 0xff; > > - > > - d->cap_present |= QEMU_PCI_CAP_SLOTID; > > - return 0; > > -} > > - > > -void slotid_cap_cleanup(PCIDevice *d) > > -{ > > - /* TODO: cleanup config space? */ > > - d->cap_present &= ~QEMU_PCI_CAP_SLOTID; > > -} > > diff --git a/hw/slotid_cap.h b/hw/slotid_cap.h > > deleted file mode 100644 > > index 70db047..0000000 > > --- a/hw/slotid_cap.h > > +++ /dev/null > > @@ -1,11 +0,0 @@ > > -#ifndef PCI_SLOTID_CAP_H > > -#define PCI_SLOTID_CAP_H > > - > > -#include "qemu-common.h" > > - > > -int slotid_cap_init(PCIDevice *dev, int nslots, > > - uint8_t chassis, > > - unsigned offset); > > -void slotid_cap_cleanup(PCIDevice *dev); > > - > > -#endif > > -- > > MST > > > > ^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 4/8] pci: update all users to look in pci/ 2012-12-12 13:13 [Qemu-devel] [PATCH 0/8] pci core reorg Michael S. Tsirkin ` (2 preceding siblings ...) 2012-12-12 13:14 ` [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci Michael S. Tsirkin @ 2012-12-12 13:14 ` Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 6/8] Revert "pci: prepare makefiles for pci code reorganization" Michael S. Tsirkin ` (5 subsequent siblings) 9 siblings, 0 replies; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 13:14 UTC (permalink / raw) To: qemu-devel update all users so we can remove the makefile hack. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- arch_init.c | 2 +- hw/ac97.c | 2 +- hw/acpi_ich9.c | 2 +- hw/acpi_piix4.c | 2 +- hw/alpha_sys.h | 4 ++-- hw/apb_pci.c | 8 ++++---- hw/apic.c | 2 +- hw/bonito.c | 4 ++-- hw/cirrus_vga.c | 2 +- hw/dec_pci.c | 8 ++++---- hw/e1000.c | 2 +- hw/eepro100.c | 2 +- hw/es1370.c | 2 +- hw/esp-pci.c | 2 +- hw/grackle_pci.c | 4 ++-- hw/gt64xxx.c | 4 ++-- hw/hda-audio.c | 2 +- hw/i82378.c | 2 +- hw/i82801b11.c | 2 +- hw/ich9.h | 8 ++++---- hw/ide.h | 2 +- hw/ide/ahci.c | 4 ++-- hw/ide/cmd646.c | 2 +- hw/ide/core.c | 2 +- hw/ide/ich.c | 4 ++-- hw/ide/pci.c | 2 +- hw/ide/piix.c | 2 +- hw/ide/via.c | 2 +- hw/intel-hda.c | 4 ++-- hw/ioh3420.c | 6 +++--- hw/ioh3420.h | 2 +- hw/ivshmem.c | 4 ++-- hw/kvm/apic.c | 2 +- hw/kvm/pci-assign.c | 4 ++-- hw/lpc_ich9.c | 8 ++++---- hw/lsi53c895a.c | 2 +- hw/macio.c | 2 +- hw/megasas.c | 4 ++-- hw/mips_fulong2e.c | 2 +- hw/mips_malta.c | 2 +- hw/ne2000.c | 2 +- hw/openpic.c | 2 +- hw/pc.c | 4 ++-- hw/pc_piix.c | 4 ++-- hw/pci_bridge_dev.c | 12 ++++++------ hw/pcnet-pci.c | 2 +- hw/piix4.c | 2 +- hw/piix_pci.c | 4 ++-- hw/ppc/e500.c | 2 +- hw/ppc440_bamboo.c | 2 +- hw/ppc4xx.h | 2 +- hw/ppc4xx_pci.c | 4 ++-- hw/ppc_newworld.c | 2 +- hw/ppc_oldworld.c | 2 +- hw/ppc_prep.c | 4 ++-- hw/ppce500_pci.c | 4 ++-- hw/prep_pci.c | 4 ++-- hw/q35.h | 4 ++-- hw/qxl.h | 2 +- hw/r2d.c | 2 +- hw/realview.c | 2 +- hw/rtl8139.c | 2 +- hw/serial-pci.c | 2 +- hw/sga.c | 2 +- hw/sh_pci.c | 4 ++-- hw/smbus_ich9.c | 2 +- hw/spapr.c | 4 ++-- hw/spapr_pci.c | 10 +++++----- hw/spapr_pci.h | 4 ++-- hw/sun4u.c | 2 +- hw/unin_pci.c | 4 ++-- hw/usb/hcd-ehci-pci.c | 2 +- hw/usb/hcd-ohci.c | 2 +- hw/usb/hcd-uhci.c | 2 +- hw/usb/hcd-xhci.c | 6 +++--- hw/versatile_pci.c | 4 ++-- hw/versatilepb.c | 2 +- hw/vfio_pci.c | 6 +++--- hw/vga-pci.c | 2 +- hw/vga.c | 2 +- hw/virtio-balloon.h | 2 +- hw/virtio-net.h | 2 +- hw/virtio-pci.c | 6 +++--- hw/virtio-scsi.h | 2 +- hw/vmware_vga.c | 2 +- hw/vt82c686.c | 4 ++-- hw/wdt_i6300esb.c | 2 +- hw/xen-host-pci-device.h | 2 +- hw/xen_apic.c | 2 +- hw/xen_platform.c | 2 +- hw/xen_pt.c | 2 +- hw/xen_pt.h | 2 +- hw/xio3130_downstream.c | 6 +++--- hw/xio3130_downstream.h | 2 +- hw/xio3130_upstream.c | 6 +++--- hw/xio3130_upstream.h | 2 +- kvm-all.c | 2 +- kvm-stub.c | 2 +- monitor.c | 2 +- target-i386/kvm.c | 2 +- xen-all.c | 2 +- 101 files changed, 158 insertions(+), 158 deletions(-) diff --git a/arch_init.c b/arch_init.c index e6effe8..e307b23 100644 --- a/arch_init.c +++ b/arch_init.c @@ -36,7 +36,7 @@ #include "arch_init.h" #include "audio/audio.h" #include "hw/pc.h" -#include "hw/pci.h" +#include "hw/pci/pci.h" #include "hw/audiodev.h" #include "kvm.h" #include "migration.h" diff --git a/hw/ac97.c b/hw/ac97.c index ce6a1dc..3e659b3 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -20,7 +20,7 @@ #include "hw.h" #include "audiodev.h" #include "audio/audio.h" -#include "pci.h" +#include "pci/pci.h" #include "dma.h" enum { diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c index 25c9d36..3e01556 100644 --- a/hw/acpi_ich9.c +++ b/hw/acpi_ich9.c @@ -25,7 +25,7 @@ */ #include "hw.h" #include "pc.h" -#include "pci.h" +#include "pci/pci.h" #include "qemu-timer.h" #include "sysemu.h" #include "acpi.h" diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 519269a..846f40a 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -22,7 +22,7 @@ #include "pc.h" #include "apm.h" #include "pm_smbus.h" -#include "pci.h" +#include "pci/pci.h" #include "acpi.h" #include "sysemu.h" #include "range.h" diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h index 7604d09..b1e5258 100644 --- a/hw/alpha_sys.h +++ b/hw/alpha_sys.h @@ -3,8 +3,8 @@ #ifndef HW_ALPHA_H #define HW_ALPHA_H 1 -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "ide.h" #include "net.h" #include "pc.h" diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 054814f..de594f8 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -27,10 +27,10 @@ the secondary PCI bridge. */ #include "sysbus.h" -#include "pci.h" -#include "pci_host.h" -#include "pci_bridge.h" -#include "pci_internals.h" +#include "pci/pci.h" +#include "pci/pci_host.h" +#include "pci/pci_bridge.h" +#include "pci/pci_internals.h" #include "apb_pci.h" #include "sysemu.h" #include "exec-memory.h" diff --git a/hw/apic.c b/hw/apic.c index f73fc87..d66a476 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -20,7 +20,7 @@ #include "apic_internal.h" #include "apic.h" #include "ioapic.h" -#include "msi.h" +#include "pci/msi.h" #include "host-utils.h" #include "trace.h" #include "pc.h" diff --git a/hw/bonito.c b/hw/bonito.c index 0bf6d4a..a1fc38c 100644 --- a/hw/bonito.c +++ b/hw/bonito.c @@ -40,10 +40,10 @@ #include <assert.h> #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "pc.h" #include "mips.h" -#include "pci_host.h" +#include "pci/pci_host.h" #include "sysemu.h" #include "exec-memory.h" diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 9bef96e..2364828 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -27,7 +27,7 @@ * available at http://home.worldonline.dk/~finth/ */ #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "console.h" #include "vga_int.h" #include "loader.h" diff --git a/hw/dec_pci.c b/hw/dec_pci.c index c30ade3..a6a7c84 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -25,10 +25,10 @@ #include "dec_pci.h" #include "sysbus.h" -#include "pci.h" -#include "pci_host.h" -#include "pci_bridge.h" -#include "pci_internals.h" +#include "pci/pci.h" +#include "pci/pci_host.h" +#include "pci/pci_bridge.h" +#include "pci/pci_internals.h" /* debug DEC */ //#define DEBUG_DEC diff --git a/hw/e1000.c b/hw/e1000.c index cb7e7e8..ecd81d8 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -26,7 +26,7 @@ #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "net.h" #include "net/checksum.h" #include "loader.h" diff --git a/hw/eepro100.c b/hw/eepro100.c index a189474..992f03a 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -42,7 +42,7 @@ #include <stddef.h> /* offsetof */ #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "net.h" #include "eeprom93xx.h" #include "sysemu.h" diff --git a/hw/es1370.c b/hw/es1370.c index e0c9729..6536578 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -29,7 +29,7 @@ #include "hw.h" #include "audiodev.h" #include "audio/audio.h" -#include "pci.h" +#include "pci/pci.h" #include "dma.h" /* Missing stuff: diff --git a/hw/esp-pci.c b/hw/esp-pci.c index d9a8e59..d433473 100644 --- a/hw/esp-pci.c +++ b/hw/esp-pci.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ -#include "pci.h" +#include "pci/pci.h" #include "eeprom93xx.h" #include "esp.h" #include "trace.h" diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 67da307..9484166 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -23,9 +23,9 @@ * THE SOFTWARE. */ -#include "pci_host.h" +#include "pci/pci_host.h" #include "ppc_mac.h" -#include "pci.h" +#include "pci/pci.h" /* debug Grackle */ //#define DEBUG_GRACKLE diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 95d491d..5aa49c6 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -24,8 +24,8 @@ #include "hw.h" #include "mips.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "pc.h" #include "exec-memory.h" diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 36761dd..92a91b5 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -18,7 +18,7 @@ */ #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "intel-hda.h" #include "intel-hda-defs.h" #include "audio/audio.h" diff --git a/hw/i82378.c b/hw/i82378.c index 99f35d4..c6b0b5e 100644 --- a/hw/i82378.c +++ b/hw/i82378.c @@ -17,7 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pci.h" +#include "pci/pci.h" #include "pc.h" #include "i8254.h" #include "pcspk.h" diff --git a/hw/i82801b11.c b/hw/i82801b11.c index 3d1f996..3dc1000 100644 --- a/hw/i82801b11.c +++ b/hw/i82801b11.c @@ -41,7 +41,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/> */ -#include "pci.h" +#include "pci/pci.h" #include "ich9.h" diff --git a/hw/ich9.h b/hw/ich9.h index de49135..247be94 100644 --- a/hw/ich9.h +++ b/hw/ich9.h @@ -8,13 +8,13 @@ #include "pc.h" #include "apm.h" #include "ioapic.h" -#include "pci.h" -#include "pcie_host.h" -#include "pci_bridge.h" +#include "pci/pci.h" +#include "pci/pcie_host.h" +#include "pci/pci_bridge.h" #include "acpi.h" #include "acpi_ich9.h" #include "pam.h" -#include "pci_internals.h" +#include "pci/pci_internals.h" void ich9_lpc_set_irq(void *opaque, int irq_num, int level); int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx); diff --git a/hw/ide.h b/hw/ide.h index add742c..081c710 100644 --- a/hw/ide.h +++ b/hw/ide.h @@ -2,7 +2,7 @@ #define HW_IDE_H #include "isa.h" -#include "pci.h" +#include "pci/pci.h" #include "memory.h" #define MAX_IDE_DEVS 2 diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 67562db..2ea64bd 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -22,9 +22,9 @@ */ #include <hw/hw.h> -#include <hw/msi.h> +#include <hw/pci/msi.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/sysbus.h> #include "monitor.h" diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 804db60..88210ea 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -24,7 +24,7 @@ */ #include <hw/hw.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> #include "block.h" #include "sysemu.h" diff --git a/hw/ide/core.c b/hw/ide/core.c index 8da894f..8ddafbb 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -24,7 +24,7 @@ */ #include <hw/hw.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> #include "qemu-error.h" #include "qemu-timer.h" diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 272b773..8e1a48e 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -61,9 +61,9 @@ */ #include <hw/hw.h> -#include <hw/msi.h> +#include <hw/pci/msi.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> #include "block.h" #include "dma.h" diff --git a/hw/ide/pci.c b/hw/ide/pci.c index bcdd70e..23a0e23 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -24,7 +24,7 @@ */ #include <hw/hw.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> #include "block.h" #include "dma.h" diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 9431bad..5cf39cf 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -25,7 +25,7 @@ #include <hw/hw.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> #include "blockdev.h" #include "sysemu.h" diff --git a/hw/ide/via.c b/hw/ide/via.c index efda173..8b4a24e 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -25,7 +25,7 @@ */ #include <hw/hw.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> #include "block.h" #include "sysemu.h" diff --git a/hw/intel-hda.c b/hw/intel-hda.c index a68c368..c21bf72 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -18,8 +18,8 @@ */ #include "hw.h" -#include "pci.h" -#include "msi.h" +#include "pci/pci.h" +#include "pci/msi.h" #include "qemu-timer.h" #include "audiodev.h" #include "intel-hda.h" diff --git a/hw/ioh3420.c b/hw/ioh3420.c index 4d31473..d706e19 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -20,9 +20,9 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "pci_ids.h" -#include "msi.h" -#include "pcie.h" +#include "pci/pci_ids.h" +#include "pci/msi.h" +#include "pci/pcie.h" #include "ioh3420.h" #define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */ diff --git a/hw/ioh3420.h b/hw/ioh3420.h index 68c523a..046cf2c 100644 --- a/hw/ioh3420.h +++ b/hw/ioh3420.h @@ -1,7 +1,7 @@ #ifndef QEMU_IOH3420_H #define QEMU_IOH3420_H -#include "pcie_port.h" +#include "pci/pcie_port.h" PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, diff --git a/hw/ivshmem.c b/hw/ivshmem.c index f6dbb21..cf64f32 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -18,8 +18,8 @@ */ #include "hw.h" #include "pc.h" -#include "pci.h" -#include "msix.h" +#include "pci/pci.h" +#include "pci/msix.h" #include "kvm.h" #include "migration.h" #include "qerror.h" diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c index 8b65d51..beb418d 100644 --- a/hw/kvm/apic.c +++ b/hw/kvm/apic.c @@ -10,7 +10,7 @@ * See the COPYING file in the top-level directory. */ #include "hw/apic_internal.h" -#include "hw/msi.h" +#include "hw/pci/msi.h" #include "kvm.h" static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic, diff --git a/hw/kvm/pci-assign.c b/hw/kvm/pci-assign.c index e80dad0..4229159 100644 --- a/hw/kvm/pci-assign.c +++ b/hw/kvm/pci-assign.c @@ -34,8 +34,8 @@ #include "monitor.h" #include "range.h" #include "sysemu.h" -#include "hw/pci.h" -#include "hw/msi.h" +#include "hw/pci/pci.h" +#include "hw/pci/msi.h" #include "kvm_i386.h" #define MSIX_PAGE_SIZE 0x1000 diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c index f253dbd..23dee88 100644 --- a/hw/lpc_ich9.c +++ b/hw/lpc_ich9.c @@ -35,14 +35,14 @@ #include "pc.h" #include "apm.h" #include "ioapic.h" -#include "pci.h" -#include "pcie_host.h" -#include "pci_bridge.h" +#include "pci/pci.h" +#include "pci/pcie_host.h" +#include "pci/pci_bridge.h" #include "ich9.h" #include "acpi.h" #include "acpi_ich9.h" #include "pam.h" -#include "pci_internals.h" +#include "pci/pci_internals.h" #include "exec-memory.h" static int ich9_lpc_sci_irq(ICH9LPCState *lpc); diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 04f2fae..4aac9a0 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -13,7 +13,7 @@ #include <assert.h> #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "scsi.h" #include "dma.h" diff --git a/hw/macio.c b/hw/macio.c index eb15b89..362afdc 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -24,7 +24,7 @@ */ #include "hw.h" #include "ppc_mac.h" -#include "pci.h" +#include "pci/pci.h" #include "escc.h" typedef struct MacIOState diff --git a/hw/megasas.c b/hw/megasas.c index 61b6527..f4fbe97 100644 --- a/hw/megasas.c +++ b/hw/megasas.c @@ -19,9 +19,9 @@ */ #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "dma.h" -#include "msix.h" +#include "pci/msix.h" #include "iov.h" #include "scsi.h" #include "scsi-defs.h" diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 5fcf900..d5cf33b 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -29,7 +29,7 @@ #include "flash.h" #include "mips.h" #include "mips_cpudevs.h" -#include "pci.h" +#include "pci/pci.h" #include "qemu-char.h" #include "sysemu.h" #include "audio/audio.h" diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 4d2464a..571903d 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -33,7 +33,7 @@ #include "flash.h" #include "mips.h" #include "mips_cpudevs.h" -#include "pci.h" +#include "pci/pci.h" #include "qemu-char.h" #include "sysemu.h" #include "arch_init.h" diff --git a/hw/ne2000.c b/hw/ne2000.c index d3dd9a6..fb78e5b 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "net.h" #include "ne2000.h" #include "loader.h" diff --git a/hw/openpic.c b/hw/openpic.c index 8b3784a..4791dc6 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -35,7 +35,7 @@ */ #include "hw.h" #include "ppc_mac.h" -#include "pci.h" +#include "pci/pci.h" #include "openpic.h" //#define DEBUG_OPENPIC diff --git a/hw/pc.c b/hw/pc.c index 2b5bbbf..77470bc 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -27,7 +27,7 @@ #include "apic.h" #include "fdc.h" #include "ide.h" -#include "pci.h" +#include "pci/pci.h" #include "monitor.h" #include "fw_cfg.h" #include "hpet_emul.h" @@ -38,7 +38,7 @@ #include "mc146818rtc.h" #include "i8254.h" #include "pcspk.h" -#include "msi.h" +#include "pci/msi.h" #include "sysbus.h" #include "sysemu.h" #include "kvm.h" diff --git a/hw/pc_piix.c b/hw/pc_piix.c index aa3e7f4..890a1d9 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -27,8 +27,8 @@ #include "hw.h" #include "pc.h" #include "apic.h" -#include "pci.h" -#include "pci_ids.h" +#include "pci/pci.h" +#include "pci/pci_ids.h" #include "usb.h" #include "net.h" #include "boards.h" diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index f706396..5c9fc50 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -19,13 +19,13 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "pci_bridge.h" -#include "pci_ids.h" -#include "msi.h" -#include "shpc.h" -#include "slotid_cap.h" +#include "pci/pci_bridge.h" +#include "pci/pci_ids.h" +#include "pci/msi.h" +#include "pci/shpc.h" +#include "pci/slotid_cap.h" #include "memory.h" -#include "pci_internals.h" +#include "pci/pci_internals.h" #define REDHAT_PCI_VENDOR_ID 0x1b36 #define PCI_BRIDGE_DEV_VENDOR_ID REDHAT_PCI_VENDOR_ID diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 0bf438f..c1abbf8 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -27,7 +27,7 @@ * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 */ -#include "pci.h" +#include "pci/pci.h" #include "net.h" #include "loader.h" #include "qemu-timer.h" diff --git a/hw/piix4.c b/hw/piix4.c index ce4eb0d..799ed17 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -24,7 +24,7 @@ #include "hw.h" #include "pc.h" -#include "pci.h" +#include "pci/pci.h" #include "isa.h" #include "sysbus.h" diff --git a/hw/piix_pci.c b/hw/piix_pci.c index ba1b3de..b5ea68b 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -24,8 +24,8 @@ #include "hw.h" #include "pc.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "isa.h" #include "sysbus.h" #include "range.h" diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 6749fff..f77c488 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -20,7 +20,7 @@ #include "net.h" #include "hw/hw.h" #include "hw/serial.h" -#include "hw/pci.h" +#include "hw/pci/pci.h" #include "hw/boards.h" #include "sysemu.h" #include "kvm.h" diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index cc85607..0b39a81 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -15,7 +15,7 @@ #include "qemu-common.h" #include "net.h" #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "boards.h" #include "kvm.h" #include "kvm_ppc.h" diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h index d795ced..2b96d47 100644 --- a/hw/ppc4xx.h +++ b/hw/ppc4xx.h @@ -25,7 +25,7 @@ #if !defined(PPC_4XX_H) #define PPC_4XX_H -#include "pci.h" +#include "pci/pci.h" /* PowerPC 4xx core initialization */ CPUPPCState *ppc4xx_init (const char *cpu_model, diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index d3ad6a0..3e8af11 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -22,8 +22,8 @@ #include "hw.h" #include "ppc.h" #include "ppc4xx.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "exec-memory.h" #undef DEBUG diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index 664747e..c1ff9d7 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -52,7 +52,7 @@ #include "adb.h" #include "mac_dbdma.h" #include "nvram.h" -#include "pci.h" +#include "pci/pci.h" #include "net.h" #include "sysemu.h" #include "boards.h" diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index e8138c0..3bc29c6 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -32,7 +32,7 @@ #include "sysemu.h" #include "net.h" #include "isa.h" -#include "pci.h" +#include "pci/pci.h" #include "boards.h" #include "fw_cfg.h" #include "escc.h" diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index bf15730..f6ffb59 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -29,8 +29,8 @@ #include "net.h" #include "sysemu.h" #include "isa.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "ppc.h" #include "boards.h" #include "qemu-log.h" diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 2ff7438..39022aa 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -15,8 +15,8 @@ */ #include "hw.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "bswap.h" #ifdef DEBUG_PCI diff --git a/hw/prep_pci.c b/hw/prep_pci.c index 0bc479c..5f22de6 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -23,8 +23,8 @@ */ #include "hw.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "pc.h" #include "exec-memory.h" diff --git a/hw/q35.h b/hw/q35.h index e34f7c1..2f951c8 100644 --- a/hw/q35.h +++ b/hw/q35.h @@ -29,8 +29,8 @@ #include "pc.h" #include "apm.h" #include "apic.h" -#include "pci.h" -#include "pcie_host.h" +#include "pci/pci.h" +#include "pci/pcie_host.h" #include "acpi.h" #include "acpi_ich9.h" #include "pam.h" diff --git a/hw/qxl.h b/hw/qxl.h index e583cfb..41246c7 100644 --- a/hw/qxl.h +++ b/hw/qxl.h @@ -2,7 +2,7 @@ #include "console.h" #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "vga_int.h" #include "qemu-thread.h" diff --git a/hw/r2d.c b/hw/r2d.c index 66212e9..e18c23b 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -29,7 +29,7 @@ #include "devices.h" #include "sysemu.h" #include "boards.h" -#include "pci.h" +#include "pci/pci.h" #include "net.h" #include "sh7750_regs.h" #include "ide.h" diff --git a/hw/realview.c b/hw/realview.c index e789c15..149bb56 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -11,7 +11,7 @@ #include "arm-misc.h" #include "primecell.h" #include "devices.h" -#include "pci.h" +#include "pci/pci.h" #include "net.h" #include "sysemu.h" #include "boards.h" diff --git a/hw/rtl8139.c b/hw/rtl8139.c index e3aa8bf..e294a2a 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -52,7 +52,7 @@ #include <zlib.h> #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "dma.h" #include "qemu-timer.h" #include "net.h" diff --git a/hw/serial-pci.c b/hw/serial-pci.c index 95dc5c8..6a2548a 100644 --- a/hw/serial-pci.c +++ b/hw/serial-pci.c @@ -26,7 +26,7 @@ /* see docs/specs/pci-serial.txt */ #include "serial.h" -#include "pci.h" +#include "pci/pci.h" #define PCI_SERIAL_MAX_PORTS 4 diff --git a/hw/sga.c b/hw/sga.c index a666349..5d80efd 100644 --- a/hw/sga.c +++ b/hw/sga.c @@ -24,7 +24,7 @@ * sgabios code originally available at code.google.com/p/sgabios * */ -#include "pci.h" +#include "pci/pci.h" #include "pc.h" #include "loader.h" #include "sysemu.h" diff --git a/hw/sh_pci.c b/hw/sh_pci.c index fdec71b..9ea08c8 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -23,8 +23,8 @@ */ #include "sysbus.h" #include "sh.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "bswap.h" #include "exec-memory.h" diff --git a/hw/smbus_ich9.c b/hw/smbus_ich9.c index 6d31e24..0c52497 100644 --- a/hw/smbus_ich9.c +++ b/hw/smbus_ich9.c @@ -27,7 +27,7 @@ #include "hw.h" #include "pc.h" #include "pm_smbus.h" -#include "pci.h" +#include "pci/pci.h" #include "sysemu.h" #include "i2c.h" #include "smbus.h" diff --git a/hw/spapr.c b/hw/spapr.c index ad3f0ea..b0125a8 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -41,11 +41,11 @@ #include "hw/spapr_vio.h" #include "hw/spapr_pci.h" #include "hw/xics.h" -#include "hw/msi.h" +#include "hw/pci/msi.h" #include "kvm.h" #include "kvm_ppc.h" -#include "pci.h" +#include "pci/pci.h" #include "exec-memory.h" #include "hw/usb.h" diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index a08ed11..e123866 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -23,17 +23,17 @@ * THE SOFTWARE. */ #include "hw.h" -#include "pci.h" -#include "msi.h" -#include "msix.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/msi.h" +#include "pci/msix.h" +#include "pci/pci_host.h" #include "hw/spapr.h" #include "hw/spapr_pci.h" #include "exec-memory.h" #include <libfdt.h> #include "trace.h" -#include "hw/pci_internals.h" +#include "hw/pci/pci_internals.h" /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */ #define RTAS_QUERY_FN 0 diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h index e307ac8..7b26ba1 100644 --- a/hw/spapr_pci.h +++ b/hw/spapr_pci.h @@ -23,8 +23,8 @@ #if !defined(__HW_SPAPR_PCI_H__) #define __HW_SPAPR_PCI_H__ -#include "hw/pci.h" -#include "hw/pci_host.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" #include "hw/xics.h" #define SPAPR_MSIX_MAX_DEVS 32 diff --git a/hw/sun4u.c b/hw/sun4u.c index b2b51e3..47bcf93 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "apb_pci.h" #include "pc.h" #include "serial.h" diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 9981d94..4675792 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -23,8 +23,8 @@ */ #include "hw.h" #include "ppc_mac.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" /* debug UniNorth */ //#define DEBUG_UNIN diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index 5887eab..c957c11 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -16,7 +16,7 @@ */ #include "hw/usb/hcd-ehci.h" -#include "hw/pci.h" +#include "hw/pci/pci.h" #include "range.h" typedef struct EHCIPCIState { diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 64de906..6b7c3dc 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -29,7 +29,7 @@ #include "hw/hw.h" #include "qemu-timer.h" #include "hw/usb.h" -#include "hw/pci.h" +#include "hw/pci/pci.h" #include "hw/sysbus.h" #include "hw/qdev-dma.h" diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 8e47803..808b004 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -27,7 +27,7 @@ */ #include "hw/hw.h" #include "hw/usb.h" -#include "hw/pci.h" +#include "hw/pci/pci.h" #include "qemu-timer.h" #include "iov.h" #include "dma.h" diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 8ef4b07..93117ec 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -21,9 +21,9 @@ #include "hw/hw.h" #include "qemu-timer.h" #include "hw/usb.h" -#include "hw/pci.h" -#include "hw/msi.h" -#include "hw/msix.h" +#include "hw/pci/pci.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" #include "trace.h" //#define DEBUG_XHCI diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index e0c3ee3..7a543b4 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -8,8 +8,8 @@ */ #include "sysbus.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "exec-memory.h" typedef struct { diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 25e652b..41e39d8 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -12,7 +12,7 @@ #include "devices.h" #include "net.h" #include "sysemu.h" -#include "pci.h" +#include "pci/pci.h" #include "i2c.h" #include "boards.h" #include "blockdev.h" diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 7c27834..45d90ab 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -31,9 +31,9 @@ #include "exec-memory.h" #include "kvm.h" #include "memory.h" -#include "msi.h" -#include "msix.h" -#include "pci.h" +#include "pci/msi.h" +#include "pci/msix.h" +#include "pci/pci.h" #include "qemu-common.h" #include "qemu-error.h" #include "qemu-queue.h" diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 947e35c..0cb318e 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -25,7 +25,7 @@ */ #include "hw.h" #include "console.h" -#include "pci.h" +#include "pci/pci.h" #include "vga_int.h" #include "pixel_ops.h" #include "qemu-timer.h" diff --git a/hw/vga.c b/hw/vga.c index 2b0200a..6d56f8a 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -25,7 +25,7 @@ #include "vga.h" #include "console.h" #include "pc.h" -#include "pci.h" +#include "pci/pci.h" #include "vga_int.h" #include "pixel_ops.h" #include "qemu-timer.h" diff --git a/hw/virtio-balloon.h b/hw/virtio-balloon.h index 73300dd..b1828f4 100644 --- a/hw/virtio-balloon.h +++ b/hw/virtio-balloon.h @@ -16,7 +16,7 @@ #define _QEMU_VIRTIO_BALLOON_H #include "virtio.h" -#include "pci.h" +#include "pci/pci.h" /* from Linux's linux/virtio_balloon.h */ diff --git a/hw/virtio-net.h b/hw/virtio-net.h index 36aa463..b13be7c 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -16,7 +16,7 @@ #include "virtio.h" #include "net.h" -#include "pci.h" +#include "pci/pci.h" #define ETH_ALEN 6 diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 71f4fb5..e9b722d 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -22,10 +22,10 @@ #include "virtio-net.h" #include "virtio-serial.h" #include "virtio-scsi.h" -#include "pci.h" +#include "pci/pci.h" #include "qemu-error.h" -#include "msi.h" -#include "msix.h" +#include "pci/msi.h" +#include "pci/msix.h" #include "net.h" #include "loader.h" #include "kvm.h" diff --git a/hw/virtio-scsi.h b/hw/virtio-scsi.h index 91924f6..7d7cba7 100644 --- a/hw/virtio-scsi.h +++ b/hw/virtio-scsi.h @@ -16,7 +16,7 @@ #include "virtio.h" #include "net.h" -#include "pci.h" +#include "pci/pci.h" /* The ID for virtio_scsi */ #define VIRTIO_ID_SCSI 8 diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 834588d..333ec8c 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -24,7 +24,7 @@ #include "hw.h" #include "loader.h" #include "console.h" -#include "pci.h" +#include "pci/pci.h" #undef VERBOSE #define HW_RECT_ACCEL diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 5d7c00c..620fb75 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -15,7 +15,7 @@ #include "vt82c686.h" #include "i2c.h" #include "smbus.h" -#include "pci.h" +#include "pci/pci.h" #include "isa.h" #include "sysbus.h" #include "mips.h" @@ -26,7 +26,7 @@ #include "qemu-timer.h" typedef uint32_t pci_addr_t; -#include "pci_host.h" +#include "pci/pci_host.h" //#define DEBUG_VT82C686B #ifdef DEBUG_VT82C686B diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index da15c73..1817742 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -25,7 +25,7 @@ #include "qemu-timer.h" #include "watchdog.h" #include "hw.h" -#include "pci.h" +#include "pci/pci.h" /*#define I6300ESB_DEBUG 1*/ diff --git a/hw/xen-host-pci-device.h b/hw/xen-host-pci-device.h index 0079dac..942b24d 100644 --- a/hw/xen-host-pci-device.h +++ b/hw/xen-host-pci-device.h @@ -1,7 +1,7 @@ #ifndef XEN_HOST_PCI_DEVICE_H #define XEN_HOST_PCI_DEVICE_H -#include "pci.h" +#include "pci/pci.h" enum { XEN_HOST_PCI_REGION_TYPE_IO = 1 << 1, diff --git a/hw/xen_apic.c b/hw/xen_apic.c index fc45366..a6632fe 100644 --- a/hw/xen_apic.c +++ b/hw/xen_apic.c @@ -10,7 +10,7 @@ * later. See the COPYING file in the top-level directory. */ #include "hw/apic_internal.h" -#include "hw/msi.h" +#include "hw/pci/msi.h" #include "xen.h" static uint64_t xen_apic_mem_read(void *opaque, hwaddr addr, diff --git a/hw/xen_platform.c b/hw/xen_platform.c index a54e7a2..10bb560 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -27,7 +27,7 @@ #include "hw.h" #include "pc.h" -#include "pci.h" +#include "pci/pci.h" #include "irq.h" #include "xen_common.h" #include "net.h" diff --git a/hw/xen_pt.c b/hw/xen_pt.c index 7a3846e..c782cdb 100644 --- a/hw/xen_pt.c +++ b/hw/xen_pt.c @@ -54,7 +54,7 @@ #include <sys/ioctl.h> -#include "pci.h" +#include "pci/pci.h" #include "xen.h" #include "xen_backend.h" #include "xen_pt.h" diff --git a/hw/xen_pt.h b/hw/xen_pt.h index f15e69a..e349730 100644 --- a/hw/xen_pt.h +++ b/hw/xen_pt.h @@ -3,7 +3,7 @@ #include "qemu-common.h" #include "xen_common.h" -#include "pci.h" +#include "pci/pci.h" #include "xen-host-pci-device.h" void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3); diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index 0d8a5e7..2dcd46b 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -19,9 +19,9 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "pci_ids.h" -#include "msi.h" -#include "pcie.h" +#include "pci/pci_ids.h" +#include "pci/msi.h" +#include "pci/pcie.h" #include "xio3130_downstream.h" #define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */ diff --git a/hw/xio3130_downstream.h b/hw/xio3130_downstream.h index 010487f..559dff6 100644 --- a/hw/xio3130_downstream.h +++ b/hw/xio3130_downstream.h @@ -1,7 +1,7 @@ #ifndef QEMU_XIO3130_DOWNSTREAM_H #define QEMU_XIO3130_DOWNSTREAM_H -#include "pcie_port.h" +#include "pci/pcie_port.h" PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index d46b86c..713caf2 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -19,9 +19,9 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "pci_ids.h" -#include "msi.h" -#include "pcie.h" +#include "pci/pci_ids.h" +#include "pci/msi.h" +#include "pci/pcie.h" #include "xio3130_upstream.h" #define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */ diff --git a/hw/xio3130_upstream.h b/hw/xio3130_upstream.h index e996997..fa09656 100644 --- a/hw/xio3130_upstream.h +++ b/hw/xio3130_upstream.h @@ -1,7 +1,7 @@ #ifndef QEMU_XIO3130_UPSTREAM_H #define QEMU_XIO3130_UPSTREAM_H -#include "pcie_port.h" +#include "pci/pcie_port.h" PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, diff --git a/kvm-all.c b/kvm-all.c index fb3180d..4bbad86 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -26,7 +26,7 @@ #include "qemu-config.h" #include "sysemu.h" #include "hw/hw.h" -#include "hw/msi.h" +#include "hw/pci/msi.h" #include "gdbstub.h" #include "kvm.h" #include "bswap.h" diff --git a/kvm-stub.c b/kvm-stub.c index a3455e2..d65fd04 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -12,7 +12,7 @@ #include "qemu-common.h" #include "hw/hw.h" -#include "hw/msi.h" +#include "hw/pci/msi.h" #include "cpu.h" #include "gdbstub.h" #include "kvm.h" diff --git a/monitor.c b/monitor.c index c0e32d6..a92ab44 100644 --- a/monitor.c +++ b/monitor.c @@ -27,7 +27,7 @@ #include "hw/usb.h" #include "hw/pcmcia.h" #include "hw/pc.h" -#include "hw/pci.h" +#include "hw/pci/pci.h" #include "hw/watchdog.h" #include "hw/loader.h" #include "gdbstub.h" diff --git a/target-i386/kvm.c b/target-i386/kvm.c index f669281..0901589 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -31,7 +31,7 @@ #include "hw/apic.h" #include "ioport.h" #include "hyperv.h" -#include "hw/pci.h" +#include "hw/pci/pci.h" //#define DEBUG_KVM diff --git a/xen-all.c b/xen-all.c index 046cc2a..e3a51cc 100644 --- a/xen-all.c +++ b/xen-all.c @@ -10,7 +10,7 @@ #include <sys/mman.h> -#include "hw/pci.h" +#include "hw/pci/pci.h" #include "hw/pc.h" #include "hw/xen_common.h" #include "hw/xen_backend.h" -- MST ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 6/8] Revert "pci: prepare makefiles for pci code reorganization" 2012-12-12 13:13 [Qemu-devel] [PATCH 0/8] pci core reorg Michael S. Tsirkin ` (3 preceding siblings ...) 2012-12-12 13:14 ` [Qemu-devel] [PATCH 4/8] pci: update all users to look in pci/ Michael S. Tsirkin @ 2012-12-12 13:14 ` Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 5/8] pci: make external dependencies explicit Michael S. Tsirkin ` (4 subsequent siblings) 9 siblings, 0 replies; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 13:14 UTC (permalink / raw) To: qemu-devel This reverts commit 475d67c3bcd6ba9fef917b6e59d96ae69eb1a9b4. Now that all users have been updated, we don't need the makefile hack or the softlink anymore. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- Makefile | 1 - Makefile.target | 1 - Makefile.user | 1 - hw/pci/hw | 1 - 4 files changed, 4 deletions(-) delete mode 120000 hw/pci/hw diff --git a/Makefile b/Makefile index b9a81d1..9ecbcbb 100644 --- a/Makefile +++ b/Makefile @@ -146,7 +146,6 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS) QEMU_CFLAGS+=$(CURL_CFLAGS) QEMU_CFLAGS += -I$(SRC_PATH)/include -QEMU_CFLAGS+=-I$(SRC_PATH)/hw/pci -I$(SRC_PATH)/hw ui/cocoa.o: ui/cocoa.m diff --git a/Makefile.target b/Makefile.target index e2e8840..8b658c0 100644 --- a/Makefile.target +++ b/Makefile.target @@ -12,7 +12,6 @@ endif QEMU_CFLAGS += -I.. -I$(SRC_PATH)/target-$(TARGET_BASE_ARCH) -DNEED_CPU_H QEMU_CFLAGS+=-I$(SRC_PATH)/include -QEMU_CFLAGS+=-I$(SRC_PATH)/hw/pci -I$(SRC_PATH)/hw ifdef CONFIG_USER_ONLY # user emulator name diff --git a/Makefile.user b/Makefile.user index 045ecd3..9302d33 100644 --- a/Makefile.user +++ b/Makefile.user @@ -11,7 +11,6 @@ $(call set-vpath, $(SRC_PATH)) QEMU_CFLAGS+=-I.. QEMU_CFLAGS += -I$(SRC_PATH)/include QEMU_CFLAGS += -DCONFIG_USER_ONLY -QEMU_CFLAGS+=-I$(SRC_PATH)/hw/pci -I$(SRC_PATH)/hw include $(SRC_PATH)/Makefile.objs diff --git a/hw/pci/hw b/hw/pci/hw deleted file mode 120000 index 945c9b4..0000000 --- a/hw/pci/hw +++ /dev/null @@ -1 +0,0 @@ -. \ No newline at end of file -- MST ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 5/8] pci: make external dependencies explicit 2012-12-12 13:13 [Qemu-devel] [PATCH 0/8] pci core reorg Michael S. Tsirkin ` (4 preceding siblings ...) 2012-12-12 13:14 ` [Qemu-devel] [PATCH 6/8] Revert "pci: prepare makefiles for pci code reorganization" Michael S. Tsirkin @ 2012-12-12 13:14 ` Michael S. Tsirkin 2012-12-12 19:49 ` Blue Swirl 2012-12-12 13:14 ` [Qemu-devel] [PATCH 7/8] pci: rename pci_internals.h pci_bus.h Michael S. Tsirkin ` (3 subsequent siblings) 9 siblings, 1 reply; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 13:14 UTC (permalink / raw) To: qemu-devel Include dependencies from pci core using <> and the correct path. Need to check whether they can be minimized, for now, at least make them explicit. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- hw/pci/msix.c | 4 ++-- hw/pci/pci-hotplug.c | 20 ++++++++++---------- hw/pci/pci.c | 16 ++++++++-------- hw/pci/pci.h | 10 +++++----- hw/pci/pci_host.h | 2 +- hw/pci/pcie.h | 2 +- hw/pci/pcie_aer.h | 2 +- hw/pci/pcie_host.c | 4 ++-- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/hw/pci/msix.c b/hw/pci/msix.c index 136ef09..ec35a5d 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -14,11 +14,11 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" +#include <hw/hw.h> #include "msi.h" #include "msix.h" #include "pci.h" -#include "range.h" +#include <range.h> #define MSIX_CAP_LENGTH 12 diff --git a/hw/pci/pci-hotplug.c b/hw/pci/pci-hotplug.c index 0ca5546..32ba449 100644 --- a/hw/pci/pci-hotplug.c +++ b/hw/pci/pci-hotplug.c @@ -22,17 +22,17 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "boards.h" +#include <hw/hw.h> +#include <hw/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" +#include <net.h> +#include <hw/pc.h> +#include <monitor.h> +#include <hw/scsi.h> +#include <hw/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, diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 97a0cd7..6023ded 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -21,19 +21,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include <hw/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 <monitor.h> +#include <net.h> +#include <sysemu.h> +#include <hw/loader.h> +#include <range.h> +#include <qmp-commands.h> #include "msi.h" #include "msix.h" -#include "exec-memory.h" +#include <exec-memory.h> //#define DEBUG_PCI #ifdef DEBUG_PCI diff --git a/hw/pci/pci.h b/hw/pci/pci.h index 4da0c2a..b517995 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -1,14 +1,14 @@ #ifndef QEMU_PCI_H #define QEMU_PCI_H -#include "qemu-common.h" +#include <qemu-common.h> -#include "qdev.h" -#include "memory.h" -#include "dma.h" +#include <hw/qdev.h> +#include <memory.h> +#include <dma.h> /* PCI includes legacy ISA access. */ -#include "isa.h" +#include <hw/isa.h> #include "pcie.h" diff --git a/hw/pci/pci_host.h b/hw/pci/pci_host.h index 4b9c300..6dfb38d 100644 --- a/hw/pci/pci_host.h +++ b/hw/pci/pci_host.h @@ -28,7 +28,7 @@ #ifndef PCI_HOST_H #define PCI_HOST_H -#include "sysbus.h" +#include <hw/sysbus.h> #define TYPE_PCI_HOST_BRIDGE "pci-host-bridge" #define PCI_HOST_BRIDGE(obj) \ diff --git a/hw/pci/pcie.h b/hw/pci/pcie.h index 4889194..cc1f2c5 100644 --- a/hw/pci/pcie.h +++ b/hw/pci/pcie.h @@ -21,7 +21,7 @@ #ifndef QEMU_PCIE_H #define QEMU_PCIE_H -#include "hw.h" +#include <hw/hw.h> #include "pci_regs.h" #include "pcie_regs.h" #include "pcie_aer.h" diff --git a/hw/pci/pcie_aer.h b/hw/pci/pcie_aer.h index 7539500..406a736 100644 --- a/hw/pci/pcie_aer.h +++ b/hw/pci/pcie_aer.h @@ -21,7 +21,7 @@ #ifndef QEMU_PCIE_AER_H #define QEMU_PCIE_AER_H -#include "hw.h" +#include <hw/hw.h> /* definitions which PCIExpressDevice uses */ diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c index c257fb4..4453cb0 100644 --- a/hw/pci/pcie_host.c +++ b/hw/pci/pcie_host.c @@ -19,10 +19,10 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "hw.h" +#include <hw/hw.h> #include "pci.h" #include "pcie_host.h" -#include "exec-memory.h" +#include <exec-memory.h> /* * PCI express mmcfig address -- MST ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 5/8] pci: make external dependencies explicit 2012-12-12 13:14 ` [Qemu-devel] [PATCH 5/8] pci: make external dependencies explicit Michael S. Tsirkin @ 2012-12-12 19:49 ` Blue Swirl 2012-12-12 20:53 ` Michael S. Tsirkin 0 siblings, 1 reply; 19+ messages in thread From: Blue Swirl @ 2012-12-12 19:49 UTC (permalink / raw) To: Michael S. Tsirkin; +Cc: qemu-devel On Wed, Dec 12, 2012 at 1:14 PM, Michael S. Tsirkin <mst@redhat.com> wrote: > Include dependencies from pci core using <> and Nack, the usual convention is to use <> for system headers like <stdio.h> and "" for local headers. For example with MSVC the search path for angle brackets does not even include the local directory: http://msdn.microsoft.com/en-us/library/36k2cdd4%28v=vs.80%29.aspx > the correct path. > Need to check whether they can be minimized, for now, > at least make them explicit. > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com> > --- > hw/pci/msix.c | 4 ++-- > hw/pci/pci-hotplug.c | 20 ++++++++++---------- > hw/pci/pci.c | 16 ++++++++-------- > hw/pci/pci.h | 10 +++++----- > hw/pci/pci_host.h | 2 +- > hw/pci/pcie.h | 2 +- > hw/pci/pcie_aer.h | 2 +- > hw/pci/pcie_host.c | 4 ++-- > 8 files changed, 30 insertions(+), 30 deletions(-) > > diff --git a/hw/pci/msix.c b/hw/pci/msix.c > index 136ef09..ec35a5d 100644 > --- a/hw/pci/msix.c > +++ b/hw/pci/msix.c > @@ -14,11 +14,11 @@ > * GNU GPL, version 2 or (at your option) any later version. > */ > > -#include "hw.h" > +#include <hw/hw.h> > #include "msi.h" > #include "msix.h" > #include "pci.h" > -#include "range.h" > +#include <range.h> > > #define MSIX_CAP_LENGTH 12 > > diff --git a/hw/pci/pci-hotplug.c b/hw/pci/pci-hotplug.c > index 0ca5546..32ba449 100644 > --- a/hw/pci/pci-hotplug.c > +++ b/hw/pci/pci-hotplug.c > @@ -22,17 +22,17 @@ > * THE SOFTWARE. > */ > > -#include "hw.h" > -#include "boards.h" > +#include <hw/hw.h> > +#include <hw/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" > +#include <net.h> > +#include <hw/pc.h> > +#include <monitor.h> > +#include <hw/scsi.h> > +#include <hw/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, > diff --git a/hw/pci/pci.c b/hw/pci/pci.c > index 97a0cd7..6023ded 100644 > --- a/hw/pci/pci.c > +++ b/hw/pci/pci.c > @@ -21,19 +21,19 @@ > * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > * THE SOFTWARE. > */ > -#include "hw.h" > +#include <hw/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 <monitor.h> > +#include <net.h> > +#include <sysemu.h> > +#include <hw/loader.h> > +#include <range.h> > +#include <qmp-commands.h> > #include "msi.h" > #include "msix.h" > -#include "exec-memory.h" > +#include <exec-memory.h> > > //#define DEBUG_PCI > #ifdef DEBUG_PCI > diff --git a/hw/pci/pci.h b/hw/pci/pci.h > index 4da0c2a..b517995 100644 > --- a/hw/pci/pci.h > +++ b/hw/pci/pci.h > @@ -1,14 +1,14 @@ > #ifndef QEMU_PCI_H > #define QEMU_PCI_H > > -#include "qemu-common.h" > +#include <qemu-common.h> > > -#include "qdev.h" > -#include "memory.h" > -#include "dma.h" > +#include <hw/qdev.h> > +#include <memory.h> > +#include <dma.h> > > /* PCI includes legacy ISA access. */ > -#include "isa.h" > +#include <hw/isa.h> > > #include "pcie.h" > > diff --git a/hw/pci/pci_host.h b/hw/pci/pci_host.h > index 4b9c300..6dfb38d 100644 > --- a/hw/pci/pci_host.h > +++ b/hw/pci/pci_host.h > @@ -28,7 +28,7 @@ > #ifndef PCI_HOST_H > #define PCI_HOST_H > > -#include "sysbus.h" > +#include <hw/sysbus.h> > > #define TYPE_PCI_HOST_BRIDGE "pci-host-bridge" > #define PCI_HOST_BRIDGE(obj) \ > diff --git a/hw/pci/pcie.h b/hw/pci/pcie.h > index 4889194..cc1f2c5 100644 > --- a/hw/pci/pcie.h > +++ b/hw/pci/pcie.h > @@ -21,7 +21,7 @@ > #ifndef QEMU_PCIE_H > #define QEMU_PCIE_H > > -#include "hw.h" > +#include <hw/hw.h> > #include "pci_regs.h" > #include "pcie_regs.h" > #include "pcie_aer.h" > diff --git a/hw/pci/pcie_aer.h b/hw/pci/pcie_aer.h > index 7539500..406a736 100644 > --- a/hw/pci/pcie_aer.h > +++ b/hw/pci/pcie_aer.h > @@ -21,7 +21,7 @@ > #ifndef QEMU_PCIE_AER_H > #define QEMU_PCIE_AER_H > > -#include "hw.h" > +#include <hw/hw.h> > > /* definitions which PCIExpressDevice uses */ > > diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c > index c257fb4..4453cb0 100644 > --- a/hw/pci/pcie_host.c > +++ b/hw/pci/pcie_host.c > @@ -19,10 +19,10 @@ > * with this program; if not, see <http://www.gnu.org/licenses/>. > */ > > -#include "hw.h" > +#include <hw/hw.h> > #include "pci.h" > #include "pcie_host.h" > -#include "exec-memory.h" > +#include <exec-memory.h> > > /* > * PCI express mmcfig address > -- > MST > > ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 5/8] pci: make external dependencies explicit 2012-12-12 19:49 ` Blue Swirl @ 2012-12-12 20:53 ` Michael S. Tsirkin 0 siblings, 0 replies; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 20:53 UTC (permalink / raw) To: Blue Swirl; +Cc: qemu-devel On Wed, Dec 12, 2012 at 07:49:35PM +0000, Blue Swirl wrote: > On Wed, Dec 12, 2012 at 1:14 PM, Michael S. Tsirkin <mst@redhat.com> wrote: > > Include dependencies from pci core using <> and > > Nack, the usual convention is to use <> for system headers like > <stdio.h> and "" for local headers. > > For example with MSVC the search path for angle brackets does not even > include the local directory: > http://msdn.microsoft.com/en-us/library/36k2cdd4%28v=vs.80%29.aspx This convention is non standard: When hw/pci/pci.h includes hw/hw.h the lookup that succeeds is not from the current directory - it's from the -I search path. So "" simply slows the preprocessor down and increases chances of picking the wrong header, for no real benefit. Oh well another qemu coding style eccentricity. I'll change them to "". > > the correct path. > > Need to check whether they can be minimized, for now, > > at least make them explicit. > > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com> > > --- > > hw/pci/msix.c | 4 ++-- > > hw/pci/pci-hotplug.c | 20 ++++++++++---------- > > hw/pci/pci.c | 16 ++++++++-------- > > hw/pci/pci.h | 10 +++++----- > > hw/pci/pci_host.h | 2 +- > > hw/pci/pcie.h | 2 +- > > hw/pci/pcie_aer.h | 2 +- > > hw/pci/pcie_host.c | 4 ++-- > > 8 files changed, 30 insertions(+), 30 deletions(-) > > > > diff --git a/hw/pci/msix.c b/hw/pci/msix.c > > index 136ef09..ec35a5d 100644 > > --- a/hw/pci/msix.c > > +++ b/hw/pci/msix.c > > @@ -14,11 +14,11 @@ > > * GNU GPL, version 2 or (at your option) any later version. > > */ > > > > -#include "hw.h" > > +#include <hw/hw.h> > > #include "msi.h" > > #include "msix.h" > > #include "pci.h" > > -#include "range.h" > > +#include <range.h> > > > > #define MSIX_CAP_LENGTH 12 > > > > diff --git a/hw/pci/pci-hotplug.c b/hw/pci/pci-hotplug.c > > index 0ca5546..32ba449 100644 > > --- a/hw/pci/pci-hotplug.c > > +++ b/hw/pci/pci-hotplug.c > > @@ -22,17 +22,17 @@ > > * THE SOFTWARE. > > */ > > > > -#include "hw.h" > > -#include "boards.h" > > +#include <hw/hw.h> > > +#include <hw/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" > > +#include <net.h> > > +#include <hw/pc.h> > > +#include <monitor.h> > > +#include <hw/scsi.h> > > +#include <hw/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, > > diff --git a/hw/pci/pci.c b/hw/pci/pci.c > > index 97a0cd7..6023ded 100644 > > --- a/hw/pci/pci.c > > +++ b/hw/pci/pci.c > > @@ -21,19 +21,19 @@ > > * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > > * THE SOFTWARE. > > */ > > -#include "hw.h" > > +#include <hw/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 <monitor.h> > > +#include <net.h> > > +#include <sysemu.h> > > +#include <hw/loader.h> > > +#include <range.h> > > +#include <qmp-commands.h> > > #include "msi.h" > > #include "msix.h" > > -#include "exec-memory.h" > > +#include <exec-memory.h> > > > > //#define DEBUG_PCI > > #ifdef DEBUG_PCI > > diff --git a/hw/pci/pci.h b/hw/pci/pci.h > > index 4da0c2a..b517995 100644 > > --- a/hw/pci/pci.h > > +++ b/hw/pci/pci.h > > @@ -1,14 +1,14 @@ > > #ifndef QEMU_PCI_H > > #define QEMU_PCI_H > > > > -#include "qemu-common.h" > > +#include <qemu-common.h> > > > > -#include "qdev.h" > > -#include "memory.h" > > -#include "dma.h" > > +#include <hw/qdev.h> > > +#include <memory.h> > > +#include <dma.h> > > > > /* PCI includes legacy ISA access. */ > > -#include "isa.h" > > +#include <hw/isa.h> > > > > #include "pcie.h" > > > > diff --git a/hw/pci/pci_host.h b/hw/pci/pci_host.h > > index 4b9c300..6dfb38d 100644 > > --- a/hw/pci/pci_host.h > > +++ b/hw/pci/pci_host.h > > @@ -28,7 +28,7 @@ > > #ifndef PCI_HOST_H > > #define PCI_HOST_H > > > > -#include "sysbus.h" > > +#include <hw/sysbus.h> > > > > #define TYPE_PCI_HOST_BRIDGE "pci-host-bridge" > > #define PCI_HOST_BRIDGE(obj) \ > > diff --git a/hw/pci/pcie.h b/hw/pci/pcie.h > > index 4889194..cc1f2c5 100644 > > --- a/hw/pci/pcie.h > > +++ b/hw/pci/pcie.h > > @@ -21,7 +21,7 @@ > > #ifndef QEMU_PCIE_H > > #define QEMU_PCIE_H > > > > -#include "hw.h" > > +#include <hw/hw.h> > > #include "pci_regs.h" > > #include "pcie_regs.h" > > #include "pcie_aer.h" > > diff --git a/hw/pci/pcie_aer.h b/hw/pci/pcie_aer.h > > index 7539500..406a736 100644 > > --- a/hw/pci/pcie_aer.h > > +++ b/hw/pci/pcie_aer.h > > @@ -21,7 +21,7 @@ > > #ifndef QEMU_PCIE_AER_H > > #define QEMU_PCIE_AER_H > > > > -#include "hw.h" > > +#include <hw/hw.h> > > > > /* definitions which PCIExpressDevice uses */ > > > > diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c > > index c257fb4..4453cb0 100644 > > --- a/hw/pci/pcie_host.c > > +++ b/hw/pci/pcie_host.c > > @@ -19,10 +19,10 @@ > > * with this program; if not, see <http://www.gnu.org/licenses/>. > > */ > > > > -#include "hw.h" > > +#include <hw/hw.h> > > #include "pci.h" > > #include "pcie_host.h" > > -#include "exec-memory.h" > > +#include <exec-memory.h> > > > > /* > > * PCI express mmcfig address > > -- > > MST > > > > ^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 7/8] pci: rename pci_internals.h pci_bus.h 2012-12-12 13:13 [Qemu-devel] [PATCH 0/8] pci core reorg Michael S. Tsirkin ` (5 preceding siblings ...) 2012-12-12 13:14 ` [Qemu-devel] [PATCH 5/8] pci: make external dependencies explicit Michael S. Tsirkin @ 2012-12-12 13:14 ` Michael S. Tsirkin 2012-12-12 19:56 ` Blue Swirl 2012-12-12 13:14 ` [Qemu-devel] [PATCH 8/8] pci_bus: update comment Michael S. Tsirkin ` (2 subsequent siblings) 9 siblings, 1 reply; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 13:14 UTC (permalink / raw) To: qemu-devel There are lots of external users of pci_internals.h, apparently making it an internal interface only didn't work out. Let's stop pretending it's an internal header. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- hw/apb_pci.c | 2 +- hw/dec_pci.c | 2 +- hw/ich9.h | 2 +- hw/lpc_ich9.c | 2 +- hw/pci/pci.c | 2 +- hw/pci/pci_bridge.c | 2 +- hw/pci/pci_bus.h | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pci/pci_internals.h | 78 -------------------------------------------------- hw/pci/pcie.c | 2 +- hw/pci/pcie_aer.c | 2 +- hw/pci/pcie_port.h | 2 +- hw/pci/shpc.c | 2 +- hw/pci_bridge_dev.c | 2 +- hw/spapr_pci.c | 2 +- 14 files changed, 90 insertions(+), 90 deletions(-) create mode 100644 hw/pci/pci_bus.h delete mode 100644 hw/pci/pci_internals.h diff --git a/hw/apb_pci.c b/hw/apb_pci.c index de594f8..fb7a07d 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -30,7 +30,7 @@ #include "pci/pci.h" #include "pci/pci_host.h" #include "pci/pci_bridge.h" -#include "pci/pci_internals.h" +#include "pci/pci_bus.h" #include "apb_pci.h" #include "sysemu.h" #include "exec-memory.h" diff --git a/hw/dec_pci.c b/hw/dec_pci.c index a6a7c84..ee3f4ca 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -28,7 +28,7 @@ #include "pci/pci.h" #include "pci/pci_host.h" #include "pci/pci_bridge.h" -#include "pci/pci_internals.h" +#include "pci/pci_bus.h" /* debug DEC */ //#define DEBUG_DEC diff --git a/hw/ich9.h b/hw/ich9.h index 247be94..4e7442c 100644 --- a/hw/ich9.h +++ b/hw/ich9.h @@ -14,7 +14,7 @@ #include "acpi.h" #include "acpi_ich9.h" #include "pam.h" -#include "pci/pci_internals.h" +#include "pci/pci_bus.h" void ich9_lpc_set_irq(void *opaque, int irq_num, int level); int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx); diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c index 23dee88..7bca061 100644 --- a/hw/lpc_ich9.c +++ b/hw/lpc_ich9.c @@ -42,7 +42,7 @@ #include "acpi.h" #include "acpi_ich9.h" #include "pam.h" -#include "pci/pci_internals.h" +#include "pci/pci_bus.h" #include "exec-memory.h" static int ich9_lpc_sci_irq(ICH9LPCState *lpc); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 6023ded..c1a4b32 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -24,7 +24,7 @@ #include <hw/hw.h> #include "pci.h" #include "pci_bridge.h" -#include "pci_internals.h" +#include "pci_bus.h" #include <monitor.h> #include <net.h> #include <sysemu.h> diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 4680501..0fb7577 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -30,7 +30,7 @@ */ #include "pci_bridge.h" -#include "pci_internals.h" +#include "pci_bus.h" #include "range.h" /* PCI bridge subsystem vendor ID helper functions */ diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h new file mode 100644 index 0000000..21d0ce6 --- /dev/null +++ b/hw/pci/pci_bus.h @@ -0,0 +1,78 @@ +#ifndef QEMU_PCI_INTERNALS_H +#define QEMU_PCI_INTERNALS_H + +/* + * This header files is private to pci.c and pci_bridge.c + * So following structures are opaque to others and shouldn't be + * accessed. + * + * For pci-to-pci bridge needs to include this header file to embed + * PCIBridge in its structure or to get sizeof(PCIBridge), + * However, they shouldn't access those following members directly. + * Use accessor function in pci.h, pci_bridge.h + */ + +#define TYPE_PCI_BUS "PCI" +#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) + +struct PCIBus { + BusState qbus; + PCIDMAContextFunc dma_context_fn; + void *dma_context_opaque; + uint8_t devfn_min; + pci_set_irq_fn set_irq; + pci_map_irq_fn map_irq; + pci_route_irq_fn route_intx_to_irq; + pci_hotplug_fn hotplug; + DeviceState *hotplug_qdev; + void *irq_opaque; + PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; + PCIDevice *parent_dev; + MemoryRegion *address_space_mem; + MemoryRegion *address_space_io; + + QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ + QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ + + /* The bus IRQ state is the logical OR of the connected devices. + Keep a count of the number of devices with raised IRQs. */ + int nirq; + int *irq_count; +}; + +typedef struct PCIBridgeWindows PCIBridgeWindows; + +/* + * Aliases for each of the address space windows that the bridge + * can forward. Mapped into the bridge's parent's address space, + * as subregions. + */ +struct PCIBridgeWindows { + MemoryRegion alias_pref_mem; + MemoryRegion alias_mem; + MemoryRegion alias_io; +}; + +struct PCIBridge { + PCIDevice dev; + + /* private member */ + PCIBus sec_bus; + /* + * Memory regions for the bridge's address spaces. These regions are not + * directly added to system_memory/system_io or its descendants. + * Bridge's secondary bus points to these, so that devices + * under the bridge see these regions as its address spaces. + * The regions are as large as the entire address space - + * they don't take into account any windows. + */ + MemoryRegion address_space_mem; + MemoryRegion address_space_io; + + PCIBridgeWindows *windows; + + pci_map_irq_fn map_irq; + const char *bus_name; +}; + +#endif /* QEMU_PCI_INTERNALS_H */ diff --git a/hw/pci/pci_internals.h b/hw/pci/pci_internals.h deleted file mode 100644 index 21d0ce6..0000000 --- a/hw/pci/pci_internals.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef QEMU_PCI_INTERNALS_H -#define QEMU_PCI_INTERNALS_H - -/* - * This header files is private to pci.c and pci_bridge.c - * So following structures are opaque to others and shouldn't be - * accessed. - * - * For pci-to-pci bridge needs to include this header file to embed - * PCIBridge in its structure or to get sizeof(PCIBridge), - * However, they shouldn't access those following members directly. - * Use accessor function in pci.h, pci_bridge.h - */ - -#define TYPE_PCI_BUS "PCI" -#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) - -struct PCIBus { - BusState qbus; - PCIDMAContextFunc dma_context_fn; - void *dma_context_opaque; - uint8_t devfn_min; - pci_set_irq_fn set_irq; - pci_map_irq_fn map_irq; - pci_route_irq_fn route_intx_to_irq; - pci_hotplug_fn hotplug; - DeviceState *hotplug_qdev; - void *irq_opaque; - PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; - PCIDevice *parent_dev; - MemoryRegion *address_space_mem; - MemoryRegion *address_space_io; - - QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ - QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ - - /* The bus IRQ state is the logical OR of the connected devices. - Keep a count of the number of devices with raised IRQs. */ - int nirq; - int *irq_count; -}; - -typedef struct PCIBridgeWindows PCIBridgeWindows; - -/* - * Aliases for each of the address space windows that the bridge - * can forward. Mapped into the bridge's parent's address space, - * as subregions. - */ -struct PCIBridgeWindows { - MemoryRegion alias_pref_mem; - MemoryRegion alias_mem; - MemoryRegion alias_io; -}; - -struct PCIBridge { - PCIDevice dev; - - /* private member */ - PCIBus sec_bus; - /* - * Memory regions for the bridge's address spaces. These regions are not - * directly added to system_memory/system_io or its descendants. - * Bridge's secondary bus points to these, so that devices - * under the bridge see these regions as its address spaces. - * The regions are as large as the entire address space - - * they don't take into account any windows. - */ - MemoryRegion address_space_mem; - MemoryRegion address_space_io; - - PCIBridgeWindows *windows; - - pci_map_irq_fn map_irq; - const char *bus_name; -}; - -#endif /* QEMU_PCI_INTERNALS_H */ diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 7c92f19..d9c38b5 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -23,7 +23,7 @@ #include "pcie.h" #include "msix.h" #include "msi.h" -#include "pci_internals.h" +#include "pci_bus.h" #include "pcie_regs.h" #include "range.h" diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index b04c164..3c3185c 100644 --- a/hw/pci/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -25,7 +25,7 @@ #include "pcie.h" #include "msix.h" #include "msi.h" -#include "pci_internals.h" +#include "pci_bus.h" #include "pcie_regs.h" //#define DEBUG_PCIE diff --git a/hw/pci/pcie_port.h b/hw/pci/pcie_port.h index 3709583..36b2241 100644 --- a/hw/pci/pcie_port.h +++ b/hw/pci/pcie_port.h @@ -22,7 +22,7 @@ #define QEMU_PCIE_PORT_H #include "pci_bridge.h" -#include "pci_internals.h" +#include "pci_bus.h" struct PCIEPort { PCIBridge br; diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index 4597bbd..9297af0 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -4,7 +4,7 @@ #include "range.h" #include "shpc.h" #include "pci.h" -#include "pci_internals.h" +#include "pci_bus.h" #include "msi.h" /* TODO: model power only and disabled slot states. */ diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index 5c9fc50..dbb4b3b 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -25,7 +25,7 @@ #include "pci/shpc.h" #include "pci/slotid_cap.h" #include "memory.h" -#include "pci/pci_internals.h" +#include "pci/pci_bus.h" #define REDHAT_PCI_VENDOR_ID 0x1b36 #define PCI_BRIDGE_DEV_VENDOR_ID REDHAT_PCI_VENDOR_ID diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index e123866..6b05e5b 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -33,7 +33,7 @@ #include <libfdt.h> #include "trace.h" -#include "hw/pci/pci_internals.h" +#include "hw/pci/pci_bus.h" /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */ #define RTAS_QUERY_FN 0 -- MST ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 7/8] pci: rename pci_internals.h pci_bus.h 2012-12-12 13:14 ` [Qemu-devel] [PATCH 7/8] pci: rename pci_internals.h pci_bus.h Michael S. Tsirkin @ 2012-12-12 19:56 ` Blue Swirl 2012-12-12 20:59 ` Michael S. Tsirkin 0 siblings, 1 reply; 19+ messages in thread From: Blue Swirl @ 2012-12-12 19:56 UTC (permalink / raw) To: Michael S. Tsirkin; +Cc: qemu-devel On Wed, Dec 12, 2012 at 1:14 PM, Michael S. Tsirkin <mst@redhat.com> wrote: > There are lots of external users of pci_internals.h, > apparently making it an internal interface only didn't > work out. Let's stop pretending it's an internal header. > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com> > --- > hw/apb_pci.c | 2 +- > hw/dec_pci.c | 2 +- > hw/ich9.h | 2 +- > hw/lpc_ich9.c | 2 +- > hw/pci/pci.c | 2 +- > hw/pci/pci_bridge.c | 2 +- > hw/pci/pci_bus.h | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/pci/pci_internals.h | 78 -------------------------------------------------- > hw/pci/pcie.c | 2 +- > hw/pci/pcie_aer.c | 2 +- > hw/pci/pcie_port.h | 2 +- > hw/pci/shpc.c | 2 +- > hw/pci_bridge_dev.c | 2 +- > hw/spapr_pci.c | 2 +- > 14 files changed, 90 insertions(+), 90 deletions(-) > create mode 100644 hw/pci/pci_bus.h > delete mode 100644 hw/pci/pci_internals.h > > diff --git a/hw/apb_pci.c b/hw/apb_pci.c > index de594f8..fb7a07d 100644 > --- a/hw/apb_pci.c > +++ b/hw/apb_pci.c > @@ -30,7 +30,7 @@ > #include "pci/pci.h" > #include "pci/pci_host.h" > #include "pci/pci_bridge.h" > -#include "pci/pci_internals.h" > +#include "pci/pci_bus.h" > #include "apb_pci.h" > #include "sysemu.h" > #include "exec-memory.h" > diff --git a/hw/dec_pci.c b/hw/dec_pci.c > index a6a7c84..ee3f4ca 100644 > --- a/hw/dec_pci.c > +++ b/hw/dec_pci.c > @@ -28,7 +28,7 @@ > #include "pci/pci.h" > #include "pci/pci_host.h" > #include "pci/pci_bridge.h" > -#include "pci/pci_internals.h" > +#include "pci/pci_bus.h" > > /* debug DEC */ > //#define DEBUG_DEC > diff --git a/hw/ich9.h b/hw/ich9.h > index 247be94..4e7442c 100644 > --- a/hw/ich9.h > +++ b/hw/ich9.h > @@ -14,7 +14,7 @@ > #include "acpi.h" > #include "acpi_ich9.h" > #include "pam.h" > -#include "pci/pci_internals.h" > +#include "pci/pci_bus.h" > > void ich9_lpc_set_irq(void *opaque, int irq_num, int level); > int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx); > diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c > index 23dee88..7bca061 100644 > --- a/hw/lpc_ich9.c > +++ b/hw/lpc_ich9.c > @@ -42,7 +42,7 @@ > #include "acpi.h" > #include "acpi_ich9.h" > #include "pam.h" > -#include "pci/pci_internals.h" > +#include "pci/pci_bus.h" > #include "exec-memory.h" > > static int ich9_lpc_sci_irq(ICH9LPCState *lpc); > diff --git a/hw/pci/pci.c b/hw/pci/pci.c > index 6023ded..c1a4b32 100644 > --- a/hw/pci/pci.c > +++ b/hw/pci/pci.c > @@ -24,7 +24,7 @@ > #include <hw/hw.h> > #include "pci.h" > #include "pci_bridge.h" > -#include "pci_internals.h" > +#include "pci_bus.h" > #include <monitor.h> > #include <net.h> > #include <sysemu.h> > diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c > index 4680501..0fb7577 100644 > --- a/hw/pci/pci_bridge.c > +++ b/hw/pci/pci_bridge.c > @@ -30,7 +30,7 @@ > */ > > #include "pci_bridge.h" > -#include "pci_internals.h" > +#include "pci_bus.h" > #include "range.h" > > /* PCI bridge subsystem vendor ID helper functions */ > diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h > new file mode 100644 > index 0000000..21d0ce6 > --- /dev/null > +++ b/hw/pci/pci_bus.h > @@ -0,0 +1,78 @@ > +#ifndef QEMU_PCI_INTERNALS_H > +#define QEMU_PCI_INTERNALS_H This should become QEMU_PCI_BUS_H or something similar. > + > +/* > + * This header files is private to pci.c and pci_bridge.c > + * So following structures are opaque to others and shouldn't be > + * accessed. > + * > + * For pci-to-pci bridge needs to include this header file to embed > + * PCIBridge in its structure or to get sizeof(PCIBridge), > + * However, they shouldn't access those following members directly. > + * Use accessor function in pci.h, pci_bridge.h > + */ > + > +#define TYPE_PCI_BUS "PCI" > +#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) > + > +struct PCIBus { > + BusState qbus; > + PCIDMAContextFunc dma_context_fn; > + void *dma_context_opaque; > + uint8_t devfn_min; > + pci_set_irq_fn set_irq; > + pci_map_irq_fn map_irq; > + pci_route_irq_fn route_intx_to_irq; > + pci_hotplug_fn hotplug; > + DeviceState *hotplug_qdev; > + void *irq_opaque; > + PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; > + PCIDevice *parent_dev; > + MemoryRegion *address_space_mem; > + MemoryRegion *address_space_io; > + > + QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ > + QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ > + > + /* The bus IRQ state is the logical OR of the connected devices. > + Keep a count of the number of devices with raised IRQs. */ > + int nirq; > + int *irq_count; > +}; > + > +typedef struct PCIBridgeWindows PCIBridgeWindows; > + > +/* > + * Aliases for each of the address space windows that the bridge > + * can forward. Mapped into the bridge's parent's address space, > + * as subregions. > + */ > +struct PCIBridgeWindows { > + MemoryRegion alias_pref_mem; > + MemoryRegion alias_mem; > + MemoryRegion alias_io; > +}; > + > +struct PCIBridge { > + PCIDevice dev; > + > + /* private member */ > + PCIBus sec_bus; > + /* > + * Memory regions for the bridge's address spaces. These regions are not > + * directly added to system_memory/system_io or its descendants. > + * Bridge's secondary bus points to these, so that devices > + * under the bridge see these regions as its address spaces. > + * The regions are as large as the entire address space - > + * they don't take into account any windows. > + */ > + MemoryRegion address_space_mem; > + MemoryRegion address_space_io; > + > + PCIBridgeWindows *windows; > + > + pci_map_irq_fn map_irq; > + const char *bus_name; > +}; > + > +#endif /* QEMU_PCI_INTERNALS_H */ > diff --git a/hw/pci/pci_internals.h b/hw/pci/pci_internals.h > deleted file mode 100644 > index 21d0ce6..0000000 > --- a/hw/pci/pci_internals.h > +++ /dev/null > @@ -1,78 +0,0 @@ > -#ifndef QEMU_PCI_INTERNALS_H > -#define QEMU_PCI_INTERNALS_H > - > -/* > - * This header files is private to pci.c and pci_bridge.c > - * So following structures are opaque to others and shouldn't be > - * accessed. > - * > - * For pci-to-pci bridge needs to include this header file to embed > - * PCIBridge in its structure or to get sizeof(PCIBridge), > - * However, they shouldn't access those following members directly. > - * Use accessor function in pci.h, pci_bridge.h > - */ > - > -#define TYPE_PCI_BUS "PCI" > -#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) > - > -struct PCIBus { > - BusState qbus; > - PCIDMAContextFunc dma_context_fn; > - void *dma_context_opaque; > - uint8_t devfn_min; > - pci_set_irq_fn set_irq; > - pci_map_irq_fn map_irq; > - pci_route_irq_fn route_intx_to_irq; > - pci_hotplug_fn hotplug; > - DeviceState *hotplug_qdev; > - void *irq_opaque; > - PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; > - PCIDevice *parent_dev; > - MemoryRegion *address_space_mem; > - MemoryRegion *address_space_io; > - > - QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ > - QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ > - > - /* The bus IRQ state is the logical OR of the connected devices. > - Keep a count of the number of devices with raised IRQs. */ > - int nirq; > - int *irq_count; > -}; > - > -typedef struct PCIBridgeWindows PCIBridgeWindows; > - > -/* > - * Aliases for each of the address space windows that the bridge > - * can forward. Mapped into the bridge's parent's address space, > - * as subregions. > - */ > -struct PCIBridgeWindows { > - MemoryRegion alias_pref_mem; > - MemoryRegion alias_mem; > - MemoryRegion alias_io; > -}; > - > -struct PCIBridge { > - PCIDevice dev; > - > - /* private member */ > - PCIBus sec_bus; > - /* > - * Memory regions for the bridge's address spaces. These regions are not > - * directly added to system_memory/system_io or its descendants. > - * Bridge's secondary bus points to these, so that devices > - * under the bridge see these regions as its address spaces. > - * The regions are as large as the entire address space - > - * they don't take into account any windows. > - */ > - MemoryRegion address_space_mem; > - MemoryRegion address_space_io; > - > - PCIBridgeWindows *windows; > - > - pci_map_irq_fn map_irq; > - const char *bus_name; > -}; > - > -#endif /* QEMU_PCI_INTERNALS_H */ > diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c > index 7c92f19..d9c38b5 100644 > --- a/hw/pci/pcie.c > +++ b/hw/pci/pcie.c > @@ -23,7 +23,7 @@ > #include "pcie.h" > #include "msix.h" > #include "msi.h" > -#include "pci_internals.h" > +#include "pci_bus.h" > #include "pcie_regs.h" > #include "range.h" > > diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c > index b04c164..3c3185c 100644 > --- a/hw/pci/pcie_aer.c > +++ b/hw/pci/pcie_aer.c > @@ -25,7 +25,7 @@ > #include "pcie.h" > #include "msix.h" > #include "msi.h" > -#include "pci_internals.h" > +#include "pci_bus.h" > #include "pcie_regs.h" > > //#define DEBUG_PCIE > diff --git a/hw/pci/pcie_port.h b/hw/pci/pcie_port.h > index 3709583..36b2241 100644 > --- a/hw/pci/pcie_port.h > +++ b/hw/pci/pcie_port.h > @@ -22,7 +22,7 @@ > #define QEMU_PCIE_PORT_H > > #include "pci_bridge.h" > -#include "pci_internals.h" > +#include "pci_bus.h" > > struct PCIEPort { > PCIBridge br; > diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c > index 4597bbd..9297af0 100644 > --- a/hw/pci/shpc.c > +++ b/hw/pci/shpc.c > @@ -4,7 +4,7 @@ > #include "range.h" > #include "shpc.h" > #include "pci.h" > -#include "pci_internals.h" > +#include "pci_bus.h" > #include "msi.h" > > /* TODO: model power only and disabled slot states. */ > diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c > index 5c9fc50..dbb4b3b 100644 > --- a/hw/pci_bridge_dev.c > +++ b/hw/pci_bridge_dev.c > @@ -25,7 +25,7 @@ > #include "pci/shpc.h" > #include "pci/slotid_cap.h" > #include "memory.h" > -#include "pci/pci_internals.h" > +#include "pci/pci_bus.h" > > #define REDHAT_PCI_VENDOR_ID 0x1b36 > #define PCI_BRIDGE_DEV_VENDOR_ID REDHAT_PCI_VENDOR_ID > diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c > index e123866..6b05e5b 100644 > --- a/hw/spapr_pci.c > +++ b/hw/spapr_pci.c > @@ -33,7 +33,7 @@ > #include <libfdt.h> > #include "trace.h" > > -#include "hw/pci/pci_internals.h" > +#include "hw/pci/pci_bus.h" > > /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */ > #define RTAS_QUERY_FN 0 > -- > MST > > ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 7/8] pci: rename pci_internals.h pci_bus.h 2012-12-12 19:56 ` Blue Swirl @ 2012-12-12 20:59 ` Michael S. Tsirkin 0 siblings, 0 replies; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 20:59 UTC (permalink / raw) To: Blue Swirl; +Cc: qemu-devel On Wed, Dec 12, 2012 at 07:56:50PM +0000, Blue Swirl wrote: > On Wed, Dec 12, 2012 at 1:14 PM, Michael S. Tsirkin <mst@redhat.com> wrote: > > There are lots of external users of pci_internals.h, > > apparently making it an internal interface only didn't > > work out. Let's stop pretending it's an internal header. > > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com> > > --- > > hw/apb_pci.c | 2 +- > > hw/dec_pci.c | 2 +- > > hw/ich9.h | 2 +- > > hw/lpc_ich9.c | 2 +- > > hw/pci/pci.c | 2 +- > > hw/pci/pci_bridge.c | 2 +- > > hw/pci/pci_bus.h | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ > > hw/pci/pci_internals.h | 78 -------------------------------------------------- > > hw/pci/pcie.c | 2 +- > > hw/pci/pcie_aer.c | 2 +- > > hw/pci/pcie_port.h | 2 +- > > hw/pci/shpc.c | 2 +- > > hw/pci_bridge_dev.c | 2 +- > > hw/spapr_pci.c | 2 +- > > 14 files changed, 90 insertions(+), 90 deletions(-) > > create mode 100644 hw/pci/pci_bus.h > > delete mode 100644 hw/pci/pci_internals.h > > > > diff --git a/hw/apb_pci.c b/hw/apb_pci.c > > index de594f8..fb7a07d 100644 > > --- a/hw/apb_pci.c > > +++ b/hw/apb_pci.c > > @@ -30,7 +30,7 @@ > > #include "pci/pci.h" > > #include "pci/pci_host.h" > > #include "pci/pci_bridge.h" > > -#include "pci/pci_internals.h" > > +#include "pci/pci_bus.h" > > #include "apb_pci.h" > > #include "sysemu.h" > > #include "exec-memory.h" > > diff --git a/hw/dec_pci.c b/hw/dec_pci.c > > index a6a7c84..ee3f4ca 100644 > > --- a/hw/dec_pci.c > > +++ b/hw/dec_pci.c > > @@ -28,7 +28,7 @@ > > #include "pci/pci.h" > > #include "pci/pci_host.h" > > #include "pci/pci_bridge.h" > > -#include "pci/pci_internals.h" > > +#include "pci/pci_bus.h" > > > > /* debug DEC */ > > //#define DEBUG_DEC > > diff --git a/hw/ich9.h b/hw/ich9.h > > index 247be94..4e7442c 100644 > > --- a/hw/ich9.h > > +++ b/hw/ich9.h > > @@ -14,7 +14,7 @@ > > #include "acpi.h" > > #include "acpi_ich9.h" > > #include "pam.h" > > -#include "pci/pci_internals.h" > > +#include "pci/pci_bus.h" > > > > void ich9_lpc_set_irq(void *opaque, int irq_num, int level); > > int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx); > > diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c > > index 23dee88..7bca061 100644 > > --- a/hw/lpc_ich9.c > > +++ b/hw/lpc_ich9.c > > @@ -42,7 +42,7 @@ > > #include "acpi.h" > > #include "acpi_ich9.h" > > #include "pam.h" > > -#include "pci/pci_internals.h" > > +#include "pci/pci_bus.h" > > #include "exec-memory.h" > > > > static int ich9_lpc_sci_irq(ICH9LPCState *lpc); > > diff --git a/hw/pci/pci.c b/hw/pci/pci.c > > index 6023ded..c1a4b32 100644 > > --- a/hw/pci/pci.c > > +++ b/hw/pci/pci.c > > @@ -24,7 +24,7 @@ > > #include <hw/hw.h> > > #include "pci.h" > > #include "pci_bridge.h" > > -#include "pci_internals.h" > > +#include "pci_bus.h" > > #include <monitor.h> > > #include <net.h> > > #include <sysemu.h> > > diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c > > index 4680501..0fb7577 100644 > > --- a/hw/pci/pci_bridge.c > > +++ b/hw/pci/pci_bridge.c > > @@ -30,7 +30,7 @@ > > */ > > > > #include "pci_bridge.h" > > -#include "pci_internals.h" > > +#include "pci_bus.h" > > #include "range.h" > > > > /* PCI bridge subsystem vendor ID helper functions */ > > diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h > > new file mode 100644 > > index 0000000..21d0ce6 > > --- /dev/null > > +++ b/hw/pci/pci_bus.h > > @@ -0,0 +1,78 @@ > > +#ifndef QEMU_PCI_INTERNALS_H > > +#define QEMU_PCI_INTERNALS_H > > This should become QEMU_PCI_BUS_H or something similar. Good catch, thanks! Will fix in a separate patch though - rename detection works better if file is moved without changes. > > + > > +/* > > + * This header files is private to pci.c and pci_bridge.c > > + * So following structures are opaque to others and shouldn't be > > + * accessed. > > + * > > + * For pci-to-pci bridge needs to include this header file to embed > > + * PCIBridge in its structure or to get sizeof(PCIBridge), > > + * However, they shouldn't access those following members directly. > > + * Use accessor function in pci.h, pci_bridge.h > > + */ > > + > > +#define TYPE_PCI_BUS "PCI" > > +#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) > > + > > +struct PCIBus { > > + BusState qbus; > > + PCIDMAContextFunc dma_context_fn; > > + void *dma_context_opaque; > > + uint8_t devfn_min; > > + pci_set_irq_fn set_irq; > > + pci_map_irq_fn map_irq; > > + pci_route_irq_fn route_intx_to_irq; > > + pci_hotplug_fn hotplug; > > + DeviceState *hotplug_qdev; > > + void *irq_opaque; > > + PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; > > + PCIDevice *parent_dev; > > + MemoryRegion *address_space_mem; > > + MemoryRegion *address_space_io; > > + > > + QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ > > + QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ > > + > > + /* The bus IRQ state is the logical OR of the connected devices. > > + Keep a count of the number of devices with raised IRQs. */ > > + int nirq; > > + int *irq_count; > > +}; > > + > > +typedef struct PCIBridgeWindows PCIBridgeWindows; > > + > > +/* > > + * Aliases for each of the address space windows that the bridge > > + * can forward. Mapped into the bridge's parent's address space, > > + * as subregions. > > + */ > > +struct PCIBridgeWindows { > > + MemoryRegion alias_pref_mem; > > + MemoryRegion alias_mem; > > + MemoryRegion alias_io; > > +}; > > + > > +struct PCIBridge { > > + PCIDevice dev; > > + > > + /* private member */ > > + PCIBus sec_bus; > > + /* > > + * Memory regions for the bridge's address spaces. These regions are not > > + * directly added to system_memory/system_io or its descendants. > > + * Bridge's secondary bus points to these, so that devices > > + * under the bridge see these regions as its address spaces. > > + * The regions are as large as the entire address space - > > + * they don't take into account any windows. > > + */ > > + MemoryRegion address_space_mem; > > + MemoryRegion address_space_io; > > + > > + PCIBridgeWindows *windows; > > + > > + pci_map_irq_fn map_irq; > > + const char *bus_name; > > +}; > > + > > +#endif /* QEMU_PCI_INTERNALS_H */ > > diff --git a/hw/pci/pci_internals.h b/hw/pci/pci_internals.h > > deleted file mode 100644 > > index 21d0ce6..0000000 > > --- a/hw/pci/pci_internals.h > > +++ /dev/null > > @@ -1,78 +0,0 @@ > > -#ifndef QEMU_PCI_INTERNALS_H > > -#define QEMU_PCI_INTERNALS_H > > - > > -/* > > - * This header files is private to pci.c and pci_bridge.c > > - * So following structures are opaque to others and shouldn't be > > - * accessed. > > - * > > - * For pci-to-pci bridge needs to include this header file to embed > > - * PCIBridge in its structure or to get sizeof(PCIBridge), > > - * However, they shouldn't access those following members directly. > > - * Use accessor function in pci.h, pci_bridge.h > > - */ > > - > > -#define TYPE_PCI_BUS "PCI" > > -#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) > > - > > -struct PCIBus { > > - BusState qbus; > > - PCIDMAContextFunc dma_context_fn; > > - void *dma_context_opaque; > > - uint8_t devfn_min; > > - pci_set_irq_fn set_irq; > > - pci_map_irq_fn map_irq; > > - pci_route_irq_fn route_intx_to_irq; > > - pci_hotplug_fn hotplug; > > - DeviceState *hotplug_qdev; > > - void *irq_opaque; > > - PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; > > - PCIDevice *parent_dev; > > - MemoryRegion *address_space_mem; > > - MemoryRegion *address_space_io; > > - > > - QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */ > > - QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */ > > - > > - /* The bus IRQ state is the logical OR of the connected devices. > > - Keep a count of the number of devices with raised IRQs. */ > > - int nirq; > > - int *irq_count; > > -}; > > - > > -typedef struct PCIBridgeWindows PCIBridgeWindows; > > - > > -/* > > - * Aliases for each of the address space windows that the bridge > > - * can forward. Mapped into the bridge's parent's address space, > > - * as subregions. > > - */ > > -struct PCIBridgeWindows { > > - MemoryRegion alias_pref_mem; > > - MemoryRegion alias_mem; > > - MemoryRegion alias_io; > > -}; > > - > > -struct PCIBridge { > > - PCIDevice dev; > > - > > - /* private member */ > > - PCIBus sec_bus; > > - /* > > - * Memory regions for the bridge's address spaces. These regions are not > > - * directly added to system_memory/system_io or its descendants. > > - * Bridge's secondary bus points to these, so that devices > > - * under the bridge see these regions as its address spaces. > > - * The regions are as large as the entire address space - > > - * they don't take into account any windows. > > - */ > > - MemoryRegion address_space_mem; > > - MemoryRegion address_space_io; > > - > > - PCIBridgeWindows *windows; > > - > > - pci_map_irq_fn map_irq; > > - const char *bus_name; > > -}; > > - > > -#endif /* QEMU_PCI_INTERNALS_H */ > > diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c > > index 7c92f19..d9c38b5 100644 > > --- a/hw/pci/pcie.c > > +++ b/hw/pci/pcie.c > > @@ -23,7 +23,7 @@ > > #include "pcie.h" > > #include "msix.h" > > #include "msi.h" > > -#include "pci_internals.h" > > +#include "pci_bus.h" > > #include "pcie_regs.h" > > #include "range.h" > > > > diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c > > index b04c164..3c3185c 100644 > > --- a/hw/pci/pcie_aer.c > > +++ b/hw/pci/pcie_aer.c > > @@ -25,7 +25,7 @@ > > #include "pcie.h" > > #include "msix.h" > > #include "msi.h" > > -#include "pci_internals.h" > > +#include "pci_bus.h" > > #include "pcie_regs.h" > > > > //#define DEBUG_PCIE > > diff --git a/hw/pci/pcie_port.h b/hw/pci/pcie_port.h > > index 3709583..36b2241 100644 > > --- a/hw/pci/pcie_port.h > > +++ b/hw/pci/pcie_port.h > > @@ -22,7 +22,7 @@ > > #define QEMU_PCIE_PORT_H > > > > #include "pci_bridge.h" > > -#include "pci_internals.h" > > +#include "pci_bus.h" > > > > struct PCIEPort { > > PCIBridge br; > > diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c > > index 4597bbd..9297af0 100644 > > --- a/hw/pci/shpc.c > > +++ b/hw/pci/shpc.c > > @@ -4,7 +4,7 @@ > > #include "range.h" > > #include "shpc.h" > > #include "pci.h" > > -#include "pci_internals.h" > > +#include "pci_bus.h" > > #include "msi.h" > > > > /* TODO: model power only and disabled slot states. */ > > diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c > > index 5c9fc50..dbb4b3b 100644 > > --- a/hw/pci_bridge_dev.c > > +++ b/hw/pci_bridge_dev.c > > @@ -25,7 +25,7 @@ > > #include "pci/shpc.h" > > #include "pci/slotid_cap.h" > > #include "memory.h" > > -#include "pci/pci_internals.h" > > +#include "pci/pci_bus.h" > > > > #define REDHAT_PCI_VENDOR_ID 0x1b36 > > #define PCI_BRIDGE_DEV_VENDOR_ID REDHAT_PCI_VENDOR_ID > > diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c > > index e123866..6b05e5b 100644 > > --- a/hw/spapr_pci.c > > +++ b/hw/spapr_pci.c > > @@ -33,7 +33,7 @@ > > #include <libfdt.h> > > #include "trace.h" > > > > -#include "hw/pci/pci_internals.h" > > +#include "hw/pci/pci_bus.h" > > > > /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */ > > #define RTAS_QUERY_FN 0 > > -- > > MST > > > > ^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 8/8] pci_bus: update comment 2012-12-12 13:13 [Qemu-devel] [PATCH 0/8] pci core reorg Michael S. Tsirkin ` (6 preceding siblings ...) 2012-12-12 13:14 ` [Qemu-devel] [PATCH 7/8] pci: rename pci_internals.h pci_bus.h Michael S. Tsirkin @ 2012-12-12 13:14 ` Michael S. Tsirkin 2012-12-12 13:51 ` [Qemu-devel] [PATCH 0/8] pci core reorg Anthony Liguori 2012-12-12 20:00 ` Blue Swirl 9 siblings, 0 replies; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 13:14 UTC (permalink / raw) To: qemu-devel Don't ask everyone to desist from including this header, simply recommend using accessors. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- hw/pci/pci_bus.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h index 21d0ce6..8217f61 100644 --- a/hw/pci/pci_bus.h +++ b/hw/pci/pci_bus.h @@ -2,14 +2,10 @@ #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. + * PCI Bus and Bridge datastructures. * - * 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 + * Do not access the following members directly; + * use accessor functions in pci.h, pci_bridge.h */ #define TYPE_PCI_BUS "PCI" -- MST ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 0/8] pci core reorg 2012-12-12 13:13 [Qemu-devel] [PATCH 0/8] pci core reorg Michael S. Tsirkin ` (7 preceding siblings ...) 2012-12-12 13:14 ` [Qemu-devel] [PATCH 8/8] pci_bus: update comment Michael S. Tsirkin @ 2012-12-12 13:51 ` Anthony Liguori 2012-12-12 13:59 ` Paolo Bonzini 2012-12-12 20:00 ` Blue Swirl 9 siblings, 1 reply; 19+ messages in thread From: Anthony Liguori @ 2012-12-12 13:51 UTC (permalink / raw) To: Michael S. Tsirkin, qemu-devel; +Cc: Paolo Bonzini "Michael S. Tsirkin" <mst@redhat.com> writes: > This patchset starts some cleanups of the pci core > by rearranging the code: pci core is split out > from devices into its own directory, pci internals.h > is renamed as it's used externally a lot. > > I'd like to merge this quickly to avoid conflicting > with others work. > Plan to send pull request tomorrow, if you have concerns, > speak up soon pls. I'd like to see an Ack from Paolo as he's working on a tree-wide file movement right now.. Don't want to conflict with what he's doing unnecessarily. Otherwise, this looks reasonable to me. Regards, Anthony Liguori > > Thanks, > > > > Michael S. Tsirkin (8): > pci: prepare makefiles for pci code reorganization > MAINTAINERS: add hw/pci/ to list of PCI files > pci: move pci core code to hw/pci > pci: update all users to look in pci/ > pci: make external dependencies explicit > Revert "pci: prepare makefiles for pci code reorganization" > pci: rename pci_internals.h pci_bus.h > pci_bus: update comment > > MAINTAINERS | 1 + > arch_init.c | 2 +- > hw/Makefile.objs | 10 +- > hw/ac97.c | 2 +- > hw/acpi_ich9.c | 2 +- > hw/acpi_piix4.c | 2 +- > hw/alpha_sys.h | 4 +- > hw/apb_pci.c | 8 +- > hw/apic.c | 2 +- > hw/bonito.c | 4 +- > hw/cirrus_vga.c | 2 +- > hw/dec_pci.c | 8 +- > hw/e1000.c | 2 +- > hw/eepro100.c | 2 +- > hw/es1370.c | 2 +- > hw/esp-pci.c | 2 +- > hw/grackle_pci.c | 4 +- > hw/gt64xxx.c | 4 +- > hw/hda-audio.c | 2 +- > hw/i386/Makefile.objs | 2 +- > hw/i82378.c | 2 +- > hw/i82801b11.c | 2 +- > hw/ich9.h | 8 +- > hw/ide.h | 2 +- > hw/ide/ahci.c | 4 +- > hw/ide/cmd646.c | 2 +- > hw/ide/core.c | 2 +- > hw/ide/ich.c | 4 +- > hw/ide/pci.c | 2 +- > hw/ide/piix.c | 2 +- > hw/ide/via.c | 2 +- > hw/intel-hda.c | 4 +- > hw/ioh3420.c | 6 +- > hw/ioh3420.h | 2 +- > hw/ivshmem.c | 4 +- > hw/kvm/apic.c | 2 +- > hw/kvm/pci-assign.c | 4 +- > hw/lpc_ich9.c | 8 +- > hw/lsi53c895a.c | 2 +- > hw/macio.c | 2 +- > hw/megasas.c | 4 +- > hw/mips_fulong2e.c | 2 +- > hw/mips_malta.c | 2 +- > hw/msi.c | 395 --------- > hw/msi.h | 50 -- > hw/msix.c | 562 ------------ > hw/msix.h | 41 - > hw/ne2000.c | 2 +- > hw/openpic.c | 2 +- > hw/pc.c | 4 +- > hw/pc_piix.c | 4 +- > 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_bus.h | 74 ++ > hw/pci/pci_host.c | 180 ++++ > hw/pci/pci_host.h | 62 ++ > hw/pci/pci_ids.h | 147 ++++ > 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_bridge_dev.c | 12 +- > 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/pcnet-pci.c | 2 +- > hw/piix4.c | 2 +- > hw/piix_pci.c | 4 +- > hw/ppc/Makefile.objs | 2 +- > hw/ppc/e500.c | 2 +- > hw/ppc440_bamboo.c | 2 +- > hw/ppc4xx.h | 2 +- > hw/ppc4xx_pci.c | 4 +- > hw/ppc_newworld.c | 2 +- > hw/ppc_oldworld.c | 2 +- > hw/ppc_prep.c | 4 +- > hw/ppce500_pci.c | 4 +- > hw/prep_pci.c | 4 +- > hw/q35.h | 4 +- > hw/qxl.h | 2 +- > hw/r2d.c | 2 +- > hw/realview.c | 2 +- > hw/rtl8139.c | 2 +- > hw/serial-pci.c | 2 +- > hw/sga.c | 2 +- > hw/sh_pci.c | 4 +- > hw/shpc.c | 681 --------------- > hw/shpc.h | 48 - > hw/slotid_cap.c | 44 - > hw/slotid_cap.h | 11 - > hw/smbus_ich9.c | 2 +- > hw/spapr.c | 4 +- > hw/spapr_pci.c | 10 +- > hw/spapr_pci.h | 4 +- > hw/sun4u.c | 2 +- > hw/unin_pci.c | 4 +- > hw/usb/hcd-ehci-pci.c | 2 +- > hw/usb/hcd-ohci.c | 2 +- > hw/usb/hcd-uhci.c | 2 +- > hw/usb/hcd-xhci.c | 6 +- > hw/versatile_pci.c | 4 +- > hw/versatilepb.c | 2 +- > hw/vfio_pci.c | 6 +- > hw/vga-pci.c | 2 +- > hw/vga.c | 2 +- > hw/virtio-balloon.h | 2 +- > hw/virtio-net.h | 2 +- > hw/virtio-pci.c | 6 +- > hw/virtio-scsi.h | 2 +- > hw/vmware_vga.c | 2 +- > hw/vt82c686.c | 4 +- > hw/wdt_i6300esb.c | 2 +- > hw/xen-host-pci-device.h | 2 +- > hw/xen_apic.c | 2 +- > hw/xen_platform.c | 2 +- > hw/xen_pt.c | 2 +- > hw/xen_pt.h | 2 +- > hw/xio3130_downstream.c | 6 +- > hw/xio3130_downstream.h | 2 +- > hw/xio3130_upstream.c | 6 +- > hw/xio3130_upstream.h | 2 +- > kvm-all.c | 2 +- > kvm-stub.c | 2 +- > monitor.c | 2 +- > target-i386/kvm.c | 2 +- > xen-all.c | 2 +- > 162 files changed, 9173 insertions(+), 9176 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_bus.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_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 > > -- > MST ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 0/8] pci core reorg 2012-12-12 13:51 ` [Qemu-devel] [PATCH 0/8] pci core reorg Anthony Liguori @ 2012-12-12 13:59 ` Paolo Bonzini 0 siblings, 0 replies; 19+ messages in thread From: Paolo Bonzini @ 2012-12-12 13:59 UTC (permalink / raw) To: Anthony Liguori; +Cc: qemu-devel, Michael S. Tsirkin Il 12/12/2012 14:51, Anthony Liguori ha scritto: > I'd like to see an Ack from Paolo as he's working on a tree-wide file > movement right now.. Don't want to conflict with what he's doing > unnecessarily. > > Otherwise, this looks reasonable to me. My changes are 99% scripted, so no problem from me. Alternatively, I can pull from Michael and send a combined pull to you. Paolo ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 0/8] pci core reorg 2012-12-12 13:13 [Qemu-devel] [PATCH 0/8] pci core reorg Michael S. Tsirkin ` (8 preceding siblings ...) 2012-12-12 13:51 ` [Qemu-devel] [PATCH 0/8] pci core reorg Anthony Liguori @ 2012-12-12 20:00 ` Blue Swirl 2012-12-12 20:58 ` Michael S. Tsirkin 9 siblings, 1 reply; 19+ messages in thread From: Blue Swirl @ 2012-12-12 20:00 UTC (permalink / raw) To: Michael S. Tsirkin; +Cc: qemu-devel On Wed, Dec 12, 2012 at 1:13 PM, Michael S. Tsirkin <mst@redhat.com> wrote: > This patchset starts some cleanups of the pci core > by rearranging the code: pci core is split out > from devices into its own directory, pci internals.h > is renamed as it's used externally a lot. > > I'd like to merge this quickly to avoid conflicting > with others work. > Plan to send pull request tomorrow, if you have concerns, > speak up soon pls. I had a few comments and one nack but otherwise nice cleanup. > > Thanks, > > > > Michael S. Tsirkin (8): > pci: prepare makefiles for pci code reorganization > MAINTAINERS: add hw/pci/ to list of PCI files > pci: move pci core code to hw/pci > pci: update all users to look in pci/ > pci: make external dependencies explicit > Revert "pci: prepare makefiles for pci code reorganization" > pci: rename pci_internals.h pci_bus.h > pci_bus: update comment > > MAINTAINERS | 1 + > arch_init.c | 2 +- > hw/Makefile.objs | 10 +- > hw/ac97.c | 2 +- > hw/acpi_ich9.c | 2 +- > hw/acpi_piix4.c | 2 +- > hw/alpha_sys.h | 4 +- > hw/apb_pci.c | 8 +- > hw/apic.c | 2 +- > hw/bonito.c | 4 +- > hw/cirrus_vga.c | 2 +- > hw/dec_pci.c | 8 +- > hw/e1000.c | 2 +- > hw/eepro100.c | 2 +- > hw/es1370.c | 2 +- > hw/esp-pci.c | 2 +- > hw/grackle_pci.c | 4 +- > hw/gt64xxx.c | 4 +- > hw/hda-audio.c | 2 +- > hw/i386/Makefile.objs | 2 +- > hw/i82378.c | 2 +- > hw/i82801b11.c | 2 +- > hw/ich9.h | 8 +- > hw/ide.h | 2 +- > hw/ide/ahci.c | 4 +- > hw/ide/cmd646.c | 2 +- > hw/ide/core.c | 2 +- > hw/ide/ich.c | 4 +- > hw/ide/pci.c | 2 +- > hw/ide/piix.c | 2 +- > hw/ide/via.c | 2 +- > hw/intel-hda.c | 4 +- > hw/ioh3420.c | 6 +- > hw/ioh3420.h | 2 +- > hw/ivshmem.c | 4 +- > hw/kvm/apic.c | 2 +- > hw/kvm/pci-assign.c | 4 +- > hw/lpc_ich9.c | 8 +- > hw/lsi53c895a.c | 2 +- > hw/macio.c | 2 +- > hw/megasas.c | 4 +- > hw/mips_fulong2e.c | 2 +- > hw/mips_malta.c | 2 +- > hw/msi.c | 395 --------- > hw/msi.h | 50 -- > hw/msix.c | 562 ------------ > hw/msix.h | 41 - > hw/ne2000.c | 2 +- > hw/openpic.c | 2 +- > hw/pc.c | 4 +- > hw/pc_piix.c | 4 +- > 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_bus.h | 74 ++ > hw/pci/pci_host.c | 180 ++++ > hw/pci/pci_host.h | 62 ++ > hw/pci/pci_ids.h | 147 ++++ > 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_bridge_dev.c | 12 +- > 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/pcnet-pci.c | 2 +- > hw/piix4.c | 2 +- > hw/piix_pci.c | 4 +- > hw/ppc/Makefile.objs | 2 +- > hw/ppc/e500.c | 2 +- > hw/ppc440_bamboo.c | 2 +- > hw/ppc4xx.h | 2 +- > hw/ppc4xx_pci.c | 4 +- > hw/ppc_newworld.c | 2 +- > hw/ppc_oldworld.c | 2 +- > hw/ppc_prep.c | 4 +- > hw/ppce500_pci.c | 4 +- > hw/prep_pci.c | 4 +- > hw/q35.h | 4 +- > hw/qxl.h | 2 +- > hw/r2d.c | 2 +- > hw/realview.c | 2 +- > hw/rtl8139.c | 2 +- > hw/serial-pci.c | 2 +- > hw/sga.c | 2 +- > hw/sh_pci.c | 4 +- > hw/shpc.c | 681 --------------- > hw/shpc.h | 48 - > hw/slotid_cap.c | 44 - > hw/slotid_cap.h | 11 - > hw/smbus_ich9.c | 2 +- > hw/spapr.c | 4 +- > hw/spapr_pci.c | 10 +- > hw/spapr_pci.h | 4 +- > hw/sun4u.c | 2 +- > hw/unin_pci.c | 4 +- > hw/usb/hcd-ehci-pci.c | 2 +- > hw/usb/hcd-ohci.c | 2 +- > hw/usb/hcd-uhci.c | 2 +- > hw/usb/hcd-xhci.c | 6 +- > hw/versatile_pci.c | 4 +- > hw/versatilepb.c | 2 +- > hw/vfio_pci.c | 6 +- > hw/vga-pci.c | 2 +- > hw/vga.c | 2 +- > hw/virtio-balloon.h | 2 +- > hw/virtio-net.h | 2 +- > hw/virtio-pci.c | 6 +- > hw/virtio-scsi.h | 2 +- > hw/vmware_vga.c | 2 +- > hw/vt82c686.c | 4 +- > hw/wdt_i6300esb.c | 2 +- > hw/xen-host-pci-device.h | 2 +- > hw/xen_apic.c | 2 +- > hw/xen_platform.c | 2 +- > hw/xen_pt.c | 2 +- > hw/xen_pt.h | 2 +- > hw/xio3130_downstream.c | 6 +- > hw/xio3130_downstream.h | 2 +- > hw/xio3130_upstream.c | 6 +- > hw/xio3130_upstream.h | 2 +- > kvm-all.c | 2 +- > kvm-stub.c | 2 +- > monitor.c | 2 +- > target-i386/kvm.c | 2 +- > xen-all.c | 2 +- > 162 files changed, 9173 insertions(+), 9176 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_bus.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_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 > > -- > MST > ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 0/8] pci core reorg 2012-12-12 20:00 ` Blue Swirl @ 2012-12-12 20:58 ` Michael S. Tsirkin 0 siblings, 0 replies; 19+ messages in thread From: Michael S. Tsirkin @ 2012-12-12 20:58 UTC (permalink / raw) To: Blue Swirl; +Cc: qemu-devel On Wed, Dec 12, 2012 at 08:00:58PM +0000, Blue Swirl wrote: > On Wed, Dec 12, 2012 at 1:13 PM, Michael S. Tsirkin <mst@redhat.com> wrote: > > This patchset starts some cleanups of the pci core > > by rearranging the code: pci core is split out > > from devices into its own directory, pci internals.h > > is renamed as it's used externally a lot. > > > > I'd like to merge this quickly to avoid conflicting > > with others work. > > Plan to send pull request tomorrow, if you have concerns, > > speak up soon pls. > > I had a few comments and one nack but otherwise nice cleanup. I haven't seen anything besides the nack, and a suggestion to fix coding style of existing files which should be done separately. > > > > Thanks, > > > > > > > > Michael S. Tsirkin (8): > > pci: prepare makefiles for pci code reorganization > > MAINTAINERS: add hw/pci/ to list of PCI files > > pci: move pci core code to hw/pci > > pci: update all users to look in pci/ > > pci: make external dependencies explicit > > Revert "pci: prepare makefiles for pci code reorganization" > > pci: rename pci_internals.h pci_bus.h > > pci_bus: update comment > > > > MAINTAINERS | 1 + > > arch_init.c | 2 +- > > hw/Makefile.objs | 10 +- > > hw/ac97.c | 2 +- > > hw/acpi_ich9.c | 2 +- > > hw/acpi_piix4.c | 2 +- > > hw/alpha_sys.h | 4 +- > > hw/apb_pci.c | 8 +- > > hw/apic.c | 2 +- > > hw/bonito.c | 4 +- > > hw/cirrus_vga.c | 2 +- > > hw/dec_pci.c | 8 +- > > hw/e1000.c | 2 +- > > hw/eepro100.c | 2 +- > > hw/es1370.c | 2 +- > > hw/esp-pci.c | 2 +- > > hw/grackle_pci.c | 4 +- > > hw/gt64xxx.c | 4 +- > > hw/hda-audio.c | 2 +- > > hw/i386/Makefile.objs | 2 +- > > hw/i82378.c | 2 +- > > hw/i82801b11.c | 2 +- > > hw/ich9.h | 8 +- > > hw/ide.h | 2 +- > > hw/ide/ahci.c | 4 +- > > hw/ide/cmd646.c | 2 +- > > hw/ide/core.c | 2 +- > > hw/ide/ich.c | 4 +- > > hw/ide/pci.c | 2 +- > > hw/ide/piix.c | 2 +- > > hw/ide/via.c | 2 +- > > hw/intel-hda.c | 4 +- > > hw/ioh3420.c | 6 +- > > hw/ioh3420.h | 2 +- > > hw/ivshmem.c | 4 +- > > hw/kvm/apic.c | 2 +- > > hw/kvm/pci-assign.c | 4 +- > > hw/lpc_ich9.c | 8 +- > > hw/lsi53c895a.c | 2 +- > > hw/macio.c | 2 +- > > hw/megasas.c | 4 +- > > hw/mips_fulong2e.c | 2 +- > > hw/mips_malta.c | 2 +- > > hw/msi.c | 395 --------- > > hw/msi.h | 50 -- > > hw/msix.c | 562 ------------ > > hw/msix.h | 41 - > > hw/ne2000.c | 2 +- > > hw/openpic.c | 2 +- > > hw/pc.c | 4 +- > > hw/pc_piix.c | 4 +- > > 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_bus.h | 74 ++ > > hw/pci/pci_host.c | 180 ++++ > > hw/pci/pci_host.h | 62 ++ > > hw/pci/pci_ids.h | 147 ++++ > > 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_bridge_dev.c | 12 +- > > 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/pcnet-pci.c | 2 +- > > hw/piix4.c | 2 +- > > hw/piix_pci.c | 4 +- > > hw/ppc/Makefile.objs | 2 +- > > hw/ppc/e500.c | 2 +- > > hw/ppc440_bamboo.c | 2 +- > > hw/ppc4xx.h | 2 +- > > hw/ppc4xx_pci.c | 4 +- > > hw/ppc_newworld.c | 2 +- > > hw/ppc_oldworld.c | 2 +- > > hw/ppc_prep.c | 4 +- > > hw/ppce500_pci.c | 4 +- > > hw/prep_pci.c | 4 +- > > hw/q35.h | 4 +- > > hw/qxl.h | 2 +- > > hw/r2d.c | 2 +- > > hw/realview.c | 2 +- > > hw/rtl8139.c | 2 +- > > hw/serial-pci.c | 2 +- > > hw/sga.c | 2 +- > > hw/sh_pci.c | 4 +- > > hw/shpc.c | 681 --------------- > > hw/shpc.h | 48 - > > hw/slotid_cap.c | 44 - > > hw/slotid_cap.h | 11 - > > hw/smbus_ich9.c | 2 +- > > hw/spapr.c | 4 +- > > hw/spapr_pci.c | 10 +- > > hw/spapr_pci.h | 4 +- > > hw/sun4u.c | 2 +- > > hw/unin_pci.c | 4 +- > > hw/usb/hcd-ehci-pci.c | 2 +- > > hw/usb/hcd-ohci.c | 2 +- > > hw/usb/hcd-uhci.c | 2 +- > > hw/usb/hcd-xhci.c | 6 +- > > hw/versatile_pci.c | 4 +- > > hw/versatilepb.c | 2 +- > > hw/vfio_pci.c | 6 +- > > hw/vga-pci.c | 2 +- > > hw/vga.c | 2 +- > > hw/virtio-balloon.h | 2 +- > > hw/virtio-net.h | 2 +- > > hw/virtio-pci.c | 6 +- > > hw/virtio-scsi.h | 2 +- > > hw/vmware_vga.c | 2 +- > > hw/vt82c686.c | 4 +- > > hw/wdt_i6300esb.c | 2 +- > > hw/xen-host-pci-device.h | 2 +- > > hw/xen_apic.c | 2 +- > > hw/xen_platform.c | 2 +- > > hw/xen_pt.c | 2 +- > > hw/xen_pt.h | 2 +- > > hw/xio3130_downstream.c | 6 +- > > hw/xio3130_downstream.h | 2 +- > > hw/xio3130_upstream.c | 6 +- > > hw/xio3130_upstream.h | 2 +- > > kvm-all.c | 2 +- > > kvm-stub.c | 2 +- > > monitor.c | 2 +- > > target-i386/kvm.c | 2 +- > > xen-all.c | 2 +- > > 162 files changed, 9173 insertions(+), 9176 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_bus.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_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 > > > > -- > > MST > > ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2012-12-12 20:56 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-12-12 13:13 [Qemu-devel] [PATCH 0/8] pci core reorg Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 1/8] pci: prepare makefiles for pci code reorganization Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 2/8] MAINTAINERS: add hw/pci/ to list of PCI files Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci Michael S. Tsirkin 2012-12-12 19:53 ` Blue Swirl 2012-12-12 20:56 ` Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 4/8] pci: update all users to look in pci/ Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 6/8] Revert "pci: prepare makefiles for pci code reorganization" Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 5/8] pci: make external dependencies explicit Michael S. Tsirkin 2012-12-12 19:49 ` Blue Swirl 2012-12-12 20:53 ` Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 7/8] pci: rename pci_internals.h pci_bus.h Michael S. Tsirkin 2012-12-12 19:56 ` Blue Swirl 2012-12-12 20:59 ` Michael S. Tsirkin 2012-12-12 13:14 ` [Qemu-devel] [PATCH 8/8] pci_bus: update comment Michael S. Tsirkin 2012-12-12 13:51 ` [Qemu-devel] [PATCH 0/8] pci core reorg Anthony Liguori 2012-12-12 13:59 ` Paolo Bonzini 2012-12-12 20:00 ` Blue Swirl 2012-12-12 20:58 ` Michael S. Tsirkin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).