From 393a98924eb00df76231384b86652e1d5f964d67 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 4 Jun 2012 16:56:01 +0200 Subject: msix: drop unused msix_bar_size, require valid bar_size No user in sight for msix_bar_size. bar_size for all users is aligned, let's simply require this instead of trying to fix up invalid input. Signed-off-by: Jan Kiszka Signed-off-by: Michael S. Tsirkin --- hw/pci.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'hw/pci.h') diff --git a/hw/pci.h b/hw/pci.h index c3cacce046..3d534e77ae 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -226,8 +226,6 @@ struct PCIDevice { MemoryRegion msix_mmio; /* Reference-count for entries actually in use by driver. */ unsigned *msix_entry_used; - /* Region including the MSI-X table */ - uint32_t msix_bar_size; /* MSIX function mask set or MSIX disabled */ bool msix_function_masked; /* Version id needed for VMState */ -- cgit v1.2.3-55-g7522 From 53f949254ad2435bfd45cb0dee96f246a0bdd7e3 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Jun 2012 12:15:51 -0600 Subject: msix: Add simple BAR allocation MSIX setup functions msi_init() takes over a BAR without really specifying or allowing specification of how it does so. Instead, let's split it into two interfaces, one fully specified, and one trivially easy. This implements the latter. msix_init_exclusive_bar() takes over allocating and filling a PCI BAR _exclusively_ for the use of MSIX. When used, the matching msi_uninit_exclusive_bar() should be used to tear it down. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/msix.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ hw/msix.h | 3 +++ hw/pci.h | 2 ++ 3 files changed, 52 insertions(+) (limited to 'hw/pci.h') diff --git a/hw/msix.c b/hw/msix.c index b64f109326..bafea94084 100644 --- a/hw/msix.c +++ b/hw/msix.c @@ -299,6 +299,45 @@ err_config: return ret; } +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_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2) + + if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) { + return -EINVAL; + } + + if (asprintf(&name, "%s-msix", dev->name) == -1) { + return -ENOMEM; + } + + memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE); + + free(name); + + ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr, + MSIX_EXCLUSIVE_BAR_SIZE); + 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; @@ -329,6 +368,14 @@ int msix_uninit(PCIDevice *dev, MemoryRegion *bar) return 0; } +void msix_uninit_exclusive_bar(PCIDevice *dev) +{ + if (msix_present(dev)) { + msix_uninit(dev, &dev->msix_exclusive_bar); + memory_region_destroy(&dev->msix_exclusive_bar); + } +} + void msix_save(PCIDevice *dev, QEMUFile *f) { unsigned n = dev->msix_entries_nr; diff --git a/hw/msix.h b/hw/msix.h index 4a17f94540..f681bb0855 100644 --- a/hw/msix.h +++ b/hw/msix.h @@ -7,10 +7,13 @@ int msix_init(PCIDevice *pdev, unsigned short nentries, MemoryRegion *bar, unsigned bar_nr, unsigned bar_size); +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); int msix_uninit(PCIDevice *d, MemoryRegion *bar); +void msix_uninit_exclusive_bar(PCIDevice *dev); unsigned int msix_nr_vectors_allocated(const PCIDevice *dev); diff --git a/hw/pci.h b/hw/pci.h index 3d534e77ae..7344891706 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -222,6 +222,8 @@ struct PCIDevice { /* Space to store MSIX table */ uint8_t *msix_table_page; + /* MemoryRegion container for msix exclusive BAR setup */ + MemoryRegion msix_exclusive_bar; /* MMIO index used to map MSIX table and pending bit entries. */ MemoryRegion msix_mmio; /* Reference-count for entries actually in use by driver. */ -- cgit v1.2.3-55-g7522 From d35e428c8400f9ddc07e5a15ff19622c869b9ba0 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Jun 2012 12:16:37 -0600 Subject: msix: Split PBA into it's own MemoryRegion These don't have to be contiguous. Size them to only what they need and use separate MemoryRegions for the vector table and PBA. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/msix.c | 106 +++++++++++++++++++++++++++++++++++++++----------------------- hw/pci.h | 10 +++--- 2 files changed, 73 insertions(+), 43 deletions(-) (limited to 'hw/pci.h') diff --git a/hw/msix.c b/hw/msix.c index 87d316a580..33121398e8 100644 --- a/hw/msix.c +++ b/hw/msix.c @@ -37,7 +37,7 @@ static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) { - uint8_t *table_entry = dev->msix_table_page + vector * PCI_MSIX_ENTRY_SIZE; + 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); @@ -93,7 +93,7 @@ static uint8_t msix_pending_mask(int vector) static uint8_t *msix_pending_byte(PCIDevice *dev, int vector) { - return dev->msix_table_page + MSIX_PAGE_PENDING + vector / 8; + return dev->msix_pba + vector / 8; } static int msix_is_pending(PCIDevice *dev, int vector) @@ -114,7 +114,7 @@ static void msix_clr_pending(PCIDevice *dev, int 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_page[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT; + return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT; } static bool msix_is_masked(PCIDevice *dev, int vector) @@ -193,37 +193,47 @@ void msix_write_config(PCIDevice *dev, uint32_t addr, } } -static uint64_t msix_mmio_read(void *opaque, target_phys_addr_t addr, - unsigned size) +static uint64_t msix_table_mmio_read(void *opaque, target_phys_addr_t addr, + unsigned size) { PCIDevice *dev = opaque; - unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3; - void *page = dev->msix_table_page; - return pci_get_long(page + offset); + return pci_get_long(dev->msix_table + addr); } -static void msix_mmio_write(void *opaque, target_phys_addr_t addr, - uint64_t val, unsigned size) +static void msix_table_mmio_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned size) { PCIDevice *dev = opaque; - unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3; - int vector = offset / PCI_MSIX_ENTRY_SIZE; + int vector = addr / PCI_MSIX_ENTRY_SIZE; bool was_masked; - /* MSI-X page includes a read-only PBA and a writeable Vector Control. */ - if (vector >= dev->msix_entries_nr) { - return; - } - was_masked = msix_is_masked(dev, vector); - pci_set_long(dev->msix_table_page + offset, val); + pci_set_long(dev->msix_table + addr, val); msix_handle_mask_update(dev, vector, was_masked); } -static const MemoryRegionOps msix_mmio_ops = { - .read = msix_mmio_read, - .write = msix_mmio_write, +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, target_phys_addr_t 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 = { @@ -236,11 +246,14 @@ static void msix_mmio_setup(PCIDevice *d, MemoryRegion *bar) { uint8_t *config = d->config + d->msix_cap; uint32_t table = pci_get_long(config + PCI_MSIX_TABLE); - uint32_t offset = table & ~(MSIX_PAGE_SIZE - 1); + uint32_t table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK; + uint32_t pba = pci_get_long(config + PCI_MSIX_PBA); + uint32_t pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK; /* TODO: for assigned devices, we'll want to make it possible to map * pending bits separately in case they are in a separate bar. */ - memory_region_add_subregion(bar, offset, &d->msix_mmio); + memory_region_add_subregion(bar, table_offset, &d->msix_table_mmio); + memory_region_add_subregion(bar, pba_offset, &d->msix_pba_mmio); } static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) @@ -252,7 +265,7 @@ static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; bool was_masked = msix_is_masked(dev, vector); - dev->msix_table_page[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT; + dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT; msix_handle_mask_update(dev, vector, was_masked); } } @@ -264,6 +277,7 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, unsigned bar_nr, unsigned bar_size) { int ret; + unsigned table_size, pba_size; /* Nothing to do if MSI is not supported by interrupt controller */ if (!msi_supported) { @@ -272,14 +286,20 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, if (nentries > MSIX_MAX_ENTRIES) return -EINVAL; + table_size = nentries * PCI_MSIX_ENTRY_SIZE; + pba_size = QEMU_ALIGN_UP(nentries, 64) / 8; + dev->msix_entry_used = g_malloc0(MSIX_MAX_ENTRIES * sizeof *dev->msix_entry_used); - dev->msix_table_page = g_malloc0(MSIX_PAGE_SIZE); + dev->msix_table = g_malloc0(table_size); + dev->msix_pba = g_malloc0(pba_size); msix_mask_all(dev, nentries); - memory_region_init_io(&dev->msix_mmio, &msix_mmio_ops, dev, - "msix", MSIX_PAGE_SIZE); + memory_region_init_io(&dev->msix_table_mmio, &msix_table_mmio_ops, dev, + "msix-table", table_size); + memory_region_init_io(&dev->msix_pba_mmio, &msix_pba_mmio_ops, dev, + "msix-pba", pba_size); dev->msix_entries_nr = nentries; ret = msix_add_config(dev, nentries, bar_nr, bar_size); @@ -292,9 +312,12 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, err_config: dev->msix_entries_nr = 0; - memory_region_destroy(&dev->msix_mmio); - g_free(dev->msix_table_page); - dev->msix_table_page = NULL; + memory_region_destroy(&dev->msix_pba_mmio); + g_free(dev->msix_pba); + dev->msix_pba = NULL; + 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; return ret; @@ -359,10 +382,14 @@ int msix_uninit(PCIDevice *dev, MemoryRegion *bar) dev->msix_cap = 0; msix_free_irq_entries(dev); dev->msix_entries_nr = 0; - memory_region_del_subregion(bar, &dev->msix_mmio); - memory_region_destroy(&dev->msix_mmio); - g_free(dev->msix_table_page); - dev->msix_table_page = NULL; + memory_region_del_subregion(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(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; @@ -385,8 +412,8 @@ void msix_save(PCIDevice *dev, QEMUFile *f) return; } - qemu_put_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE); - qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8); + 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. */ @@ -400,8 +427,8 @@ void msix_load(PCIDevice *dev, QEMUFile *f) } msix_free_irq_entries(dev); - qemu_get_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE); - qemu_get_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8); + 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++) { @@ -448,7 +475,8 @@ void msix_reset(PCIDevice *dev) msix_free_irq_entries(dev); dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &= ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET]; - memset(dev->msix_table_page, 0, MSIX_PAGE_SIZE); + 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); } diff --git a/hw/pci.h b/hw/pci.h index 7344891706..44ae8715b0 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -220,12 +220,14 @@ struct PCIDevice { /* MSI-X entries */ int msix_entries_nr; - /* Space to store MSIX table */ - uint8_t *msix_table_page; + /* 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; - /* MMIO index used to map MSIX table and pending bit entries. */ - MemoryRegion msix_mmio; + /* 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 */ -- cgit v1.2.3-55-g7522 From f90c2bcdbc69e41e575f868b984c3e2de8f51bac Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 3 Jul 2012 22:39:27 -0600 Subject: pci: convert PCIUnregisterFunc to void Not a single driver has any possibility of failure on their exit function, let's keep it that way. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/ac97.c | 3 +-- hw/e1000.c | 3 +-- hw/eepro100.c | 3 +-- hw/es1370.c | 3 +-- hw/ide/cmd646.c | 4 +--- hw/ide/ich.c | 4 +--- hw/ide/piix.c | 4 +--- hw/ide/via.c | 4 +--- hw/intel-hda.c | 3 +-- hw/ioh3420.c | 8 +++----- hw/ivshmem.c | 4 +--- hw/lsi53c895a.c | 4 +--- hw/ne2000.c | 3 +-- hw/pci.c | 8 +++----- hw/pci.h | 2 +- hw/pci_bridge.c | 3 +-- hw/pci_bridge.h | 2 +- hw/pci_bridge_dev.c | 13 +++++-------- hw/pcnet-pci.c | 3 +-- hw/rtl8139.c | 3 +-- hw/usb/hcd-uhci.c | 3 +-- hw/virtio-pci.c | 23 +++++++++++------------ hw/wdt_i6300esb.c | 4 +--- hw/xio3130_downstream.c | 8 +++----- hw/xio3130_upstream.c | 8 +++----- 25 files changed, 47 insertions(+), 83 deletions(-) (limited to 'hw/pci.h') diff --git a/hw/ac97.c b/hw/ac97.c index e791b9d3e6..0f561fa5c1 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -1319,13 +1319,12 @@ static int ac97_initfn (PCIDevice *dev) return 0; } -static int ac97_exitfn (PCIDevice *dev) +static void ac97_exitfn (PCIDevice *dev) { AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev); memory_region_destroy (&s->io_nam); memory_region_destroy (&s->io_nabm); - return 0; } int ac97_init (PCIBus *bus) diff --git a/hw/e1000.c b/hw/e1000.c index 4573f1301e..6c5bc44e8c 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1192,7 +1192,7 @@ e1000_cleanup(VLANClientState *nc) s->nic = NULL; } -static int +static void pci_e1000_uninit(PCIDevice *dev) { E1000State *d = DO_UPCAST(E1000State, dev, dev); @@ -1202,7 +1202,6 @@ pci_e1000_uninit(PCIDevice *dev) memory_region_destroy(&d->mmio); memory_region_destroy(&d->io); qemu_del_vlan_client(&d->nic->nc); - return 0; } static NetClientInfo net_e1000_info = { diff --git a/hw/eepro100.c b/hw/eepro100.c index 6279ae36ec..9745ad592e 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1831,7 +1831,7 @@ static void nic_cleanup(VLANClientState *nc) s->nic = NULL; } -static int pci_nic_uninit(PCIDevice *pci_dev) +static void pci_nic_uninit(PCIDevice *pci_dev) { EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev); @@ -1841,7 +1841,6 @@ static int pci_nic_uninit(PCIDevice *pci_dev) vmstate_unregister(&pci_dev->qdev, s->vmstate, s); eeprom93xx_free(&pci_dev->qdev, s->eeprom); qemu_del_vlan_client(&s->nic->nc); - return 0; } static NetClientInfo net_eepro100_info = { diff --git a/hw/es1370.c b/hw/es1370.c index 573f747362..e34234c350 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -1018,12 +1018,11 @@ static int es1370_initfn (PCIDevice *dev) return 0; } -static int es1370_exitfn (PCIDevice *dev) +static void es1370_exitfn (PCIDevice *dev) { ES1370State *s = DO_UPCAST (ES1370State, dev, dev); memory_region_destroy (&s->io); - return 0; } int es1370_init (PCIBus *bus) diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index bf8ece4708..4ff3624aa9 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -295,7 +295,7 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev) return 0; } -static int pci_cmd646_ide_exitfn(PCIDevice *dev) +static void pci_cmd646_ide_exitfn(PCIDevice *dev) { PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); unsigned i; @@ -309,8 +309,6 @@ static int pci_cmd646_ide_exitfn(PCIDevice *dev) memory_region_destroy(&d->cmd646_bar[i].data); } memory_region_destroy(&d->bmdma_bar); - - return 0; } void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table, diff --git a/hw/ide/ich.c b/hw/ide/ich.c index e3eaaea882..c3a425b22f 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -132,15 +132,13 @@ static int pci_ich9_ahci_init(PCIDevice *dev) return 0; } -static int pci_ich9_uninit(PCIDevice *dev) +static void pci_ich9_uninit(PCIDevice *dev) { struct AHCIPCIState *d; d = DO_UPCAST(struct AHCIPCIState, card, dev); msi_uninit(dev); ahci_uninit(&d->ahci); - - return 0; } static void ich_ahci_class_init(ObjectClass *klass, void *data) diff --git a/hw/ide/piix.c b/hw/ide/piix.c index bcaa400e2d..455c1b2698 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -199,7 +199,7 @@ PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn) return dev; } -static int pci_piix_ide_exitfn(PCIDevice *dev) +static void pci_piix_ide_exitfn(PCIDevice *dev) { PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); unsigned i; @@ -211,8 +211,6 @@ static int pci_piix_ide_exitfn(PCIDevice *dev) memory_region_destroy(&d->bmdma[i].addr_ioport); } memory_region_destroy(&d->bmdma_bar); - - return 0; } /* hd_table must contain 4 block drivers */ diff --git a/hw/ide/via.c b/hw/ide/via.c index eec5136019..3e25085d42 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -189,7 +189,7 @@ static int vt82c686b_ide_initfn(PCIDevice *dev) return 0; } -static int vt82c686b_ide_exitfn(PCIDevice *dev) +static void vt82c686b_ide_exitfn(PCIDevice *dev) { PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); unsigned i; @@ -201,8 +201,6 @@ static int vt82c686b_ide_exitfn(PCIDevice *dev) memory_region_destroy(&d->bmdma[i].addr_ioport); } memory_region_destroy(&d->bmdma_bar); - - return 0; } void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn) diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 8f3b70bd14..04bed5e894 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -1144,13 +1144,12 @@ static int intel_hda_init(PCIDevice *pci) return 0; } -static int intel_hda_exit(PCIDevice *pci) +static void intel_hda_exit(PCIDevice *pci) { IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci); msi_uninit(&d->pci); memory_region_destroy(&d->mmio); - return 0; } static int intel_hda_post_load(void *opaque, int version) diff --git a/hw/ioh3420.c b/hw/ioh3420.c index 0a2601cac4..94a537c9b3 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -96,7 +96,6 @@ static int ioh3420_initfn(PCIDevice *d) PCIEPort *p = DO_UPCAST(PCIEPort, br, br); PCIESlot *s = DO_UPCAST(PCIESlot, port, p); int rc; - int tmp; rc = pci_bridge_initfn(d); if (rc < 0) { @@ -144,12 +143,11 @@ err_pcie_cap: err_msi: msi_uninit(d); err_bridge: - tmp = pci_bridge_exitfn(d); - assert(!tmp); + pci_bridge_exitfn(d); return rc; } -static int ioh3420_exitfn(PCIDevice *d) +static void ioh3420_exitfn(PCIDevice *d) { PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); PCIEPort *p = DO_UPCAST(PCIEPort, br, br); @@ -159,7 +157,7 @@ static int ioh3420_exitfn(PCIDevice *d) pcie_chassis_del_slot(s); pcie_cap_exit(d); msi_uninit(d); - return pci_bridge_exitfn(d); + pci_bridge_exitfn(d); } PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction, diff --git a/hw/ivshmem.c b/hw/ivshmem.c index 8b49eee8e9..7d4123cc38 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -760,7 +760,7 @@ static int pci_ivshmem_init(PCIDevice *dev) return 0; } -static int pci_ivshmem_uninit(PCIDevice *dev) +static void pci_ivshmem_uninit(PCIDevice *dev) { IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev); @@ -775,8 +775,6 @@ static int pci_ivshmem_uninit(PCIDevice *dev) memory_region_destroy(&s->ivshmem); memory_region_destroy(&s->bar); unregister_savevm(&dev->qdev, "ivshmem", s); - - return 0; } static Property ivshmem_properties[] = { diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index f022a02447..9205f659fe 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -2070,15 +2070,13 @@ static const VMStateDescription vmstate_lsi_scsi = { } }; -static int lsi_scsi_uninit(PCIDevice *d) +static void lsi_scsi_uninit(PCIDevice *d) { LSIState *s = DO_UPCAST(LSIState, dev, d); memory_region_destroy(&s->mmio_io); memory_region_destroy(&s->ram_io); memory_region_destroy(&s->io_io); - - return 0; } static const struct SCSIBusInfo lsi_scsi_info = { diff --git a/hw/ne2000.c b/hw/ne2000.c index d02e60c4a6..afadbdbac1 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -744,14 +744,13 @@ static int pci_ne2000_init(PCIDevice *pci_dev) return 0; } -static int pci_ne2000_exit(PCIDevice *pci_dev) +static void pci_ne2000_exit(PCIDevice *pci_dev) { PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev); NE2000State *s = &d->ne2000; memory_region_destroy(&s->io); qemu_del_vlan_client(&s->nic->nc); - return 0; } static Property ne2000_properties[] = { diff --git a/hw/pci.c b/hw/pci.c index d5c664c9cd..f783362ae3 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -837,12 +837,10 @@ static int pci_unregister_device(DeviceState *dev) { PCIDevice *pci_dev = PCI_DEVICE(dev); PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); - int ret = 0; - if (pc->exit) - ret = pc->exit(pci_dev); - if (ret) - return ret; + if (pc->exit) { + pc->exit(pci_dev); + } pci_unregister_io_regions(pci_dev); pci_del_option_rom(pci_dev); diff --git a/hw/pci.h b/hw/pci.h index 44ae8715b0..6983b2f57a 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -85,7 +85,7 @@ 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 int PCIUnregisterFunc(PCIDevice *pci_dev); +typedef void PCIUnregisterFunc(PCIDevice *pci_dev); typedef struct PCIIORegion { pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c index e0832b4a67..0125fd95fc 100644 --- a/hw/pci_bridge.c +++ b/hw/pci_bridge.c @@ -333,7 +333,7 @@ int pci_bridge_initfn(PCIDevice *dev) } /* default qdev clean up function for PCI-to-PCI bridge */ -int pci_bridge_exitfn(PCIDevice *pci_dev) +void pci_bridge_exitfn(PCIDevice *pci_dev) { PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); assert(QLIST_EMPTY(&s->sec_bus.child)); @@ -342,7 +342,6 @@ int pci_bridge_exitfn(PCIDevice *pci_dev) memory_region_destroy(&s->address_space_mem); memory_region_destroy(&s->address_space_io); /* qbus_free() is called automatically by qdev_free() */ - return 0; } /* diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h index 84411a69dc..a00accc172 100644 --- a/hw/pci_bridge.h +++ b/hw/pci_bridge.h @@ -44,7 +44,7 @@ void pci_bridge_reset_reg(PCIDevice *dev); void pci_bridge_reset(DeviceState *qdev); int pci_bridge_initfn(PCIDevice *pci_dev); -int pci_bridge_exitfn(PCIDevice *pci_dev); +void pci_bridge_exitfn(PCIDevice *pci_dev); /* diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index 1cc1d2049c..f7063961a0 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -52,7 +52,8 @@ static int pci_bridge_dev_initfn(PCIDevice *dev) { PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br); - int err, ret; + int err; + pci_bridge_map_irq(br, NULL, pci_bridge_dev_map_irq_fn); err = pci_bridge_initfn(dev); if (err) { @@ -86,26 +87,22 @@ slotid_error: shpc_cleanup(dev, &bridge_dev->bar); shpc_error: memory_region_destroy(&bridge_dev->bar); - ret = pci_bridge_exitfn(dev); - assert(!ret); + pci_bridge_exitfn(dev); bridge_error: return err; } -static int pci_bridge_dev_exitfn(PCIDevice *dev) +static void pci_bridge_dev_exitfn(PCIDevice *dev) { PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br); - int ret; if (msi_present(dev)) { msi_uninit(dev); } slotid_cap_cleanup(dev); shpc_cleanup(dev, &bridge_dev->bar); memory_region_destroy(&bridge_dev->bar); - ret = pci_bridge_exitfn(dev); - assert(!ret); - return 0; + pci_bridge_exitfn(dev); } static void pci_bridge_dev_write_config(PCIDevice *d, diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 34d73aaea1..5439db3494 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -271,7 +271,7 @@ static void pci_pcnet_cleanup(VLANClientState *nc) pcnet_common_cleanup(d); } -static int pci_pcnet_uninit(PCIDevice *dev) +static void pci_pcnet_uninit(PCIDevice *dev) { PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev); @@ -280,7 +280,6 @@ static int pci_pcnet_uninit(PCIDevice *dev) qemu_del_timer(d->state.poll_timer); qemu_free_timer(d->state.poll_timer); qemu_del_vlan_client(&d->state.nic->nc); - return 0; } static NetClientInfo net_pci_pcnet_info = { diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 060404c137..a7a3f27084 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3427,7 +3427,7 @@ static void rtl8139_cleanup(VLANClientState *nc) s->nic = NULL; } -static int pci_rtl8139_uninit(PCIDevice *dev) +static void pci_rtl8139_uninit(PCIDevice *dev) { RTL8139State *s = DO_UPCAST(RTL8139State, dev, dev); @@ -3440,7 +3440,6 @@ static int pci_rtl8139_uninit(PCIDevice *dev) qemu_del_timer(s->timer); qemu_free_timer(s->timer); qemu_del_vlan_client(&s->nic->nc); - return 0; } static NetClientInfo net_rtl8139_info = { diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 9e211a0bb4..04aabd9aac 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -1233,12 +1233,11 @@ static int usb_uhci_vt82c686b_initfn(PCIDevice *dev) return usb_uhci_common_initfn(dev); } -static int usb_uhci_exit(PCIDevice *dev) +static void usb_uhci_exit(PCIDevice *dev) { UHCIState *s = DO_UPCAST(UHCIState, dev, dev); memory_region_destroy(&s->io_bar); - return 0; } static Property uhci_properties[] = { diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 3dca37ff0c..6ed21b75c8 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -828,22 +828,21 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev) return 0; } -static int virtio_exit_pci(PCIDevice *pci_dev) +static void virtio_exit_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); memory_region_destroy(&proxy->bar); msix_uninit_exclusive_bar(pci_dev); - return 0; } -static int virtio_blk_exit_pci(PCIDevice *pci_dev) +static void virtio_blk_exit_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); virtio_pci_stop_ioeventfd(proxy); virtio_blk_exit(proxy->vdev); - return virtio_exit_pci(pci_dev); + virtio_exit_pci(pci_dev); } static int virtio_serial_init_pci(PCIDevice *pci_dev) @@ -868,13 +867,13 @@ static int virtio_serial_init_pci(PCIDevice *pci_dev) return 0; } -static int virtio_serial_exit_pci(PCIDevice *pci_dev) +static void virtio_serial_exit_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); virtio_pci_stop_ioeventfd(proxy); virtio_serial_exit(proxy->vdev); - return virtio_exit_pci(pci_dev); + virtio_exit_pci(pci_dev); } static int virtio_net_init_pci(PCIDevice *pci_dev) @@ -892,13 +891,13 @@ static int virtio_net_init_pci(PCIDevice *pci_dev) return 0; } -static int virtio_net_exit_pci(PCIDevice *pci_dev) +static void virtio_net_exit_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); virtio_pci_stop_ioeventfd(proxy); virtio_net_exit(proxy->vdev); - return virtio_exit_pci(pci_dev); + virtio_exit_pci(pci_dev); } static int virtio_balloon_init_pci(PCIDevice *pci_dev) @@ -919,13 +918,13 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev) return 0; } -static int virtio_balloon_exit_pci(PCIDevice *pci_dev) +static void virtio_balloon_exit_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); virtio_pci_stop_ioeventfd(proxy); virtio_balloon_exit(proxy->vdev); - return virtio_exit_pci(pci_dev); + virtio_exit_pci(pci_dev); } static Property virtio_blk_properties[] = { @@ -1074,12 +1073,12 @@ static int virtio_scsi_init_pci(PCIDevice *pci_dev) return 0; } -static int virtio_scsi_exit_pci(PCIDevice *pci_dev) +static void virtio_scsi_exit_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); virtio_scsi_exit(proxy->vdev); - return virtio_exit_pci(pci_dev); + virtio_exit_pci(pci_dev); } static Property virtio_scsi_properties[] = { diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index 15c69db932..4a83474906 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -411,13 +411,11 @@ static int i6300esb_init(PCIDevice *dev) return 0; } -static int i6300esb_exit(PCIDevice *dev) +static void i6300esb_exit(PCIDevice *dev) { I6300State *d = DO_UPCAST(I6300State, dev, dev); memory_region_destroy(&d->io_mem); - - return 0; } static WatchdogTimerModel model = { diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index 56d1b353d0..0d8a5e7020 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -60,7 +60,6 @@ static int xio3130_downstream_initfn(PCIDevice *d) PCIEPort *p = DO_UPCAST(PCIEPort, br, br); PCIESlot *s = DO_UPCAST(PCIESlot, port, p); int rc; - int tmp; rc = pci_bridge_initfn(d); if (rc < 0) { @@ -108,12 +107,11 @@ err_pcie_cap: err_msi: msi_uninit(d); err_bridge: - tmp = pci_bridge_exitfn(d); - assert(!tmp); + pci_bridge_exitfn(d); return rc; } -static int xio3130_downstream_exitfn(PCIDevice *d) +static void xio3130_downstream_exitfn(PCIDevice *d) { PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); PCIEPort *p = DO_UPCAST(PCIEPort, br, br); @@ -123,7 +121,7 @@ static int xio3130_downstream_exitfn(PCIDevice *d) pcie_chassis_del_slot(s); pcie_cap_exit(d); msi_uninit(d); - return pci_bridge_exitfn(d); + pci_bridge_exitfn(d); } PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction, diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index 79725813a2..d46b86c74d 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -56,7 +56,6 @@ static int xio3130_upstream_initfn(PCIDevice *d) PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); PCIEPort *p = DO_UPCAST(PCIEPort, br, br); int rc; - int tmp; rc = pci_bridge_initfn(d); if (rc < 0) { @@ -95,17 +94,16 @@ err: err_msi: msi_uninit(d); err_bridge: - tmp = pci_bridge_exitfn(d); - assert(!tmp); + pci_bridge_exitfn(d); return rc; } -static int xio3130_upstream_exitfn(PCIDevice *d) +static void xio3130_upstream_exitfn(PCIDevice *d) { pcie_aer_exit(d); pcie_cap_exit(d); msi_uninit(d); - return pci_bridge_exitfn(d); + pci_bridge_exitfn(d); } PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction, -- cgit v1.2.3-55-g7522 From 3afa9bb488ea981d39255a25aaeb85eeafda41cb Mon Sep 17 00:00:00 2001 From: Michael S. Tsirkin Date: Thu, 19 Jul 2012 17:11:47 +0300 Subject: pci: Add pci_device_route_intx_to_irq Device assigned on KVM needs to know the mode (enabled/inverted/disabled) and the IRQ number that a given device triggers in the attached interrupt controller. Add a PCI IRQ path discovery function that walks from a given device to the host bridge, and gets this information. For this purpose, a host bridge callback function is introduced: route_intx_to_irq. It is so far only implemented by the PIIX3, other host bridges can be added later on as required. Will be used for KVM PCI device assignment and VFIO. Based on patch by Jan Kiszka, with minor tweaks. Signed-off-by: Jan Kiszka Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 20 ++++++++++++++++++++ hw/pci.h | 12 ++++++++++++ hw/pci_internals.h | 1 + hw/piix_pci.c | 18 ++++++++++++++++++ 4 files changed, 51 insertions(+) (limited to 'hw/pci.h') diff --git a/hw/pci.c b/hw/pci.c index ef7607e177..e80599f058 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1066,6 +1066,26 @@ static void pci_set_irq(void *opaque, int irq_num, int level) 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); + assert(bus->route_intx_to_irq); + return bus->route_intx_to_irq(bus->irq_opaque, pin); +} + /***********************************************************/ /* monitor info on PCI */ diff --git a/hw/pci.h b/hw/pci.h index 6983b2f57a..7f7f88c6b9 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -141,6 +141,15 @@ enum { #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; @@ -278,6 +287,7 @@ 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, @@ -306,6 +316,8 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, 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); void pci_device_reset(PCIDevice *dev); void pci_bus_reset(PCIBus *bus); diff --git a/hw/pci_internals.h b/hw/pci_internals.h index 96690b72d3..d704704833 100644 --- a/hw/pci_internals.h +++ b/hw/pci_internals.h @@ -19,6 +19,7 @@ struct PCIBus { 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; diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 09e84f59b6..8ece07c182 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -89,6 +89,7 @@ struct PCII440FXState { #define I440FX_SMRAM 0x72 static void piix3_set_irq(void *opaque, int pirq, int level); +static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx); static void piix3_write_config_xen(PCIDevice *dev, uint32_t address, uint32_t val, int len); @@ -315,6 +316,7 @@ static PCIBus *i440fx_common_init(const char *device_name, pci_create_simple_multifunction(b, -1, true, "PIIX3")); pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, PIIX_NUM_PIRQS); + pci_bus_set_route_irq_fn(b, piix3_route_intx_pin_to_irq); } piix3->pic = pic; *isa_bus = DO_UPCAST(ISABus, qbus, @@ -386,6 +388,22 @@ static void piix3_set_irq(void *opaque, int pirq, int level) piix3_set_irq_level(piix3, pirq, level); } +static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) +{ + PIIX3State *piix3 = opaque; + int irq = piix3->dev.config[PIIX_PIRQC + pin]; + PCIINTxRoute route; + + if (irq < PIIX_NUM_PIC_IRQS) { + route.mode = PCI_INTX_ENABLED; + route.irq = irq; + } else { + route.mode = PCI_INTX_DISABLED; + route.irq = -1; + } + return route; +} + /* irq routing is changed. so rebuild bitmap */ static void piix3_update_irq_levels(PIIX3State *piix3) { -- cgit v1.2.3-55-g7522 From 0ae1625177aba9ac70beb1556615530ddb18086d Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 2 Jul 2012 14:38:47 +0200 Subject: pci: Add INTx routing notifier This per-device notifier shall be triggered by any interrupt router along the path of a device's legacy interrupt signal on routing changes. For simplicity reasons and as this is a slow path anyway, no further details on the routing changes are provided. Instead, the callback is expected to use pci_device_route_intx_to_irq to check the effect of the change. Will be used by KVM PCI device assignment and VFIO. Signed-off-by: Jan Kiszka Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 23 +++++++++++++++++++++++ hw/pci.h | 7 +++++++ hw/piix_pci.c | 2 ++ 3 files changed, 32 insertions(+) (limited to 'hw/pci.h') diff --git a/hw/pci.c b/hw/pci.c index e80599f058..94601f28f9 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1086,6 +1086,29 @@ PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) return bus->route_intx_to_irq(bus->irq_opaque, pin); } +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; +} + /***********************************************************/ /* monitor info on PCI */ diff --git a/hw/pci.h b/hw/pci.h index 7f7f88c6b9..e96e8a7e54 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -182,6 +182,7 @@ typedef struct PCIDeviceClass { 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); @@ -259,6 +260,9 @@ struct PCIDevice { 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; @@ -318,6 +322,9 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, 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); +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); diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 8ece07c182..c497a014af 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -423,6 +423,8 @@ static void piix3_write_config(PCIDevice *dev, if (ranges_overlap(address, len, PIIX_PIRQC, 4)) { PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev); int pic_irq; + + pci_bus_fire_intx_routing_notifier(piix3->dev.bus); piix3_update_irq_levels(piix3); for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) { piix3_set_irq_pic(piix3, pic_irq); -- cgit v1.2.3-55-g7522