[OpenBIOS] [PATCH 4/4] pci.c: move openpic interrupt mapping to post-PCI-bus scan

Mark Cave-Ayland mark.cave-ayland at ilande.co.uk
Thu Nov 13 13:19:54 CET 2014


Move the interrupt mapping from the pre-scan pci_host_set_interrupt_map()
to the post-scan ob_pci_host_set_interrupt_map() function.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>
---
 openbios-devel/drivers/pci.c |  146 +++++++++++++++++++++---------------------
 1 file changed, 72 insertions(+), 74 deletions(-)

diff --git a/openbios-devel/drivers/pci.c b/openbios-devel/drivers/pci.c
index 09e601c..629a652 100644
--- a/openbios-devel/drivers/pci.c
+++ b/openbios-devel/drivers/pci.c
@@ -417,70 +417,6 @@ static void pci_set_bus_range(const pci_config_t *config)
 	set_property(dev, "bus-range", (char *)props, 2 * sizeof(props[0]));
 }
 
-/* Convert device/irq pin to interrupt property */
-#define SUN4U_INTERRUPT(dev, irq_pin) \
-            ((((dev >> 11) << 2) + irq_pin - 1) & 0x1f)
-
-static void pci_host_set_interrupt_map(phandle_t dev)
-{
-/* XXX We currently have a hook in the MPIC init code to fill in its handle.
- *     If you want to have interrupt maps for your PCI host bus, add your
- *     architecture to the #if and make your bridge detect code fill in its
- *     handle too.
- *
- *     It would be great if someone clever could come up with a more universal
- *     mechanism here.
- */
-#if defined(CONFIG_PPC)
-	u32 props[7 * 8];
-	int i;
-
-	/* Oldworld macs do interrupt maps differently */
-	if(!is_newworld())
-		return;
-
-	for (i = 0; i < (7*8); i+=7) {
-		props[i+PCI_INT_MAP_PCI0] = 0;
-		props[i+PCI_INT_MAP_PCI1] = 0;
-		props[i+PCI_INT_MAP_PCI2] = 0;
-		props[i+PCI_INT_MAP_PCI_INT] = (i / 7) + 1; // starts at PINA=1
-		props[i+PCI_INT_MAP_PIC_HANDLE] = 0; // gets patched in later
-		props[i+PCI_INT_MAP_PIC_INT] = arch->irqs[i / 7];
-		props[i+PCI_INT_MAP_PIC_POL] = 3;
-	}
-	set_property(dev, "interrupt-map", (char *)props, 7 * 8 * sizeof(props[0]));
-
-	props[PCI_INT_MAP_PCI0] = 0;
-	props[PCI_INT_MAP_PCI1] = 0;
-	props[PCI_INT_MAP_PCI2] = 0;
-	props[PCI_INT_MAP_PCI_INT] = 0x7;
-
-	set_property(dev, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0]));
-#elif defined(CONFIG_SPARC64)
-	uint32_t props[12];
-	int ncells, device, i;
-
-	/* Set interrupt-map for devices 4 (NE2000) and 5 (CMD646) */
-	ncells = 0;
-	for (i = 4; i <= 5; i++) {
-		device = i << 11;
-
-		ncells += pci_encode_phys_addr(props + ncells, 0, 0, device, 0, 0);
-		props[ncells++] = 1;
-		props[ncells++] = dev;
-		props[ncells++] = SUN4U_INTERRUPT(device, 1);
-	}
-
-	set_property(dev, "interrupt-map", (char *)props, ncells * sizeof(props[0]));
-
-	props[0] = 0x0000f800;
-	props[1] = 0x0;
-	props[2] = 0x0;
-	props[3] = 7;
-	set_property(dev, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0]));
-#endif
-}
-
 static void pci_host_set_reg(phandle_t phandle)
 {
     phandle_t dev = phandle;
@@ -547,7 +483,6 @@ int host_config_cb(const pci_config_t *config)
 	//XXX this overrides "reg" property
 	pci_host_set_reg(get_cur_dev());
 	pci_host_set_ranges(config);
-	pci_host_set_interrupt_map(get_cur_dev());
 
 	return 0;
 }
@@ -1436,20 +1371,26 @@ static void ob_pci_set_available(phandle_t host, unsigned long mem_base, unsigne
     set_property(host, "available", (char *)props, ncells * sizeof(props[0]));
 }
 
