Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/macppc/pci Properly walk the OF tree to map a PCI n...



details:   https://anonhg.NetBSD.org/src/rev/55c25cfd7d81
branches:  trunk
changeset: 550703:55c25cfd7d81
user:      matt <matt%NetBSD.org@localhost>
date:      Mon Aug 18 07:08:11 2003 +0000

description:
Properly walk the OF tree to map a PCI node's interrupt property into the
proper settings for the interrupt-controller.

diffstat:

 sys/arch/macppc/pci/pci_machdep.c |  88 ++++++++++++++++++++++++++++++++------
 1 files changed, 73 insertions(+), 15 deletions(-)

diffs (184 lines):

diff -r 407e44bcd6ab -r 55c25cfd7d81 sys/arch/macppc/pci/pci_machdep.c
--- a/sys/arch/macppc/pci/pci_machdep.c Mon Aug 18 05:39:52 2003 +0000
+++ b/sys/arch/macppc/pci/pci_machdep.c Mon Aug 18 07:08:11 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pci_machdep.c,v 1.21 2003/07/15 02:43:33 lukem Exp $   */
+/*     $NetBSD: pci_machdep.c,v 1.22 2003/08/18 07:08:11 matt Exp $    */
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
@@ -43,7 +43,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.21 2003/07/15 02:43:33 lukem Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.22 2003/08/18 07:08:11 matt Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -295,13 +295,20 @@
        int node;
        pcitag_t tag;
        pcireg_t csr, intr;
-       int len, i;
+       int len, i, ilen;
        int32_t irqs[4];
        struct {
                u_int32_t phys_hi, phys_mid, phys_lo;
                u_int32_t size_hi, size_lo;
        } addr[8];
+       struct {
+               u_int32_t phys_hi, phys_mid, phys_lo;
+               u_int32_t icells[5];
+       } iaddr;
 
+       len = OF_getprop(parent, "#interrupt-cells", &ilen, sizeof(ilen));
+       if (len < 0)            
+               ilen = 0;       
        for (node = OF_child(parent); node; node = OF_peer(node)) {
                len = OF_getprop(node, "assigned-addresses", addr,
                                 sizeof(addr));
@@ -337,9 +344,22 @@
                 * Make sure the line register is programmed with the
                 * interrupt mapping.
                 */
-               if (find_node_intr(node, &addr[0].phys_hi, irqs) == -1)
+               if (ilen == 0)
                        continue;
-
+               iaddr.phys_hi = addr[0].phys_hi;
+               iaddr.phys_mid = addr[0].phys_mid;
+               iaddr.phys_lo = addr[0].phys_lo;
+               /*
+                * Thankfully, PCI can only have one entry in its "interrupts" 
+                * property.
+                */
+               len = OF_getprop(node, "interrupts", &iaddr.icells[0], 4*ilen);
+               if (len != 4*ilen)
+                       continue;
+               if (find_node_intr(node, &iaddr.phys_hi, irqs) == -1) {
+                       printf("find_node_intr failed\n");
+                       continue;
+               }
                intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
                intr &= ~PCI_INTERRUPT_LINE_MASK;
                intr |= irqs[0] & PCI_INTERRUPT_LINE_MASK;
@@ -357,9 +377,10 @@
 {
        int parent, len, mlen, iparent;
        int match, i;
-       u_int32_t map[160], *mp;
+       u_int32_t map[160];
+       const u_int32_t *mp;
        u_int32_t imask[8], maskedaddr[8];
-       u_int32_t icells;
+       u_int32_t acells, icells;
        char name[32];
 
        len = OF_getprop(node, "AAPL,interrupts", intr, 4) ;
@@ -370,6 +391,9 @@
        len = OF_getprop(parent, "interrupt-map", map, sizeof(map));
        mlen = OF_getprop(parent, "interrupt-map-mask", imask, sizeof(imask));
 
+       if (mlen != -1)
+               memcpy(maskedaddr, addr, mlen);
+again:
        if (len == -1 || mlen == -1)
                goto nomap;
 
@@ -381,33 +405,63 @@
 #endif
 
        /* mask addr by "interrupt-map-mask" */
-       memcpy(maskedaddr, addr, mlen);
        for (i = 0; i < mlen / 4; i++)
                maskedaddr[i] &= imask[i];
 
        mp = map;
+       i = 0;
        while (len > mlen) {
                match = memcmp(maskedaddr, mp, mlen);
                mp += mlen / 4;
                len -= mlen;
 
                /*
-                * We must read "#interrupt-cells" for each time because
-                * interrupt-parent may be different.
+                * We must read "#address-cells" and "#interrupt-cells" each
+                * time because each interrupt-parent may be different.
                 */
                iparent = *mp++;
                len -= 4;
+               if (OF_getprop(iparent, "#address-cells", &acells, 4) != 4)
+                       return -1;
                if (OF_getprop(iparent, "#interrupt-cells", &icells, 4) != 4)
-                       goto nomap;
+                       return -1;
 
                /* Found. */
                if (match == 0) {
-                       memcpy(intr, mp, icells * 4);
-                       return icells * 4;
+                       /*
+                        * We matched on address/interrupt, but are we done?
+                        */
+                       if (acells == 0) { /* XXX */
+                               /*
+                                * If we are at the interrupt controller,
+                                * we are finally done.  Save the result and
+                                * return.
+                                */
+                               memcpy(intr, mp, icells * 4);
+                               return icells * 4;
+                       }
+                       /*
+                        * We are now at an intermedia interrupt node.  We
+                        * need to use its interrupt mask and map the 
+                        * supplied address/interupt via its map.
+                        */
+                       mlen = OF_getprop(iparent, "interrupt-map-mask",
+                           imask, sizeof(imask));
+#ifdef DIAGNOSTIC
+                       if (mlen != (acells + icells)*4) {
+                               printf("interrupt-map inconsistent (%d, %d)\n",
+                                   mlen, (acells + icells)*4);
+                               return -1;
+                       }
+#endif
+                       memcpy(maskedaddr, mp, mlen);
+                       len = OF_getprop(iparent, "interrupt-map", map,
+                           sizeof(map));
+                       goto again;
                }
 
-               mp += icells;
-               len -= icells * 4;
+               mp += (acells + icells);
+               len -= (acells + icells) * 4;
        }
 
 nomap:
@@ -422,6 +476,7 @@
                len = OF_getprop(parent, "AAPL,interrupts", intr, 4) ;
                if (len == 4)
                        return len;
+#if 0
                /*
                 * XXX I don't know what is the correct local address.
                 * XXX Use the first entry for now.
@@ -431,12 +486,15 @@
                        addr = &map[5];
                        return find_node_intr(parent, addr, intr);
                }
+#endif
        }
 
+#if 0
        /* XXX This may be wrong... */
        len = OF_getprop(node, "interrupts", intr, 4) ;
        if (len == 4)
                return len;
+#endif
 
        return -1;
 }



Home | Main Index | Thread Index | Old Index