diff mbox

ich9: add support for pci assignment

Message ID 20130123020429.28329.65700.stgit@bling.home
State New
Headers show

Commit Message

Alex Williamson Jan. 23, 2013, 2:11 a.m. UTC
Fills out support for the pci assignment API.  Added:

PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)

Add calls to pci_bus_fire_intx_routing_notifier() when routing changes
are made.

From: Jason Baron <jbaron@redhat.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---

Jason posted this back in October, there were no comments.  Updated
and tested for latest tree.  Currently attempting to use -device
pci-assign with q35 results in:

qemu-system-x86_64: -device pci-assign,host=b:00.0,addr=6: PCI: Bug - unimplemented PCI INTx routing (q35-pcihost)

This allows it to work.  Note that there's a seabios bug for option
ROMs making use of interrupts, hopefully we can also pull that fix
in for 1.4, but guests not relying on bios programming of the PCI
interrupt line value should work fine.

 hw/ich9.h     |    1 +
 hw/lpc_ich9.c |   33 +++++++++++++++++++++++++++++++++
 hw/pc_q35.c   |    1 +
 3 files changed, 35 insertions(+)

Comments

Michael S. Tsirkin Jan. 23, 2013, 10:08 a.m. UTC | #1
On Tue, Jan 22, 2013 at 07:11:37PM -0700, Alex Williamson wrote:
> Fills out support for the pci assignment API.  Added:
> 
> PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)
> 
> Add calls to pci_bus_fire_intx_routing_notifier() when routing changes
> are made.
> 
> From: Jason Baron <jbaron@redhat.com>
> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>

Anthony any objection if I keep merging these things?
You wanted to be in control when the bulk of the q35
work was being merged but I'm guessing it's ok now?

> ---
> 
> Jason posted this back in October, there were no comments.  Updated
> and tested for latest tree.  Currently attempting to use -device
> pci-assign with q35 results in:
> 
> qemu-system-x86_64: -device pci-assign,host=b:00.0,addr=6: PCI: Bug - unimplemented PCI INTx routing (q35-pcihost)
> 
> This allows it to work.  Note that there's a seabios bug for option
> ROMs making use of interrupts, hopefully we can also pull that fix
> in for 1.4, but guests not relying on bios programming of the PCI
> interrupt line value should work fine.
> 
>  hw/ich9.h     |    1 +
>  hw/lpc_ich9.c |   33 +++++++++++++++++++++++++++++++++
>  hw/pc_q35.c   |    1 +
>  3 files changed, 35 insertions(+)
> 
> diff --git a/hw/ich9.h b/hw/ich9.h
> index b8d8e6d..d4509bb 100644
> --- a/hw/ich9.h
> +++ b/hw/ich9.h
> @@ -18,6 +18,7 @@
>  
>  void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
>  int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
> +PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
>  void ich9_lpc_pm_init(PCIDevice *pci_lpc, qemu_irq cmos_s3);
>  PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus);
>  i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
> diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c
> index 16843d7..e25689b 100644
> --- a/hw/lpc_ich9.c
> +++ b/hw/lpc_ich9.c
> @@ -158,6 +158,7 @@ static void ich9_cc_write(void *opaque, hwaddr addr,
>  
>      ich9_cc_addr_len(&addr, &len);
>      memcpy(lpc->chip_config + addr, &val, len);
> +    pci_bus_fire_intx_routing_notifier(lpc->d.bus);
>      ich9_cc_update(lpc);
>  }
>  
> @@ -286,6 +287,32 @@ int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx)
>      return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx];
>  }
>  
> +PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)
> +{
> +    ICH9LPCState *lpc = opaque;
> +    PCIINTxRoute route;
> +    int pic_irq;
> +    int pic_dis;
> +
> +    assert(0 <= pirq_pin);
> +    assert(pirq_pin < ICH9_LPC_NB_PIRQS);
> +
> +    route.mode = PCI_INTX_ENABLED;
> +    ich9_lpc_pic_irq(lpc, pirq_pin, &pic_irq, &pic_dis);
> +    if (!pic_dis) {
> +        if (pic_irq < ICH9_LPC_PIC_NUM_PINS) {
> +            route.irq = pic_irq;
> +        } else {
> +            route.mode = PCI_INTX_DISABLED;
> +            route.irq = -1;
> +        }
> +    } else {
> +        route.irq = ich9_pirq_to_gsi(pirq_pin);
> +    }
> +
> +    return route;
> +}
> +
>  static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
>  {
>      switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
> @@ -405,6 +432,12 @@ static void ich9_lpc_config_write(PCIDevice *d,
>      if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) {
>          ich9_lpc_rcba_update(lpc, rbca_old);
>      }
> +    if (ranges_overlap(addr, len, ICH9_LPC_PIRQA_ROUT, 4)) {
> +        pci_bus_fire_intx_routing_notifier(lpc->d.bus);
> +    }
> +    if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) {
> +        pci_bus_fire_intx_routing_notifier(lpc->d.bus);
> +    }
>  }
>  
>  static void ich9_lpc_reset(DeviceState *qdev)
> diff --git a/hw/pc_q35.c b/hw/pc_q35.c
> index d82353e..6f5ff8d 100644
> --- a/hw/pc_q35.c
> +++ b/hw/pc_q35.c
> @@ -147,6 +147,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
>      ich9_lpc->ioapic = gsi_state->ioapic_irq;
>      pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc,
>                   ICH9_LPC_NB_PIRQS);
> +    pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq);
>      isa_bus = ich9_lpc->isa_bus;
>  
>      /*end early*/
Michael S. Tsirkin Jan. 23, 2013, 3:41 p.m. UTC | #2
On Tue, Jan 22, 2013 at 07:11:37PM -0700, Alex Williamson wrote:
> Fills out support for the pci assignment API.  Added:
> 
> PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)
> 
> Add calls to pci_bus_fire_intx_routing_notifier() when routing changes
> are made.
> 
> From: Jason Baron <jbaron@redhat.com>
> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>