+/* Convert device/irq pin to interrupt property */
+#define SUN4U_INTERRUPT(dev, irq_pin) \
+            ((((dev >> 11) << 2) + irq_pin - 1) & 0x1f)
+
 static void ob_pci_host_set_interrupt_map(phandle_t host)
 {
-#if defined(CONFIG_PPC)
     phandle_t dnode = 0;
+    u32 props[128];
+    int i;
+
+#if defined(CONFIG_PPC)
     phandle_t target_node;
-    u32 *interrupt_map;
-    int len, i;
 
     /* Oldworld macs do interrupt maps differently */
     if (!is_newworld())
         return;
 
-    /* patch in interrupt parent */
-    while ((dnode = dt_iterate_type(dnode, "open-pic"))) {
+    dnode = dt_iterate_type(0, "open-pic");
+    if (dnode) {
+        /* patch in openpic interrupt-parent properties */
         target_node = find_dev("/pci/mac-io");
         set_int_property(target_node, "interrupt-parent", dnode);
 
@@ -1477,12 +1418,69 @@ static void ob_pci_host_set_interrupt_map(phandle_t host)
         target_node = find_dev("/pci");
         set_int_property(target_node, "interrupt-parent", dnode);
 
-        interrupt_map = (u32 *)get_property(target_node, "interrupt-map", &len);
-        for (i = 0; i < 8; i++) {
-            interrupt_map[(i * 7) + PCI_INT_MAP_PIC_HANDLE] = (u32)dnode;
+        /* openpic interrupt mapping */
+        for (i = 0; i < (7*8); i += 7) {
+            props[i + PCI_INT_MAP_PCI0] = 0;
+            props[i + PCI_INT_MAP_PCI1] = 0;
+            props[i + PCI_INT_MAP_PCI2] = 0;
+            props[i + PCI_INT_MAP_PCI_INT] = (i / 7) + 1; // starts at PINA=1
+            props[i + PCI_INT_MAP_PIC_HANDLE] = dnode;
+            props[i + PCI_INT_MAP_PIC_INT] = arch->irqs[i / 7];
+            props[i + PCI_INT_MAP_PIC_POL] = 3;
+        }
+        set_property(host, "interrupt-map", (char *)props, 7 * 8 * sizeof(props[0]));
+
+        props[PCI_INT_MAP_PCI0] = 0;
+        props[PCI_INT_MAP_PCI1] = 0;
+        props[PCI_INT_MAP_PCI2] = 0;
+        props[PCI_INT_MAP_PCI_INT] = 0x7;
+
+        set_property(host, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0]));
+    }
+
+#elif defined(CONFIG_SPARC64)
+    int ncells, len;
+    u32 *val, addr;
+    char *reg;
+
+    /* Set interrupt-map for devices 4 (NE2000) and 5 (CMD646) */
+    ncells = 0;
+
+    PUSH(host);
+    fword("child");
+    dnode = POP();
+    while (dnode) {
+        if (get_int_property(dnode, "interrupts", &len)) {
+            reg = get_property(dnode, "reg", &len);
+            if (reg) {
+                val = (u32 *)reg;
+
+                for (i = 0; i < (len / sizeof(u32)); i += 5) {
+                    addr = val[i];
+
+                    /* Device address is in 1st 32-bit word of encoded PCI address for config space */
+                    if (!(addr & 0x03000000)) {
+                        ncells += pci_encode_phys_addr(props + ncells, 0, 0, addr, 0, 0);
+                        props[ncells++] = 1;    /* always interrupt pin 1 for QEMU */
+                        props[ncells++] = host;
+                        props[ncells++] = SUN4U_INTERRUPT(addr, 1);
+                    }
+                }
+            }
         }
-        set_property(target_node, "interrupt-map", (char *)interrupt_map, len);
+
+        PUSH(dnode);
+        fword("peer");
+        dnode = POP();
     }
+    set_property(host, "interrupt-map", (char *)props, ncells * sizeof(props[0]));
+
+    props[0] = 0x0000f800;
+    props[1] = 0x0;
+    props[2] = 0x0;
+    props[3] = 7;
+    set_property(host, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0]));
+
 #endif
 }
 
-- 
1.7.10.4




More information about the OpenBIOS mailing list