qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 61/61] pc_q35: apic mode for pci interrupt routing.


From: Isaku Yamahata
Subject: [Qemu-devel] [PATCH 61/61] pc_q35: apic mode for pci interrupt routing.
Date: Wed, 30 Sep 2009 19:18:37 +0900

apic mode for pci interrupt routing.

Signed-off-by: Isaku Yamahata <address@hidden>
---
 hw/pc_q35.c |    4 +-
 hw/q35.c    |   87 +++++++++++++++++++++++++++++++++++++++++++++++-----------
 hw/q35.h    |    6 +++-
 3 files changed, 77 insertions(+), 20 deletions(-)

diff --git a/hw/pc_q35.c b/hw/pc_q35.c
index 9980a39..105b97b 100644
--- a/hw/pc_q35.c
+++ b/hw/pc_q35.c
@@ -132,10 +132,10 @@ static void pc_q35_init(ram_addr_t ram_size,
     i8259 = i8259_init(cpu_irq[0]);
     isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
     isa_irq_state->i8259 = i8259;
-    isa_irq_state->ioapic = ioapic_init();
     isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
 
-    host_bus = gmch_init(&gmch_state, isa_irq, &ich9_lpc_devfn);
+    host_bus = gmch_init(&gmch_state, isa_irq, &ich9_lpc_devfn,
+                         &isa_irq_state->ioapic);
 
     isa_bus_irqs(isa_irq);
     pc_register_ferr_irq(isa_reserve_irq(13));
diff --git a/hw/q35.c b/hw/q35.c
index 05267ea..06dbdf9 100644
--- a/hw/q35.c
+++ b/hw/q35.c
@@ -59,6 +59,7 @@ struct ICH9_LPCState {
     /* ICH9 LPC PCI to ISA bridge */
     PCIDevice d;
 
+    int apic_mode;
     int pci_irq_levels[ICH9_LPC_NB_PIRQS];
 
     APMState apm;
@@ -68,6 +69,7 @@ struct ICH9_LPCState {
 struct ICH9_LPCIrqState {
     struct ICH9_LPCState *lpc;
     qemu_irq *pic;
+    qemu_irq *ioapic;
 };
 
 typedef struct GMCHState {
@@ -154,12 +156,42 @@ static void gmch_update_pcixbar(struct GMCH_PCIState *gs)
 static struct ICH9_LPCState *ich9_lpc_init(PCIBus *bus, int devfn, struct 
ICH9_LPCIrqState *irq_state);
 static void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
 
+static void ich9_lpc_ioapic_update_fn(void *opaque, int reset)
+{
+    struct ICH9_LPCIrqState *irq_state = opaque;
+    struct ICH9_LPCState *ich9_lpc = irq_state->lpc;
+
+    /* this can be called via gmch_init() where ich9_lpc isn't
+       allocated yet */
+    if (ich9_lpc == NULL)
+        return;
+
+    if (reset)
+        ich9_lpc->apic_mode = 0;
+    else
+        ich9_lpc->apic_mode = 1;
+}
+
 /* return the global irq number corresponding to a given device irq
-   pin. We could also use the bus number to have a more precise
-   mapping. */
-static int pci_slot_get_pirq(void *opaque, PCIDevice *pci_dev, int irq_num)
+   pin.
+   pic mode: LNKx
+   apic mode: gsi
+   We could also use the bus number/device to have a more precise mapping. */
+static int pci_slot_map_irq(void *opaque, PCIDevice *pci_dev, int irq_num)
 {
-    return pci_swizzle_map_irq_fn(NULL, pci_dev, irq_num);
+    struct ICH9_LPCIrqState *irq_state = opaque;
+    struct ICH9_LPCState *lpc = irq_state->lpc;
+    int pin = pci_swizzle_map_irq_fn(NULL, pci_dev, irq_num);
+
+    if (!lpc->apic_mode) {
+        /* INTA -> INKA, ...
+           this would be device wise... */
+        return pin;
+    }
+
+    /* APIC mode INTA -> 16, ...
+       this would be device wise... */
+    return pin + ICH9_LPC_PIC_NUM_PINS;
 }
 
 /* PAM */
@@ -385,24 +417,30 @@ static int gmch_initfn(PCIDevice *d)
 }
 
 /* host bridge */
-PCIBus *gmch_init(PCIDevice **pgmch_state, qemu_irq *pic, int *ich9_lpc_devfn)
+PCIBus *gmch_init(PCIDevice **pgmch_state, qemu_irq *pic, int *ich9_lpc_devfn,
+                  qemu_irq **ioapic)
 {
     DeviceState *dev;
     GMCHState *s;
     PCIBus *b;
     PCIDevice *d;
     struct GMCH_PCIState *gs;
-    struct ICH9_LPCIrqState *irq_state = qemu_malloc(sizeof(*irq_state));
+    struct ICH9_LPCIrqState *irq_state = qemu_mallocz(sizeof(*irq_state));
 
     irq_state->pic = pic;
     dev = qdev_create(NULL, "gmch-pcihost");
     s = gmchstate_from_sysbus(sysbus_from_qdev(dev));
     b = pci_register_bus(dev, "pci.0",
-                         ich9_lpc_set_irq, pci_slot_get_pirq, irq_state, 0,
+                         ich9_lpc_set_irq, pci_slot_map_irq, irq_state, 0,
                          24 /* 24 pin IO APIC */);
     s->host.pci.bus = b;
     qdev_init(dev);
 
+    *ioapic = ioapic_init_with_mre(ICH9_LPC_IOAPIC_NUM_PINS,
+                                   ich9_lpc_ioapic_update_fn,
+                                   irq_state);
+    irq_state->ioapic = *ioapic;
+
     d = pci_create_simple(b, 0, "gmch");
     s->dev = d;
     gs = DO_UPCAST(struct GMCH_PCIState, d, d);
@@ -554,11 +592,10 @@ static void ich9_lpc_pic_irq(struct ICH9_LPCState *lpc, 
int irq_num,
     abort();
 }
 
-static void ich9_lpc_set_irq(void *opaque, int irq_num, int level)
+/* irq_num = LNKx: 0 = LNKA, ... */
+static void ich9_lpc_set_irq_pic(struct ICH9_LPCState *ich9_lpc,
+                                 qemu_irq *pic, int irq_num, int level)
 {
-    struct ICH9_LPCIrqState *irq_state = opaque;
-    struct ICH9_LPCState *ich9_lpc = irq_state->lpc;
-    qemu_irq *pic = irq_state->pic;
     int i, pic_level;
     int pic_irq;
     int pic_dis;
@@ -569,16 +606,11 @@ static void ich9_lpc_set_irq(void *opaque, int irq_num, 
int level)
     /* now we change the pic irq level according to
        the ich9 lpc irq mappings */
     ich9_lpc_pic_irq(ich9_lpc, irq_num, &pic_irq, &pic_dis);
+    assert(pic_irq < ICH9_LPC_PIC_NUM_PINS);
     if (pic_dis) {
         return;
     }
 
-    if (pic_irq > 24) {
-        fprintf(stderr, "%s: error irq_num %d pic_irq %d\n",
-                __func__, irq_num, pic_irq);
-        return;
-    }
-
     /* The pic level is the logical OR of all the PCI irqs mapped to it */
     pic_level = 0;
     for (i = 0; i < ICH9_LPC_NB_PIRQS; i++) {
@@ -592,6 +624,27 @@ static void ich9_lpc_set_irq(void *opaque, int irq_num, 
int level)
     qemu_set_irq(pic[pic_irq], pic_level);
 }
 
+/* irq_num = GSI */
+static void ich9_lpc_set_irq_apic(struct ICH9_LPCState *ich9_lpc,
+                                  qemu_irq *ioapic, int irq_num, int level)
+{
+    assert(irq_num < ICH9_LPC_IOAPIC_NUM_PINS);
+    qemu_set_irq(ioapic[irq_num], level);
+}
+
+/* pic mode:  irq_num = LNKx
+   apic mode: irq_num = GSI */
+static void ich9_lpc_set_irq(void *opaque, int irq_num, int level)
+{
+    struct ICH9_LPCIrqState *irq_state = opaque;
+    struct ICH9_LPCState *ich9_lpc = irq_state->lpc;
+
+    if (ich9_lpc->apic_mode)
+        ich9_lpc_set_irq_apic(ich9_lpc, irq_state->ioapic, irq_num, level);
+    else
+        ich9_lpc_set_irq_pic(ich9_lpc, irq_state->pic, irq_num, level);
+}
+
 /* APM */
 static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
 {
diff --git a/hw/q35.h b/hw/q35.h
index a3a97b5..2f68152 100644
--- a/hw/q35.h
+++ b/hw/q35.h
@@ -25,7 +25,8 @@
 #include "acpi_ich9.h"
 
 void gmch_init_memory_mappings(PCIDevice *d);
-PCIBus *gmch_init(PCIDevice **pgmch_state, qemu_irq *pic, int *ich9_lpc_devfn);
+PCIBus *gmch_init(PCIDevice **pgmch_state, qemu_irq *pic, int *ich9_lpc_devfn,
+                  qemu_irq **ioapic);
 
 PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int secondary_bus_num);
 
@@ -176,6 +177,9 @@ void ich9_hot_add_init(struct ich9_lpc_pm_regs *pm);
 #define  ICH9_LPC_RCBA_EN                       0x1
 #define  ICH9_LPC_RCBA_DEFAULT                  0x0
 
+#define ICH9_LPC_PIC_NUM_PINS                   16
+#define ICH9_LPC_IOAPIC_NUM_PINS                24
+
 /* D30:F1 power management I/O registers
    offset from the address ICH9_LPC_PMBASE */
 
-- 
1.6.0.2





reply via email to

[Prev in Thread] Current Thread [Next in Thread]