Applied, thanks for repost (note for the future: it's preferable put
the From: at top of the commit log, this way git am knows to pick it up).

> ---
> 
> Jason posted this back in October, there were no comments.  Updated
> and tested for latest tree.  Currently attempting to use -device
> pci-assign with q35 results in:
> 
> qemu-system-x86_64: -device pci-assign,host=b:00.0,addr=6: PCI: Bug - unimplemented PCI INTx routing (q35-pcihost)
> 
> This allows it to work.  Note that there's a seabios bug for option
> ROMs making use of interrupts, hopefully we can also pull that fix
> in for 1.4, but guests not relying on bios programming of the PCI
> interrupt line value should work fine.
> 
>  hw/ich9.h     |    1 +
>  hw/lpc_ich9.c |   33 +++++++++++++++++++++++++++++++++
>  hw/pc_q35.c   |    1 +
>  3 files changed, 35 insertions(+)
> 
> diff --git a/hw/ich9.h b/hw/ich9.h
> index b8d8e6d..d4509bb 100644
> --- a/hw/ich9.h
> +++ b/hw/ich9.h
> @@ -18,6 +18,7 @@
>  
>  void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
>  int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
> +PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
>  void ich9_lpc_pm_init(PCIDevice *pci_lpc, qemu_irq cmos_s3);
>  PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus);
>  i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
> diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c
> index 16843d7..e25689b 100644
> --- a/hw/lpc_ich9.c
> +++ b/hw/lpc_ich9.c
> @@ -158,6 +158,7 @@ static void ich9_cc_write(void *opaque, hwaddr addr,
>  
>      ich9_cc_addr_len(&addr, &len);
>      memcpy(lpc->chip_config + addr, &val, len);
> +    pci_bus_fire_intx_routing_notifier(lpc->d.bus);
>      ich9_cc_update(lpc);
>  }
>  
> @@ -286,6 +287,32 @@ int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx)
>      return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx];
>  }
>  
> +PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)
> +{
> +    ICH9LPCState *lpc = opaque;
> +    PCIINTxRoute route;
> +    int pic_irq;
> +    int pic_dis;
> +
> +    assert(0 <= pirq_pin);
> +    assert(pirq_pin < ICH9_LPC_NB_PIRQS);
> +
> +    route.mode = PCI_INTX_ENABLED;
> +    ich9_lpc_pic_irq(lpc, pirq_pin, &pic_irq, &pic_dis);
> +    if (!pic_dis) {
> +        if (pic_irq < ICH9_LPC_PIC_NUM_PINS) {
> +            route.irq = pic_irq;
> +        } else {
> +            route.mode = PCI_INTX_DISABLED;
> +            route.irq = -1;
> +        }
> +    } else {
> +        route.irq = ich9_pirq_to_gsi(pirq_pin);
> +    }
> +
> +    return route;
> +}
> +
>  static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
>  {
>      switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
> @@ -405,6 +432,12 @@ static void ich9_lpc_config_write(PCIDevice *d,
>      if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) {
>          ich9_lpc_rcba_update(lpc, rbca_old);
>      }
> +    if (ranges_overlap(addr, len, ICH9_LPC_PIRQA_ROUT, 4)) {
> +        pci_bus_fire_intx_routing_notifier(lpc->d.bus);
> +    }
> +    if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) {
> +        pci_bus_fire_intx_routing_notifier(lpc->d.bus);
> +    }
>  }
>  
>  static void ich9_lpc_reset(DeviceState *qdev)
> diff --git a/hw/pc_q35.c b/hw/pc_q35.c
> index d82353e..6f5ff8d 100644
> --- a/hw/pc_q35.c
> +++ b/hw/pc_q35.c
> @@ -147,6 +147,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
>      ich9_lpc->ioapic = gsi_state->ioapic_irq;
>      pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc,
>                   ICH9_LPC_NB_PIRQS);
> +    pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq);
>      isa_bus = ich9_lpc->isa_bus;
>  
>      /*end early*/
diff mbox

