From patchwork Fri Oct 29 15:27:20 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 290522 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o9TFRqvE011458 for ; Fri, 29 Oct 2010 15:27:54 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932854Ab0J2P11 (ORCPT ); Fri, 29 Oct 2010 11:27:27 -0400 Received: from mx1.redhat.com ([209.132.183.28]:16084 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932776Ab0J2P1Y (ORCPT ); Fri, 29 Oct 2010 11:27:24 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o9TFRLDm013174 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 29 Oct 2010 11:27:21 -0400 Received: from s20.home (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id o9TFRKLF010325; Fri, 29 Oct 2010 11:27:20 -0400 From: Alex Williamson Subject: [PATCH] pci: Add callbacks to support retreiving and updating interrupts To: qemu-devel@nongnu.org, mst@redhat.com Cc: kvm@vger.kernel.org, alex.williamson@redhat.com, chrisw@redhat.com, ddutile@redhat.com Date: Fri, 29 Oct 2010 09:27:20 -0600 Message-ID: <20101029152703.9046.17453.stgit@s20.home> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Fri, 29 Oct 2010 15:27:54 +0000 (UTC) diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 0ecac55..47ff0d9 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -336,8 +336,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, d = FROM_SYSBUS(APBState, s); d->bus = pci_register_bus(&d->busdev.qdev, "pci", - pci_apb_set_irq, pci_pbm_map_irq, d, - 0, 32); + pci_apb_set_irq, NULL, + pci_pbm_map_irq, d, 0, 32); pci_bus_set_mem_base(d->bus, mem_base); for (i = 0; i < 32; i++) { diff --git a/hw/bonito.c b/hw/bonito.c index dcf0311..d2869bb 100644 --- a/hw/bonito.c +++ b/hw/bonito.c @@ -772,7 +772,7 @@ PCIBus *bonito_init(qemu_irq *pic) dev = qdev_create(NULL, "Bonito-pcihost"); pcihost = FROM_SYSBUS(BonitoState, sysbus_from_qdev(dev)); b = pci_register_bus(&pcihost->busdev.qdev, "pci", pci_bonito_set_irq, - pci_bonito_map_irq, pic, 0x28, 32); + NULL, pci_bonito_map_irq, pic, 0x28, 32); pcihost->bus = b; qdev_init_nofail(dev); diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 91c755f..e747d7e 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -89,7 +89,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) s = sysbus_from_qdev(dev); d = FROM_SYSBUS(GrackleState, s); d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", - pci_grackle_set_irq, + pci_grackle_set_irq, NULL, pci_grackle_map_irq, pic, 0, 4); diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index cabf7ea..2a0fc4a 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -1114,8 +1114,9 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) s->pci = qemu_mallocz(sizeof(GT64120PCIState)); s->pci->bus = pci_register_bus(NULL, "pci", - pci_gt64120_set_irq, pci_gt64120_map_irq, - pic, PCI_DEVFN(18, 0), 4); + pci_gt64120_set_irq, NULL, + pci_gt64120_map_irq, pic, + PCI_DEVFN(18, 0), 4); s->ISD_handle = cpu_register_io_memory(gt64120_read, gt64120_write, s); d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice), 0, NULL, NULL); diff --git a/hw/pci.c b/hw/pci.c index 1280d4d..645b119 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -41,6 +41,7 @@ struct PCIBus { BusState qbus; int devfn_min; pci_set_irq_fn set_irq; + pci_get_irq_fn get_irq; pci_map_irq_fn map_irq; pci_hotplug_fn hotplug; DeviceState *hotplug_qdev; @@ -139,6 +140,23 @@ static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); } +int pci_get_irq(PCIDevice *pci_dev, int pin) +{ + PCIBus *bus; + for (;;) { + if (!pci_dev) + return -ENOSYS; + bus = pci_dev->bus; + if (!bus) + return -ENOSYS; + pin = bus->map_irq(pci_dev, pin); + if (bus->get_irq) + break; + pci_dev = bus->parent_dev; + } + return bus->get_irq(bus->irq_opaque, pin); +} + /* Update interrupt status bit in config space on interrupt * state change. */ static void pci_update_irq_status(PCIDevice *dev) @@ -260,10 +278,11 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min) return bus; } -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *irq_opaque, int nirq) +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_get_irq_fn get_irq, + pci_map_irq_fn map_irq, void *irq_opaque, int nirq) { bus->set_irq = set_irq; + bus->get_irq = get_irq; bus->map_irq = map_irq; bus->irq_opaque = irq_opaque; bus->nirq = nirq; @@ -283,13 +302,14 @@ void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base) } PCIBus *pci_register_bus(DeviceState *parent, const char *name, - pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *irq_opaque, int devfn_min, int nirq) + pci_set_irq_fn set_irq, pci_get_irq_fn get_irq, + pci_map_irq_fn map_irq, void *irq_opaque, + int devfn_min, int nirq) { PCIBus *bus; bus = pci_bus_new(parent, name, devfn_min); - pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq); + pci_bus_irqs(bus, set_irq, get_irq, map_irq, irq_opaque, nirq); return bus; } @@ -1541,6 +1561,28 @@ typedef struct { uint32_t did; } PCIBridge; +void pci_register_update_irqs(PCIDevice *d, PCIUpdateIRQs *update_irqs) +{ + d->update_irqs = update_irqs; +} + +static void pci_bridge_update_irqs_fn(PCIBus *b, PCIDevice *d) +{ + if (d->update_irqs) { + d->update_irqs(d); + } +} + +void pci_bridge_update_irqs(PCIBus *b) +{ + PCIBus *child; + + pci_for_each_device_under_bus(b, pci_bridge_update_irqs_fn); + + QLIST_FOREACH(child, &b->child, sibling) { + pci_bridge_update_irqs(child); + } +} static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d) { diff --git a/hw/pci.h b/hw/pci.h index 3d23f03..1502dc1 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -77,6 +77,7 @@ typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, uint32_t address, uint32_t data, int len); typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, uint32_t address, int len); +typedef void PCIUpdateIRQs(PCIDevice *pci_dev); typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type); typedef int PCIUnregisterFunc(PCIDevice *pci_dev); @@ -141,6 +142,7 @@ struct PCIDevice { /* do not access the following fields */ PCIConfigReadFunc *config_read; PCIConfigWriteFunc *config_write; + PCIUpdateIRQs *update_irqs; /* IRQ objects for the INTA-INTD pins. */ qemu_irq *irq; @@ -201,18 +203,24 @@ void pci_default_write_config(PCIDevice *d, void pci_device_save(PCIDevice *s, QEMUFile *f); int pci_device_load(PCIDevice *s, QEMUFile *f); +int pci_get_irq(PCIDevice *pci_dev, int pin); + typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); +typedef int (*pci_get_irq_fn)(void *opaque, int irq_num); typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, int state); void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, int devfn_min); PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min); -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *irq_opaque, int nirq); +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_get_irq_fn get_irq, + pci_map_irq_fn map_irq, void *irq_opaque, int nirq); +void pci_bridge_update_irqs(PCIBus *bus); +void pci_register_update_irqs(PCIDevice *pci_dev, PCIUpdateIRQs *update_irqs); void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev); PCIBus *pci_register_bus(DeviceState *parent, const char *name, - pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *irq_opaque, int devfn_min, int nirq); + pci_set_irq_fn set_irq, pci_get_irq_fn get_irq, + pci_map_irq_fn map_irq, void *irq_opaque, + int devfn_min, int nirq); void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base); diff --git a/hw/piix_pci.c b/hw/piix_pci.c index b5589b9..8c3f845 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -55,7 +55,10 @@ struct PCII440FXState { #define I440FX_PAM_SIZE 7 #define I440FX_SMRAM 0x72 +#define PIIX_CONFIG_IRQ_ROUTE 0x60 + static void piix3_set_irq(void *opaque, int irq_num, int level); +static int piix3_get_irq(void *opaque, int irq_num); /* return the global irq number corresponding to a given device irq pin. We could also use the bus number to have a more precise @@ -236,7 +239,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq * piix3 = DO_UPCAST(PIIX3State, dev, pci_create_simple_multifunction(b, -1, true, "PIIX3")); piix3->pic = pic; - pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, 4); + pci_bus_irqs(b, piix3_set_irq, piix3_get_irq, pci_slot_get_pirq, piix3, 4); (*pi440fx_state)->piix3 = piix3; *piix3_devfn = piix3->dev.devfn; @@ -273,6 +276,13 @@ static void piix3_set_irq(void *opaque, int irq_num, int level) } } +static int piix3_get_irq(void *opaque, int irq_num) +{ + PIIX3State *piix3 = opaque; + + return piix3->dev.config[0x60 + irq_num]; +} + static void piix3_reset(void *opaque) { PIIX3State *d = opaque; @@ -311,6 +321,16 @@ static void piix3_reset(void *opaque) pci_conf[0xae] = 0x00; memset(d->pci_irq_levels, 0, sizeof(d->pci_irq_levels)); + pci_bridge_update_irqs(d->dev.bus); +} + +static void piix3_write_config(PCIDevice *dev, + uint32_t address, uint32_t val, int len) +{ + pci_default_write_config(dev, address, val, len); + if (ranges_overlap(address, len, PIIX_CONFIG_IRQ_ROUTE, 4)) { + pci_bridge_update_irqs(dev->bus); + } } static const VMStateDescription vmstate_piix3 = { @@ -357,6 +377,7 @@ static PCIDeviceInfo i440fx_info[] = { .qdev.vmsd = &vmstate_piix3, .qdev.no_user = 1, .init = piix3_initfn, + .config_write = piix3_write_config, },{ /* end of list */ } diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index 6e437e7..5f3faf7 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -358,7 +358,7 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4], controller = qemu_mallocz(sizeof(PPC4xxPCIState)); controller->pci_state.bus = pci_register_bus(NULL, "pci", - ppc4xx_pci_set_irq, + ppc4xx_pci_set_irq, NULL, ppc4xx_pci_map_irq, pci_irqs, 0, 4); diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 8ac99f2..a6e64d4 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -277,7 +277,7 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers) controller = qemu_mallocz(sizeof(PPCE500PCIState)); controller->pci_state.bus = pci_register_bus(NULL, "pci", - mpc85xx_pci_set_irq, + mpc85xx_pci_set_irq, NULL, mpc85xx_pci_map_irq, pci_irqs, PCI_DEVFN(0x11, 0), 4); diff --git a/hw/prep_pci.c b/hw/prep_pci.c index 0c2afe9..d2e5c4b 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -118,7 +118,7 @@ PCIBus *pci_prep_init(qemu_irq *pic) s = qemu_mallocz(sizeof(PREPPCIState)); s->bus = pci_register_bus(NULL, "pci", - prep_set_irq, prep_map_irq, pic, 0, 4); + prep_set_irq, NULL, prep_map_irq, pic, 0, 4); pci_host_conf_register_ioport(0xcf8, s); diff --git a/hw/sh_pci.c b/hw/sh_pci.c index cc2f190..b39c78b 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -99,7 +99,7 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, p = qemu_mallocz(sizeof(SHPCIC)); p->bus = pci_register_bus(NULL, "pci", - set_irq, map_irq, opaque, devfn_min, nirq); + set_irq, NULL, map_irq, opaque, devfn_min, nirq); p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice), -1, NULL, NULL); diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 1310211..ec2f246 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -229,8 +229,9 @@ PCIBus *pci_pmac_init(qemu_irq *pic) s = sysbus_from_qdev(dev); d = FROM_SYSBUS(UNINState, s); d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", - pci_unin_set_irq, pci_unin_map_irq, - pic, PCI_DEVFN(11, 0), 4); + pci_unin_set_irq, NULL, + pci_unin_map_irq, pic, + PCI_DEVFN(11, 0), 4); #if 0 pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north"); @@ -281,8 +282,9 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic) d = FROM_SYSBUS(UNINState, s); d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", - pci_unin_set_irq, pci_unin_map_irq, - pic, PCI_DEVFN(11, 0), 4); + pci_unin_set_irq, NULL, + pci_unin_map_irq, pic, + PCI_DEVFN(11, 0), 4); sysbus_mmio_map(s, 0, 0xf0800000); sysbus_mmio_map(s, 1, 0xf0c00000); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index a76bdfa..7f85e77 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -126,7 +126,7 @@ static int pci_vpb_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq[i]); } bus = pci_register_bus(&dev->qdev, "pci", - pci_vpb_set_irq, pci_vpb_map_irq, s->irq, + pci_vpb_set_irq, NULL, pci_vpb_map_irq, s->irq, PCI_DEVFN(11, 0), 4); /* ??? Register memory space. */