From 18e08a55292a57b988df7fa14af2b4dd282a6486 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 11 Nov 2009 14:59:56 +0200 Subject: [PATCH 01/26] pci: pci.h cleanup: move out stuff not in pci.c pci.h declares some functions which aren't defined in pci.h. Clean up moving things to appropriate headers, and update all users. Signed-off-by: Michael S. Tsirkin --- hw/apb_pci.c | 1 + hw/apb_pci.h | 9 +++++++++ hw/lsi53c895a.c | 2 ++ hw/mips_malta.c | 2 ++ hw/pc.c | 5 +++++ hw/pci.h | 25 ------------------------- hw/ppc_newworld.c | 1 + hw/ppc_oldworld.c | 1 + hw/ppc_prep.c | 2 ++ hw/prep_pci.c | 1 + hw/prep_pci.h | 8 ++++++++ hw/r2d.c | 1 + hw/realview.c | 1 + hw/sh_pci.c | 1 + hw/sh_pci.h | 9 +++++++++ hw/sun4u.c | 1 + hw/usb-ohci.c | 1 + hw/usb-ohci.h | 9 +++++++++ hw/usb-uhci.c | 1 + hw/usb-uhci.h | 9 +++++++++ hw/versatilepb.c | 1 + hw/vmware_vga.c | 1 + hw/vmware_vga.h | 9 +++++++++ 23 files changed, 76 insertions(+), 25 deletions(-) create mode 100644 hw/apb_pci.h create mode 100644 hw/prep_pci.h create mode 100644 hw/sh_pci.h create mode 100644 hw/usb-ohci.h create mode 100644 hw/usb-uhci.h create mode 100644 hw/vmware_vga.h diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 39998791f2..1748d8dc79 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -29,6 +29,7 @@ #include "sysbus.h" #include "pci.h" #include "pci_host.h" +#include "apb_pci.h" /* debug APB */ //#define DEBUG_APB diff --git a/hw/apb_pci.h b/hw/apb_pci.h new file mode 100644 index 0000000000..8869f9d326 --- /dev/null +++ b/hw/apb_pci.h @@ -0,0 +1,9 @@ +#ifndef APB_PCI_H +#define APB_PCI_H + +#include "qemu-common.h" + +PCIBus *pci_apb_init(target_phys_addr_t special_base, + target_phys_addr_t mem_base, + qemu_irq *pic, PCIBus **bus2, PCIBus **bus3); +#endif diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 7e47fc9abc..8b8a80b898 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -31,6 +31,8 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__); exit(1);} while do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) #endif +#define LSI_MAX_DEVS 7 + #define LSI_SCNTL0_TRG 0x01 #define LSI_SCNTL0_AAP 0x02 #define LSI_SCNTL0_EPC 0x08 diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 76884570fb..571d8ced16 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -32,6 +32,8 @@ #include "flash.h" #include "mips.h" #include "pci.h" +#include "usb-uhci.h" +#include "vmware_vga.h" #include "qemu-char.h" #include "sysemu.h" #include "audio/audio.h" diff --git a/hw/pc.c b/hw/pc.c index 7c791c4136..97964b27eb 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -25,6 +25,11 @@ #include "pc.h" #include "fdc.h" #include "pci.h" +#include "vmware_vga.h" +#include "usb-uhci.h" +#include "usb-ohci.h" +#include "prep_pci.h" +#include "apb_pci.h" #include "block.h" #include "sysemu.h" #include "audio/audio.h" diff --git a/hw/pci.h b/hw/pci.h index 9a56d0df6e..560da5074e 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -413,31 +413,6 @@ static inline uint32_t pci_config_size(PCIDevice *d) return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; } -/* lsi53c895a.c */ -#define LSI_MAX_DEVS 7 - -/* vmware_vga.c */ -void pci_vmsvga_init(PCIBus *bus); - -/* usb-uhci.c */ -void usb_uhci_piix3_init(PCIBus *bus, int devfn); -void usb_uhci_piix4_init(PCIBus *bus, int devfn); - -/* usb-ohci.c */ -void usb_ohci_init_pci(struct PCIBus *bus, int devfn); - -/* prep_pci.c */ -PCIBus *pci_prep_init(qemu_irq *pic); - -/* apb_pci.c */ -PCIBus *pci_apb_init(target_phys_addr_t special_base, - target_phys_addr_t mem_base, - qemu_irq *pic, PCIBus **bus2, PCIBus **bus3); - -/* sh_pci.c */ -PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *pic, int devfn_min, int nirq); - /* These are not pci specific. Should move into a separate header. * Only pci.c uses them, so keep them here for now. */ diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index da868d302b..7579ddd340 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -29,6 +29,7 @@ #include "nvram.h" #include "pc.h" #include "pci.h" +#include "usb-ohci.h" #include "net.h" #include "sysemu.h" #include "boards.h" diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 9b49a3dbdd..32fd03a900 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -32,6 +32,7 @@ #include "net.h" #include "isa.h" #include "pci.h" +#include "usb-ohci.h" #include "boards.h" #include "fw_cfg.h" #include "escc.h" diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index cd561e10c6..eb758f2dab 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -29,6 +29,8 @@ #include "sysemu.h" #include "isa.h" #include "pci.h" +#include "prep_pci.h" +#include "usb-ohci.h" #include "ppc.h" #include "boards.h" #include "qemu-log.h" diff --git a/hw/prep_pci.c b/hw/prep_pci.c index a338f81e11..80e20ac1ae 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -25,6 +25,7 @@ #include "hw.h" #include "pci.h" #include "pci_host.h" +#include "prep_pci.h" typedef PCIHostState PREPPCIState; diff --git a/hw/prep_pci.h b/hw/prep_pci.h new file mode 100644 index 0000000000..cd6851288c --- /dev/null +++ b/hw/prep_pci.h @@ -0,0 +1,8 @@ +#ifndef QEMU_PREP_PCI_H +#define QEMU_PREP_PCI_H + +#include "qemu-common.h" + +PCIBus *pci_prep_init(qemu_irq *pic); + +#endif diff --git a/hw/r2d.c b/hw/r2d.c index c074a6e9c5..e4c02f05ef 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -29,6 +29,7 @@ #include "sysemu.h" #include "boards.h" #include "pci.h" +#include "sh_pci.h" #include "net.h" #include "sh7750_regs.h" #include "ide.h" diff --git a/hw/realview.c b/hw/realview.c index f0b8347340..3322c4fd5d 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -12,6 +12,7 @@ #include "primecell.h" #include "devices.h" #include "pci.h" +#include "usb-ohci.h" #include "net.h" #include "sysemu.h" #include "boards.h" diff --git a/hw/sh_pci.c b/hw/sh_pci.c index 4277b01c9f..52dc02e1e7 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -24,6 +24,7 @@ #include "hw.h" #include "sh.h" #include "pci.h" +#include "sh_pci.h" #include "bswap.h" typedef struct { diff --git a/hw/sh_pci.h b/hw/sh_pci.h new file mode 100644 index 0000000000..b1a5ec37c3 --- /dev/null +++ b/hw/sh_pci.h @@ -0,0 +1,9 @@ +#ifndef QEMU_SH_PCI_H +#define QEMU_SH_PCI_H + +#include "qemu-common.h" + +PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, + void *pic, int devfn_min, int nirq); + +#endif diff --git a/hw/sun4u.c b/hw/sun4u.c index 2189fa06af..a7a227bbec 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -23,6 +23,7 @@ */ #include "hw.h" #include "pci.h" +#include "apb_pci.h" #include "pc.h" #include "nvram.h" #include "fdc.h" diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 0f7f4de154..7ab3a98619 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -32,6 +32,7 @@ #include "pci.h" #include "pxa.h" #include "devices.h" +#include "usb-ohci.h" //#define DEBUG_OHCI /* Dump packet contents. */ diff --git a/hw/usb-ohci.h b/hw/usb-ohci.h new file mode 100644 index 0000000000..eefcef3602 --- /dev/null +++ b/hw/usb-ohci.h @@ -0,0 +1,9 @@ +#ifndef QEMU_USB_OHCI_H +#define QEMU_USB_OHCI_H + +#include "qemu-common.h" + +void usb_ohci_init_pci(struct PCIBus *bus, int devfn); + +#endif + diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 8babb0265e..671916e056 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -29,6 +29,7 @@ #include "usb.h" #include "pci.h" #include "qemu-timer.h" +#include "usb-uhci.h" //#define DEBUG //#define DEBUG_DUMP_DATA diff --git a/hw/usb-uhci.h b/hw/usb-uhci.h new file mode 100644 index 0000000000..911948edb4 --- /dev/null +++ b/hw/usb-uhci.h @@ -0,0 +1,9 @@ +#ifndef QEMU_USB_UHCI_H +#define QEMU_USB_UHCI_H + +#include "qemu-common.h" + +void usb_uhci_piix3_init(PCIBus *bus, int devfn); +void usb_uhci_piix4_init(PCIBus *bus, int devfn); + +#endif diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 226c616ee3..391f5b88c6 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -14,6 +14,7 @@ #include "net.h" #include "sysemu.h" #include "pci.h" +#include "usb-ohci.h" #include "boards.h" /* Primary interrupt controller. */ diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 33e876e959..bb3410105f 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -24,6 +24,7 @@ #include "hw.h" #include "console.h" #include "pci.h" +#include "vmware_vga.h" #define VERBOSE #undef DIRECT_VRAM diff --git a/hw/vmware_vga.h b/hw/vmware_vga.h new file mode 100644 index 0000000000..2e0813c81b --- /dev/null +++ b/hw/vmware_vga.h @@ -0,0 +1,9 @@ +#ifndef QEMU_VMWARE_VGA_H +#define QEMU_VMWARE_VGA_H + +#include "qemu-common.h" + +/* vmware_vga.c */ +void pci_vmsvga_init(PCIBus *bus); + +#endif From f88d7509b444ffa289e5054b34bc6f4800f6b76d Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:29 +0900 Subject: [PATCH 02/26] pci: fix pci_info_device(). It printed wrong limit value of bridge. This patch fixes it. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci.c b/hw/pci.c index 5b3461cd66..040fa767fb 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -986,7 +986,7 @@ static void pci_info_device(PCIBus *bus, PCIDevice *d) base, limit); base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_MEMORY); - limit= pci_config_get_memory_base(d, PCI_BASE_ADDRESS_SPACE_MEMORY); + limit= pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_MEMORY); monitor_printf(mon, " memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n", base, limit); From b6243d991a4d073b2c8c16737fec9ee74274bfeb Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:30 +0900 Subject: [PATCH 03/26] pci: move pci_data_{read, write}() declaration from pci.h to pci_host.h Now pci host stuff has been moved from pci.[hc] to pci_host.[hc] so the declaration of pci_data_{read, write}() should be in pci_host.h This patch moves them from pci.h to pci_host.h for consistency. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.h | 2 -- hw/pci_host.h | 3 +++ hw/sh_pci.c | 1 + hw/versatile_pci.c | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/pci.h b/hw/pci.h index 560da5074e..2f213524c5 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -293,8 +293,6 @@ 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); -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); int pci_bus_num(PCIBus *s); void pci_for_each_device(PCIBus *bus, int bus_num, void (*fn)(PCIBus *bus, PCIDevice *d)); PCIBus *pci_find_host_bus(int domain); diff --git a/hw/pci_host.h b/hw/pci_host.h index e5e877f4cd..7cfa693563 100644 --- a/hw/pci_host.h +++ b/hw/pci_host.h @@ -36,6 +36,9 @@ typedef struct { PCIBus *bus; } PCIHostState; +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); + /* for mmio */ int pci_host_config_register_io_memory(PCIHostState *s); int pci_host_config_register_io_memory_noswap(PCIHostState *s); diff --git a/hw/sh_pci.c b/hw/sh_pci.c index 52dc02e1e7..abe4c7568b 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -24,6 +24,7 @@ #include "hw.h" #include "sh.h" #include "pci.h" +#include "pci_host.h" #include "sh_pci.h" #include "bswap.h" diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index a0d7d07ad2..153c6514f7 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -9,6 +9,7 @@ #include "sysbus.h" #include "pci.h" +#include "pci_host.h" typedef struct { SysBusDevice busdev; From 4677d8ed9db8564fb0b02c1d012d4b25de633290 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 12 Nov 2009 14:58:31 +0900 Subject: [PATCH 04/26] pci: simplify (pci_/pcie_mmcfg_)data_read() Remove switch on length: we don't care about high bits for value, so just return all ones if no device. And add one assert(). Signed-off-by: Michael S. Tsirkin Acked-by: Isaku Yamahata --- hw/pci_host.c | 22 ++++++---------------- hw/pcie_host.c | 26 +++++--------------------- 2 files changed, 11 insertions(+), 37 deletions(-) diff --git a/hw/pci_host.c b/hw/pci_host.c index f4518dce72..4a29f44904 100644 --- a/hw/pci_host.c +++ b/hw/pci_host.c @@ -71,25 +71,15 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) uint32_t config_addr = pci_addr_to_config(addr); uint32_t val; + assert(len == 1 || len == 2 || len == 4); if (!pci_dev) { - switch(len) { - case 1: - val = 0xff; - break; - case 2: - val = 0xffff; - break; - default: - case 4: - val = 0xffffffff; - break; - } - } else { - val = pci_dev->config_read(pci_dev, config_addr, len); - PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n", - __func__, pci_dev->name, config_addr, val, len); + return ~0x0; } + val = pci_dev->config_read(pci_dev, config_addr, len); + PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n", + __func__, pci_dev->name, config_addr, val, len); + return val; } diff --git a/hw/pcie_host.c b/hw/pcie_host.c index b52fec6813..1dbc94ef6e 100644 --- a/hw/pcie_host.c +++ b/hw/pcie_host.c @@ -65,31 +65,15 @@ static void pcie_mmcfg_data_write(PCIBus *s, PCIE_MMCFG_CONFOFFSET(mmcfg_addr), val, len); } -static uint32_t pcie_mmcfg_data_read(PCIBus *s, - uint32_t mmcfg_addr, int len) +static uint32_t pcie_mmcfg_data_read(PCIBus *s, uint32_t addr, int len) { - PCIDevice *pci_dev = pcie_mmcfg_addr_to_dev(s, mmcfg_addr); - uint32_t val; + PCIDevice *pci_dev = pcie_mmcfg_addr_to_dev(s, addr); + assert(len == 1 || len == 2 || len == 4); if (!pci_dev) { - switch(len) { - case 1: - val = 0xff; - break; - case 2: - val = 0xffff; - break; - default: - case 4: - val = 0xffffffff; - break; - } - } else { - val = pci_dev->config_read(pci_dev, - PCIE_MMCFG_CONFOFFSET(mmcfg_addr), len); + return ~0x0; } - - return val; + return pci_dev->config_read(pci_dev, PCIE_MMCFG_CONFOFFSET(addr), len); } static void pcie_mmcfg_data_writeb(void *opaque, From 7ac901cd18c382b9e7a07ac0b3a47f86d1ed4c1d Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:32 +0900 Subject: [PATCH 05/26] pci: remove pci_addr_to_config() by open code This patch removes pci_addr_to_config() and open code it as suggested by Michael S. Tsirkin . Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci_host.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/hw/pci_host.c b/hw/pci_host.c index 4a29f44904..ccefa34a4a 100644 --- a/hw/pci_host.c +++ b/hw/pci_host.c @@ -47,15 +47,10 @@ static inline PCIDevice *pci_addr_to_dev(PCIBus *bus, uint32_t addr) return pci_find_device(bus, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn)); } -static inline uint32_t pci_addr_to_config(uint32_t addr) -{ - return addr & (PCI_CONFIG_SPACE_SIZE - 1); -} - void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len) { PCIDevice *pci_dev = pci_addr_to_dev(s, addr); - uint32_t config_addr = pci_addr_to_config(addr); + uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); if (!pci_dev) return; @@ -68,7 +63,7 @@ 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) { PCIDevice *pci_dev = pci_addr_to_dev(s, addr); - uint32_t config_addr = pci_addr_to_config(addr); + uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); uint32_t val; assert(len == 1 || len == 2 || len == 4); From 8d6514f8dd2a8102ec3d577b13cb565fb9cfe73c Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 13:17:23 +0200 Subject: [PATCH 06/26] pci: rename (pci_/pcie_mmcfg_)addr_to_dev This patch renames pci_addr_to_dev(), pcie_mmcfg_addr_to_dev() to pci_dev_find_by_addr(), pcie_dev_find_by_mmcfg_addr() as "Michael S. Tsirkin" suggested. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci_host.c | 6 +++--- hw/pcie_host.c | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/hw/pci_host.c b/hw/pci_host.c index ccefa34a4a..403d0408c6 100644 --- a/hw/pci_host.c +++ b/hw/pci_host.c @@ -40,7 +40,7 @@ do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0) */ /* the helper functio to get a PCIDeice* for a given pci address */ -static inline PCIDevice *pci_addr_to_dev(PCIBus *bus, uint32_t addr) +static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr) { uint8_t bus_num = (addr >> 16) & 0xff; uint8_t devfn = (addr >> 8) & 0xff; @@ -49,7 +49,7 @@ static inline PCIDevice *pci_addr_to_dev(PCIBus *bus, uint32_t addr) void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len) { - PCIDevice *pci_dev = pci_addr_to_dev(s, addr); + PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); if (!pci_dev) @@ -62,7 +62,7 @@ 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) { - PCIDevice *pci_dev = pci_addr_to_dev(s, addr); + PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); uint32_t val; diff --git a/hw/pcie_host.c b/hw/pcie_host.c index 1dbc94ef6e..fbd6c3759f 100644 --- a/hw/pcie_host.c +++ b/hw/pcie_host.c @@ -46,7 +46,8 @@ /* a helper function to get a PCIDevice for a given mmconfig address */ -static inline PCIDevice *pcie_mmcfg_addr_to_dev(PCIBus *s, uint32_t mmcfg_addr) +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), PCI_SLOT(PCIE_MMCFG_DEVFN(mmcfg_addr)), @@ -56,7 +57,7 @@ static inline PCIDevice *pcie_mmcfg_addr_to_dev(PCIBus *s, uint32_t mmcfg_addr) static void pcie_mmcfg_data_write(PCIBus *s, uint32_t mmcfg_addr, uint32_t val, int len) { - PCIDevice *pci_dev = pcie_mmcfg_addr_to_dev(s, mmcfg_addr); + PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); if (!pci_dev) return; @@ -67,7 +68,7 @@ static void pcie_mmcfg_data_write(PCIBus *s, static uint32_t pcie_mmcfg_data_read(PCIBus *s, uint32_t addr, int len) { - PCIDevice *pci_dev = pcie_mmcfg_addr_to_dev(s, addr); + PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, addr); assert(len == 1 || len == 2 || len == 4); if (!pci_dev) { From f08b32fe959c157d3c3acdad9c7bfe56b5597af1 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:34 +0900 Subject: [PATCH 07/26] pci: shorten pci_host_{conf, data}_register_xxx function a bit. pci_host_data_register_io_memory and its variants are too long a bit. So shorten them. Now they are pci_host_{conf, data}_register_{mmio, mmio_noswap, ioport}() Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/apb_pci.c | 4 ++-- hw/grackle_pci.c | 8 ++++---- hw/pci_host.c | 8 ++++---- hw/pci_host.h | 8 ++++---- hw/piix_pci.c | 2 +- hw/ppc4xx_pci.c | 2 +- hw/ppce500_pci.c | 4 ++-- hw/prep_pci.c | 2 +- hw/unin_pci.c | 16 ++++++++-------- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 1748d8dc79..f2ed136fda 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -236,10 +236,10 @@ static int pci_pbm_init_device(SysBusDevice *dev) pci_apb_iowrite, s); sysbus_init_mmio(dev, 0x10000ULL, pci_ioport); /* mem_config */ - pci_mem_config = pci_host_config_register_io_memory(&s->host_state); + pci_mem_config = pci_host_conf_register_mmio(&s->host_state); sysbus_init_mmio(dev, 0x10ULL, pci_mem_config); /* mem_data */ - pci_mem_data = pci_host_data_register_io_memory(&s->host_state); + pci_mem_data = pci_host_data_register_mmio(&s->host_state); sysbus_init_mmio(dev, 0x10000000ULL, pci_mem_data); return 0; } diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index f3a8a7da12..089d1fba01 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -108,8 +108,8 @@ static int pci_grackle_init_device(SysBusDevice *dev) s = FROM_SYSBUS(GrackleState, dev); - pci_mem_config = pci_host_config_register_io_memory(&s->host_state); - pci_mem_data = pci_host_data_register_io_memory(&s->host_state); + pci_mem_config = pci_host_conf_register_mmio(&s->host_state); + pci_mem_data = pci_host_data_register_mmio(&s->host_state); sysbus_init_mmio(dev, 0x1000, pci_mem_config); sysbus_init_mmio(dev, 0x1000, pci_mem_data); @@ -126,8 +126,8 @@ static int pci_dec_21154_init_device(SysBusDevice *dev) s = FROM_SYSBUS(GrackleState, dev); - pci_mem_config = pci_host_config_register_io_memory(&s->host_state); - pci_mem_data = pci_host_data_register_io_memory(&s->host_state); + pci_mem_config = pci_host_conf_register_mmio(&s->host_state); + pci_mem_data = pci_host_data_register_mmio(&s->host_state); sysbus_init_mmio(dev, 0x1000, pci_mem_config); sysbus_init_mmio(dev, 0x1000, pci_mem_data); return 0; diff --git a/hw/pci_host.c b/hw/pci_host.c index 403d0408c6..45ddcd1e8f 100644 --- a/hw/pci_host.c +++ b/hw/pci_host.c @@ -116,7 +116,7 @@ static CPUReadMemoryFunc * const pci_host_config_read[] = { &pci_host_config_readl, }; -int pci_host_config_register_io_memory(PCIHostState *s) +int pci_host_conf_register_mmio(PCIHostState *s) { return cpu_register_io_memory(pci_host_config_read, pci_host_config_write, s); @@ -156,7 +156,7 @@ static CPUReadMemoryFunc * const pci_host_config_read_noswap[] = { &pci_host_config_readl_noswap, }; -int pci_host_config_register_io_memory_noswap(PCIHostState *s) +int pci_host_conf_register_mmio_noswap(PCIHostState *s) { return cpu_register_io_memory(pci_host_config_read_noswap, pci_host_config_write_noswap, s); @@ -180,7 +180,7 @@ static uint32_t pci_host_config_readl_ioport(void *opaque, uint32_t addr) return val; } -void pci_host_config_register_ioport(pio_addr_t ioport, PCIHostState *s) +void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s) { register_ioport_write(ioport, 4, 4, pci_host_config_writel_ioport, s); register_ioport_read(ioport, 4, 4, pci_host_config_readl_ioport, s); @@ -203,7 +203,7 @@ static CPUReadMemoryFunc * const pci_host_data_read_mmio[] = { pci_host_data_readl_mmio, }; -int pci_host_data_register_io_memory(PCIHostState *s) +int pci_host_data_register_mmio(PCIHostState *s) { return cpu_register_io_memory(pci_host_data_read_mmio, pci_host_data_write_mmio, diff --git a/hw/pci_host.h b/hw/pci_host.h index 7cfa693563..cf3a3393d9 100644 --- a/hw/pci_host.h +++ b/hw/pci_host.h @@ -40,12 +40,12 @@ 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); /* for mmio */ -int pci_host_config_register_io_memory(PCIHostState *s); -int pci_host_config_register_io_memory_noswap(PCIHostState *s); -int pci_host_data_register_io_memory(PCIHostState *s); +int pci_host_conf_register_mmio(PCIHostState *s); +int pci_host_conf_register_mmio_noswap(PCIHostState *s); +int pci_host_data_register_mmio(PCIHostState *s); /* for ioio */ -void pci_host_config_register_ioport(pio_addr_t ioport, PCIHostState *s); +void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s); void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s); #endif /* PCI_HOST_H */ diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 5fb7d7be93..a44f941dc2 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -180,7 +180,7 @@ static int i440fx_pcihost_initfn(SysBusDevice *dev) { I440FXState *s = FROM_SYSBUS(I440FXState, dev); - pci_host_config_register_ioport(0xcf8, s); + pci_host_conf_register_ioport(0xcf8, s); pci_host_data_register_ioport(0xcfc, s); return 0; diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index 3aa7489e28..2d00b61228 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -378,7 +378,7 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4], cpu_register_physical_memory(config_space + PCIC0_CFGADDR, 4, index); /* CFGDATA */ - index = pci_host_data_register_io_memory(&controller->pci_state); + index = pci_host_data_register_mmio(&controller->pci_state); if (index < 0) goto free; cpu_register_physical_memory(config_space + PCIC0_CFGDATA, 4, index); diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 223de3ae34..a72fb86d2e 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -293,13 +293,13 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers) controller->pci_dev = d; /* CFGADDR */ - index = pci_host_config_register_io_memory_noswap(&controller->pci_state); + index = pci_host_conf_register_mmio_noswap(&controller->pci_state); if (index < 0) goto free; cpu_register_physical_memory(registers + PCIE500_CFGADDR, 4, index); /* CFGDATA */ - index = pci_host_data_register_io_memory(&controller->pci_state); + index = pci_host_data_register_mmio(&controller->pci_state); if (index < 0) goto free; cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index); diff --git a/hw/prep_pci.c b/hw/prep_pci.c index 80e20ac1ae..19f028c7b7 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -128,7 +128,7 @@ PCIBus *pci_prep_init(qemu_irq *pic) s->bus = pci_register_bus(NULL, "pci", prep_set_irq, prep_map_irq, pic, 0, 4); - pci_host_config_register_ioport(0xcf8, s); + pci_host_conf_register_ioport(0xcf8, s); pci_host_data_register_ioport(0xcfc, s); diff --git a/hw/unin_pci.c b/hw/unin_pci.c index fe13e7b3eb..5b3f118fc5 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -84,8 +84,8 @@ static int pci_unin_main_init_device(SysBusDevice *dev) /* Uninorth main bus */ s = FROM_SYSBUS(UNINState, dev); - pci_mem_config = pci_host_config_register_io_memory(&s->host_state); - pci_mem_data = pci_host_data_register_io_memory(&s->host_state); + pci_mem_config = pci_host_conf_register_mmio(&s->host_state); + pci_mem_data = pci_host_data_register_mmio(&s->host_state); sysbus_init_mmio(dev, 0x1000, pci_mem_config); sysbus_init_mmio(dev, 0x1000, pci_mem_data); @@ -103,8 +103,8 @@ static int pci_dec_21154_init_device(SysBusDevice *dev) s = FROM_SYSBUS(UNINState, dev); // XXX: s = &pci_bridge[2]; - pci_mem_config = pci_host_config_register_io_memory_noswap(&s->host_state); - pci_mem_data = pci_host_data_register_io_memory(&s->host_state); + pci_mem_config = pci_host_conf_register_mmio_noswap(&s->host_state); + pci_mem_data = pci_host_data_register_mmio(&s->host_state); sysbus_init_mmio(dev, 0x1000, pci_mem_config); sysbus_init_mmio(dev, 0x1000, pci_mem_data); return 0; @@ -118,8 +118,8 @@ static int pci_unin_agp_init_device(SysBusDevice *dev) /* Uninorth AGP bus */ s = FROM_SYSBUS(UNINState, dev); - pci_mem_config = pci_host_config_register_io_memory_noswap(&s->host_state); - pci_mem_data = pci_host_data_register_io_memory(&s->host_state); + pci_mem_config = pci_host_conf_register_mmio_noswap(&s->host_state); + pci_mem_data = pci_host_data_register_mmio(&s->host_state); sysbus_init_mmio(dev, 0x1000, pci_mem_config); sysbus_init_mmio(dev, 0x1000, pci_mem_data); return 0; @@ -133,8 +133,8 @@ static int pci_unin_internal_init_device(SysBusDevice *dev) /* Uninorth internal bus */ s = FROM_SYSBUS(UNINState, dev); - pci_mem_config = pci_host_config_register_io_memory_noswap(&s->host_state); - pci_mem_data = pci_host_data_register_io_memory(&s->host_state); + pci_mem_config = pci_host_conf_register_mmio_noswap(&s->host_state); + pci_mem_data = pci_host_data_register_mmio(&s->host_state); sysbus_init_mmio(dev, 0x1000, pci_mem_config); sysbus_init_mmio(dev, 0x1000, pci_mem_data); return 0; From 070297d2609fea4fd7afec05eb9a43688b91fb79 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:35 +0900 Subject: [PATCH 08/26] pci: remove pci_sub_bus() by open coding. Because pci_sub_bus() is used only once so eliminate it by open coding as suggested by "Michael S. Tsirkin" . Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 040fa767fb..aa677b2dbe 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -239,13 +239,6 @@ int pci_bus_num(PCIBus *s) return s->parent_dev->config[PCI_SECONDARY_BUS]; } -static uint8_t pci_sub_bus(PCIBus *s) -{ - if (!s->parent_dev) - return 255; /* pci host bridge */ - return s->parent_dev->config[PCI_SUBORDINATE_BUS]; -} - static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) { PCIDevice *s = container_of(pv, PCIDevice, config); @@ -1180,7 +1173,10 @@ PCIBus *pci_find_bus(PCIBus *bus, int bus_num) /* try child bus */ QLIST_FOREACH(sec, &bus->child, sibling) { - if (pci_bus_num(sec) <= bus_num && bus_num <= pci_sub_bus(sec)) { + + if (!bus->parent_dev /* pci host bridge */ + || (pci_bus_num(sec) <= bus_num && + bus->parent_dev->config[PCI_SUBORDINATE_BUS])) { return pci_find_bus(sec, bus_num); } } From c469e1dd6375c50bc61d995dde4714fc19f411ed Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:36 +0900 Subject: [PATCH 09/26] pci: s/pci_find_host_bus/pci_find_root_bus/g This patch renames pci_find_host_bus() to pci_find_root_bus() as suggested by "Michael S. Tsirkin" . Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci-hotplug.c | 4 ++-- hw/pci.c | 8 ++++---- hw/pci.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index a254498143..081d6d1ac9 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -113,7 +113,7 @@ void drive_hot_add(Monitor *mon, const QDict *qdict) if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) { goto err; } - dev = pci_find_device(pci_find_host_bus(0), pci_bus, slot, 0); + dev = pci_find_device(pci_find_root_bus(0), pci_bus, slot, 0); if (!dev) { monitor_printf(mon, "no pci device with address %s\n", pci_addr); goto err; @@ -257,7 +257,7 @@ void pci_device_hot_remove(Monitor *mon, const char *pci_addr) return; } - d = pci_find_device(pci_find_host_bus(0), bus, slot, 0); + d = pci_find_device(pci_find_root_bus(0), bus, slot, 0); if (!d) { monitor_printf(mon, "slot %d empty\n", slot); return; diff --git a/hw/pci.c b/hw/pci.c index aa677b2dbe..d8f5fa0ede 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -146,7 +146,7 @@ static void pci_host_bus_register(int domain, PCIBus *bus) QLIST_INSERT_HEAD(&host_buses, host, next); } -PCIBus *pci_find_host_bus(int domain) +PCIBus *pci_find_root_bus(int domain) { struct PCIHostBus *host; @@ -372,7 +372,7 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *s return -1; /* Note: QEMU doesn't implement domains other than 0 */ - if (!pci_find_bus(pci_find_host_bus(dom), bus)) + if (!pci_find_bus(pci_find_root_bus(dom), bus)) return -1; *domp = dom; @@ -402,7 +402,7 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) if (!devaddr) { *devfnp = -1; - return pci_find_bus(pci_find_host_bus(0), 0); + return pci_find_bus(pci_find_root_bus(0), 0); } if (pci_parse_devaddr(devaddr, &dom, &bus, &slot) < 0) { @@ -410,7 +410,7 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) } *devfnp = slot << 3; - return pci_find_bus(pci_find_host_bus(0), bus); + return pci_find_bus(pci_find_root_bus(0), bus); } static void pci_init_cmask(PCIDevice *dev) diff --git a/hw/pci.h b/hw/pci.h index 2f213524c5..ff5f36ceeb 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -295,7 +295,7 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, const char *default_devaddr); int pci_bus_num(PCIBus *s); void pci_for_each_device(PCIBus *bus, int bus_num, void (*fn)(PCIBus *bus, PCIDevice *d)); -PCIBus *pci_find_host_bus(int domain); +PCIBus *pci_find_root_bus(int domain); PCIBus *pci_find_bus(PCIBus *bus, int bus_num); PCIDevice *pci_find_device(PCIBus *bus, int bus_num, int slot, int function); PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr); From 42331e9f2fa2d98acc8faf31c4b04de8ea2d7129 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:37 +0900 Subject: [PATCH 10/26] pci_host: remove unnecessary & 0xff. This patch removes unnecessary & 0xff in pci_dev_find_by_addr(). Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci_host.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/pci_host.c b/hw/pci_host.c index 45ddcd1e8f..eeb8deeafb 100644 --- a/hw/pci_host.c +++ b/hw/pci_host.c @@ -42,8 +42,9 @@ do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0) /* 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) & 0xff; - uint8_t devfn = (addr >> 8) & 0xff; + uint8_t bus_num = addr >> 16; + uint8_t devfn = addr >> 8; + return pci_find_device(bus, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn)); } From c34369d48c9b94f5a71f65cc97caaa5a75ffad5c Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:38 +0900 Subject: [PATCH 11/26] pci: kill unnecessary included in pci.c including pci_host.h isn't needed by pci.c. This patch kills it. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/pci.c b/hw/pci.c index d8f5fa0ede..c3ad1bbb89 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -23,7 +23,6 @@ */ #include "hw.h" #include "pci.h" -#include "pci_host.h" #include "monitor.h" #include "net.h" #include "sysemu.h" From 3e21ffc954c09e90b25a446813ff1c0b26817aef Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:39 +0900 Subject: [PATCH 12/26] pci: clean up of pci_init_wmask(). This patch replaces for loop by memset in pci_init_wmask(). Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index c3ad1bbb89..64cf0a8a50 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -426,15 +426,15 @@ static void pci_init_cmask(PCIDevice *dev) static void pci_init_wmask(PCIDevice *dev) { - int i; int config_size = pci_config_size(dev); dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff; dev->wmask[PCI_INTERRUPT_LINE] = 0xff; pci_set_word(dev->wmask + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - for (i = PCI_CONFIG_HEADER_SIZE; i < config_size; ++i) - dev->wmask[i] = 0xff; + + memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff, + config_size - PCI_CONFIG_HEADER_SIZE); } static void pci_init_wmask_bridge(PCIDevice *d) From 3c217c14f58c0146a0dbca01716cd850a63a0e81 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:40 +0900 Subject: [PATCH 13/26] pci: remove some unnecessary comment in pci.h This patch removes some comment which should go into commit log in pci.h. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.h | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/hw/pci.h b/hw/pci.h index ff5f36ceeb..b2c2c92f2d 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -382,17 +382,10 @@ typedef struct { PCIConfigWriteFunc *config_write; /* pci config header type */ - uint8_t header_type; /* this is necessary for initialization - * code to know its header type before - * device specific code can initialize - * configuration space. - */ + uint8_t header_type; /* pcie stuff */ - int is_express; /* is this device pci express? - * initialization code needs to know this before - * each specific device initialization. - */ + int is_express; /* is this device pci express? */ } PCIDeviceInfo; void pci_qdev_register(PCIDeviceInfo *info); From fb47a2e983f3e0b4c9d36fe0d31ed8a1224e767b Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:41 +0900 Subject: [PATCH 14/26] pci: move typedef, PCIHostState, PCIExpressHost to qemu-common.h. This patch moves two typedefs, PCIHostState and PCIExpressHost to qemu-common.h for consistency as PCIBus and PCIDevice are typedefed in qemu-common.h. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci_host.h | 4 ++-- hw/pcie_host.h | 4 ++-- qemu-common.h | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/pci_host.h b/hw/pci_host.h index cf3a3393d9..a006687f8b 100644 --- a/hw/pci_host.h +++ b/hw/pci_host.h @@ -30,11 +30,11 @@ #include "sysbus.h" -typedef struct { +struct PCIHostState { SysBusDevice busdev; uint32_t config_reg; PCIBus *bus; -} PCIHostState; +}; 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); diff --git a/hw/pcie_host.h b/hw/pcie_host.h index a7771c912a..7754ac94e8 100644 --- a/hw/pcie_host.h +++ b/hw/pcie_host.h @@ -24,7 +24,7 @@ #include "pci_host.h" -typedef struct { +struct PCIExpressHost { PCIHostState pci; /* express part */ @@ -37,7 +37,7 @@ typedef struct { /* result of cpu_register_io_memory() to map MMCONFIG area */ int mmio_index; -} PCIExpressHost; +}; int pcie_host_init(PCIExpressHost *e); void pcie_host_mmcfg_unmap(PCIExpressHost *e); diff --git a/qemu-common.h b/qemu-common.h index b1e038bd00..57af677f07 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -198,6 +198,8 @@ typedef struct i2c_bus i2c_bus; typedef struct i2c_slave i2c_slave; typedef struct SMBusDevice SMBusDevice; typedef struct QEMUTimer QEMUTimer; +typedef struct PCIHostState PCIHostState; +typedef struct PCIExpressHost PCIExpressHost; typedef struct PCIBus PCIBus; typedef struct PCIDevice PCIDevice; typedef struct SerialState SerialState; From 2c56b44b88d913c4f7acb444071052b55b37da34 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:42 +0900 Subject: [PATCH 15/26] pci: remove unused constants This patch removes unused constants committed by fb23162885f7fd8cf7334bed22c25ac32c7d8b9d. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/hw/pci.h b/hw/pci.h index b2c2c92f2d..6a868f95de 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -101,14 +101,6 @@ typedef struct PCIIORegion { #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 master */ -#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_REVISION_ID 0x08 /* 8 bits */ #define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ @@ -128,7 +120,6 @@ typedef struct PCIIORegion { #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_32 0x01 From ec50344230aad67a867ac59e4a0cd7233149484c Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:43 +0900 Subject: [PATCH 16/26] pci: clean up of pci_update_mappings() This patch converts r->size == 0 to !r_size. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci.c b/hw/pci.c index 64cf0a8a50..d6f647cc25 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -733,7 +733,7 @@ static void pci_update_mappings(PCIDevice *d) r = &d->io_regions[i]; /* this region isn't registered */ - if (r->size == 0) + if (!r->size) continue; if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { From 876a350d3daed88c5677397c287c6210cf163f6c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 12 Nov 2009 13:47:17 +0200 Subject: [PATCH 17/26] pci: split up up pci_update mappings Split bar address math into a separate function. In particular, this gets rid of an ugly forward goto into scope that we have there. Signed-off-by: Michael S. Tsirkin Acked-by: Isaku Yamahata --- hw/pci.c | 125 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 57 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index d6f647cc25..49d06489e0 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -721,14 +721,77 @@ static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size, } } +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 >= TARGET_PHYS_ADDR_MAX) { + return PCI_BAR_UNMAPPED; + } + + return new_addr; +} + static void pci_update_mappings(PCIDevice *d) { PCIIORegion *r; - int cmd, i; - pcibus_t last_addr, new_addr; - pcibus_t filtered_size; + int i; + pcibus_t new_addr, filtered_size; - cmd = pci_get_word(d->config + PCI_COMMAND); for(i = 0; i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; @@ -736,59 +799,7 @@ static void pci_update_mappings(PCIDevice *d) if (!r->size) continue; - if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { - if (cmd & PCI_COMMAND_IO) { - new_addr = pci_get_long(d->config + pci_bar(d, i)); - new_addr = new_addr & ~(r->size - 1); - last_addr = new_addr + r->size - 1; - /* NOTE: we have only 64K ioports on PC */ - if (last_addr <= new_addr || new_addr == 0 || - last_addr >= 0x10000) { - new_addr = PCI_BAR_UNMAPPED; - } - } else { - new_addr = PCI_BAR_UNMAPPED; - } - } else { - if (cmd & PCI_COMMAND_MEMORY) { - if (r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { - new_addr = pci_get_quad(d->config + pci_bar(d, i)); - } else { - new_addr = pci_get_long(d->config + pci_bar(d, i)); - } - /* the ROM slot has a specific enable bit */ - if (i == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) - goto no_mem_map; - new_addr = new_addr & ~(r->size - 1); - last_addr = new_addr + r->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 || - - /* Now pcibus_t is 64bit. - * Check if 32 bit BAR wrap around explicitly. - * Without this, PC ide doesn't work well. - * TODO: remove this work around. - */ - (!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) && - last_addr >= UINT32_MAX) || - - /* - * OS is allowed to set BAR beyond its addressable - * bits. For example, 32 bit OS can set 64bit bar - * to >4G. Check it. - */ - last_addr >= TARGET_PHYS_ADDR_MAX) { - new_addr = PCI_BAR_UNMAPPED; - } - } else { - no_mem_map: - new_addr = PCI_BAR_UNMAPPED; - } - } + new_addr = pci_bar_address(d, i, r->type, r->size); /* bridge filtering */ filtered_size = r->size; From b47b0706f15f9427ffc48b0db61f1b6e52b98b2a Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:45 +0900 Subject: [PATCH 18/26] pci: remove magic number, 256 in pci.c This patch replaces magic number, 256, with ARRAY_SIZE(). Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 49d06489e0..6d94286a46 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -487,7 +487,8 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, uint8_t header_type) { if (devfn < 0) { - for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) { + for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices); + devfn += 8) { if (!bus->devices[devfn]) goto found; } @@ -1035,7 +1036,7 @@ static void pci_for_each_device_under_bus(PCIBus *bus, PCIDevice *d; int devfn; - for(devfn = 0; devfn < 256; devfn++) { + for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { d = bus->devices[devfn]; if (d) fn(bus, d); From 10c9c329da60fe64ad24dba6f81044559ff15f9b Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:46 +0900 Subject: [PATCH 19/26] pci: fix pci_config_get_io_base(). fix typo in pci_config_get_io_base(). Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci.c b/hw/pci.c index 6d94286a46..bc566e5945 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -630,7 +630,7 @@ static uint32_t pci_config_get_io_base(PCIDevice *d, 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 + PCI_IO_BASE_UPPER16) << 16; + val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16; } return val; } From d46636b88339ecc2cb8d10113f45ada164817773 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:47 +0900 Subject: [PATCH 20/26] pci: pci bridge related clean up. - fix bridge prefetchable memory accesser to check 64bit or not. - use pcibus_t consistently instead mixing pcibus_t and uint64_t. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 18 +++++++++++------- hw/pci.h | 1 + 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index bc566e5945..e26b3d0341 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -635,19 +635,23 @@ static uint32_t pci_config_get_io_base(PCIDevice *d, return val; } -static uint64_t pci_config_get_memory_base(PCIDevice *d, uint32_t base) +static pcibus_t pci_config_get_memory_base(PCIDevice *d, uint32_t base) { - return ((uint64_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) + return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) << 16; } -static uint64_t pci_config_get_pref_base(PCIDevice *d, +static pcibus_t pci_config_get_pref_base(PCIDevice *d, uint32_t base, uint32_t upper) { - uint64_t val; - val = ((uint64_t)pci_get_word(d->config + base) & - PCI_PREF_RANGE_MASK) << 16; - val |= (uint64_t)pci_get_long(d->config + upper) << 32; + 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; } diff --git a/hw/pci.h b/hw/pci.h index 6a868f95de..0baf69bd5d 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -131,6 +131,7 @@ typedef struct PCIIORegion { #define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ #define PCI_PREF_MEMORY_LIMIT 0x26 #define PCI_PREF_RANGE_MASK (~0x0fUL) +#define PCI_PREF_RANGE_TYPE_64 0x01 #define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ #define PCI_PREF_LIMIT_UPPER32 0x2c #define PCI_SUBSYSTEM_VENDOR_ID 0x2c /* 16 bits */ From 88a9556430df57cbe7666e4e4cf78c3bd3bc8220 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 12 Nov 2009 13:54:31 +0200 Subject: [PATCH 21/26] pci: convert goto into scope in bridge_filter goto into scope is evil. rearrange pci_bridge_filter so that we always go to end of function on error. Signed-off-by: Michael S. Tsirkin Acked-by: Isaku Yamahata --- hw/pci.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index e26b3d0341..8cf008d31d 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -717,13 +717,14 @@ static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size, } if (base > limit) { - no_map: - *addr = PCI_BAR_UNMAPPED; - *size = 0; - } else { - *addr = base; - *size = limit - base + 1; + goto no_map; } + *addr = base; + *size = limit - base + 1; + return; +no_map: + *addr = PCI_BAR_UNMAPPED; + *size = 0; } static pcibus_t pci_bar_address(PCIDevice *d, From b5f28bcaeec3ca54755f24ae665c4028fc598d77 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 24 Nov 2009 16:44:15 +0200 Subject: [PATCH 22/26] msix: add helper to unuse all msix entries will be used by virtio on soft reset Signed-off-by: Michael S. Tsirkin --- hw/msix.c | 7 +++++++ hw/msix.h | 1 + 2 files changed, 8 insertions(+) diff --git a/hw/msix.c b/hw/msix.c index 548ffd5c8b..d49944111f 100644 --- a/hw/msix.c +++ b/hw/msix.c @@ -378,3 +378,10 @@ void msix_vector_unuse(PCIDevice *dev, unsigned vector) if (vector < dev->msix_entries_nr && dev->msix_entry_used[vector]) --dev->msix_entry_used[vector]; } + +void msix_unuse_all_vectors(PCIDevice *dev) +{ + if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) + return; + msix_free_irq_entries(dev); +} diff --git a/hw/msix.h b/hw/msix.h index 39fa568f9c..a9f7993c39 100644 --- a/hw/msix.h +++ b/hw/msix.h @@ -25,6 +25,7 @@ uint32_t msix_bar_size(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); From 1b8e9b274287ea7e2256244e62ed285b7d83e0ad Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 24 Nov 2009 16:45:35 +0200 Subject: [PATCH 23/26] virtio: do not reset msix state on soft reset msix state is managed by OS, not the driver, so it's wrong to touch it on io from driver. Mark all vectors unused instead. Signed-off-by: Michael S. Tsirkin --- hw/virtio-pci.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index aebcf9d0d1..d222ce03fe 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -185,8 +185,10 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case VIRTIO_PCI_QUEUE_PFN: pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; - if (pa == 0) - virtio_pci_reset(&proxy->pci_dev.qdev); + if (pa == 0) { + virtio_reset(proxy->vdev); + msix_unuse_all_vectors(&proxy->pci_dev); + } else virtio_queue_set_addr(vdev, vdev->queue_sel, pa); break; @@ -199,8 +201,10 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case VIRTIO_PCI_STATUS: vdev->status = val & 0xFF; - if (vdev->status == 0) - virtio_pci_reset(&proxy->pci_dev.qdev); + if (vdev->status == 0) { + virtio_reset(proxy->vdev); + msix_unuse_all_vectors(&proxy->pci_dev); + } break; case VIRTIO_MSI_CONFIG_VECTOR: msix_vector_unuse(&proxy->pci_dev, vdev->config_vector); From ae1be0bbc127a9a6289873efdb7cb22c57d81a9d Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 25 Nov 2009 11:41:48 +0200 Subject: [PATCH 24/26] msix: fix mask bit state after reset PCI spec states that mask bit must be 1 after reset. Make it so. Signed-off-by: Michael S. Tsirkin --- hw/msix.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/msix.c b/hw/msix.c index d49944111f..45f83dd716 100644 --- a/hw/msix.c +++ b/hw/msix.c @@ -217,6 +217,15 @@ void msix_mmio_map(PCIDevice *d, int region_num, d->msix_mmio_index); } +static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) +{ + int vector; + for (vector = 0; vector < nentries; ++vector) { + unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL; + dev->msix_table_page[offset] |= MSIX_VECTOR_MASK; + } +} + /* Initialize the MSI-X structures. Note: if MSI-X is supported, BAR size is * modified, it should be retrieved with msix_bar_size. */ int msix_init(struct PCIDevice *dev, unsigned short nentries, @@ -234,6 +243,7 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, sizeof *dev->msix_entry_used); dev->msix_table_page = qemu_mallocz(MSIX_PAGE_SIZE); + msix_mask_all(dev, nentries); dev->msix_mmio_index = cpu_register_io_memory(msix_mmio_read, msix_mmio_write, dev); @@ -353,6 +363,7 @@ void msix_reset(PCIDevice *dev) msix_free_irq_entries(dev); dev->config[dev->msix_cap + MSIX_ENABLE_OFFSET] &= MSIX_ENABLE_MASK; memset(dev->msix_table_page, 0, MSIX_PAGE_SIZE); + msix_mask_all(dev, dev->msix_entries_nr); } /* PCI spec suggests that devices make it possible for software to configure From 1f944c661a821774e7b8cfbf5560a238795f2a60 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 25 Nov 2009 12:00:10 +0200 Subject: [PATCH 25/26] msix: fix reset value for enable bit On reset, we currently clear all bits in msix control register *except* enable bit. This is wrong: the spec says we should clear writeable bits: function mask and enable bit. Correct this. Signed-off-by: Michael S. Tsirkin --- hw/msix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/msix.c b/hw/msix.c index 45f83dd716..785e097d80 100644 --- a/hw/msix.c +++ b/hw/msix.c @@ -361,7 +361,8 @@ void msix_reset(PCIDevice *dev) if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) return; msix_free_irq_entries(dev); - dev->config[dev->msix_cap + MSIX_ENABLE_OFFSET] &= MSIX_ENABLE_MASK; + dev->config[dev->msix_cap + MSIX_ENABLE_OFFSET] &= + ~dev->wmask[dev->msix_cap + MSIX_ENABLE_OFFSET]; memset(dev->msix_table_page, 0, MSIX_PAGE_SIZE); msix_mask_all(dev, dev->msix_entries_nr); } From 98304c846d8866dae6322ef400ce6595b23cfc41 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 25 Nov 2009 12:24:14 +0200 Subject: [PATCH 26/26] msix: clear pending bit of an unused vector PCI spec states: if a masked vector has its Pending bit set, and the associated underlying interrupt events are somehow satisfied (usually by software though the exact manner is function-specific), the function must clear the Pending bit, to avoid sending a spurious interrupt message later when software unmasks the vector. In our case this happens if vector becomes unused. Clear pending bit in this case. Signed-off-by: Michael S. Tsirkin --- hw/msix.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/hw/msix.c b/hw/msix.c index 785e097d80..4bc6147234 100644 --- a/hw/msix.c +++ b/hw/msix.c @@ -105,14 +105,6 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries, 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; -} - /* Handle MSI-X capability config write. */ void msix_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len) @@ -271,6 +263,16 @@ err_index: return ret; } +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); + } +} + /* Clean up resources for the device. */ int msix_uninit(PCIDevice *dev) { @@ -387,8 +389,13 @@ int msix_vector_use(PCIDevice *dev, unsigned vector) /* Mark vector as unused. */ void msix_vector_unuse(PCIDevice *dev, unsigned vector) { - if (vector < dev->msix_entries_nr && dev->msix_entry_used[vector]) - --dev->msix_entry_used[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)