Patch

diff --git a/hw/ich9.h b/hw/ich9.h
index b8d8e6d..d4509bb 100644
--- a/hw/ich9.h
+++ b/hw/ich9.h
@@ -18,6 +18,7 @@ 
 
 void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
 int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
+PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
 void ich9_lpc_pm_init(PCIDevice *pci_lpc, qemu_irq cmos_s3);
 PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus);
 i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c
index 16843d7..e25689b 100644
--- a/hw/lpc_ich9.c
+++ b/hw/lpc_ich9.c
@@ -158,6 +158,7 @@  static void ich9_cc_write(void *opaque, hwaddr addr,
 
     ich9_cc_addr_len(&addr, &len);
     memcpy(lpc->chip_config + addr, &val, len);
+    pci_bus_fire_intx_routing_notifier(lpc->d.bus);
     ich9_cc_update(lpc);
 }
 
@@ -286,6 +287,32 @@  int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx)
     return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx];
 }
 
+PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)
+{
+    ICH9LPCState *lpc = opaque;
+    PCIINTxRoute route;
+    int pic_irq;
+    int pic_dis;
+
+    assert(0 <= pirq_pin);
+    assert(pirq_pin < ICH9_LPC_NB_PIRQS);
+
+    route.mode = PCI_INTX_ENABLED;
+    ich9_lpc_pic_irq(lpc, pirq_pin, &pic_irq, &pic_dis);
+    if (!pic_dis) {
+        if (pic_irq < ICH9_LPC_PIC_NUM_PINS) {
+            route.irq = pic_irq;
+        } else {
+            route.mode = PCI_INTX_DISABLED;
+            route.irq = -1;
+        }
+    } else {
+        route.irq = ich9_pirq_to_gsi(pirq_pin);
+    }
+
+    return route;
+}
+
 static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
 {
     switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
@@ -405,6 +432,12 @@  static void ich9_lpc_config_write(PCIDevice *d,
     if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) {
         ich9_lpc_rcba_update(lpc, rbca_old);
     }
+    if (ranges_overlap(addr, len, ICH9_LPC_PIRQA_ROUT, 4)) {
+        pci_bus_fire_intx_routing_notifier(lpc->d.bus);
+    }
+    if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) {
+        pci_bus_fire_intx_routing_notifier(lpc->d.bus);
+    }
 }
 
 static void ich9_lpc_reset(DeviceState *qdev)
diff --git a/hw/pc_q35.c b/hw/pc_q35.c
index d82353e..6f5ff8d 100644
--- a/hw/pc_q35.c
+++ b/hw/pc_q35.c
@@ -147,6 +147,7 @@  static void pc_q35_init(QEMUMachineInitArgs *args)
     ich9_lpc->ioapic = gsi_state->ioapic_irq;
     pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc,
                  ICH9_LPC_NB_PIRQS);
+    pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq);
     isa_bus = ich9_lpc->isa_bus;
 
     /*end early*/