changeset ea5a46abdcca in /z/repo/m5
details: http://repo.m5sim.org/m5?cmd=changeset;node=ea5a46abdcca
description:
        ARM: Make GIC handle IPIs and multiple processors.

diffstat:

 src/dev/arm/RealView.py |    3 +-
 src/dev/arm/gic.cc      |  450 +++++++++++++++++++++++++++++++++--------------
 src/dev/arm/gic.hh      |   75 ++++++-
 3 files changed, 377 insertions(+), 151 deletions(-)

diffs (truncated from 881 to 300 lines):

diff -r 0cc4594abf28 -r ea5a46abdcca src/dev/arm/RealView.py
--- a/src/dev/arm/RealView.py   Wed May 04 20:38:27 2011 -0500
+++ b/src/dev/arm/RealView.py   Wed May 04 20:38:27 2011 -0500
@@ -82,7 +82,8 @@
     dist_addr = Param.Addr(0x1f001000, "Address for distributor")
     cpu_addr = Param.Addr(0x1f000100, "Address for cpu")
     dist_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to distributor")
-    cpu_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to cpu")
+    cpu_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to cpu interface")
+    int_latency = Param.Latency('10ns', "Delay for interrupt to get to CPU")
     it_lines = Param.UInt32(128, "Number of interrupt lines supported (max = 
1020)")
 
 class AmbaFake(AmbaDevice):
diff -r 0cc4594abf28 -r ea5a46abdcca src/dev/arm/gic.cc
--- a/src/dev/arm/gic.cc        Wed May 04 20:38:27 2011 -0500
+++ b/src/dev/arm/gic.cc        Wed May 04 20:38:27 2011 -0500
@@ -42,11 +42,10 @@
  */
 
 #include "base/trace.hh"
-#include "cpu/intr_control.hh"
 #include "debug/Checkpoint.hh"
 #include "debug/GIC.hh"
+#include "debug/IPI.hh"
 #include "dev/arm/gic.hh"
-#include "dev/platform.hh"
 #include "dev/terminal.hh"
 #include "mem/packet.hh"
 #include "mem/packet_access.hh"
@@ -54,32 +53,40 @@
 Gic::Gic(const Params *p)
     : PioDevice(p),distAddr(p->dist_addr), cpuAddr(p->cpu_addr),
       distPioDelay(p->dist_pio_delay), cpuPioDelay(p->cpu_pio_delay),
-      enabled(false), itLines(p->it_lines)
+      intLatency(p->int_latency), enabled(false), itLines(p->it_lines)
 {
     itLinesLog2 = ceilLog2(itLines);
 
-    for (int x = 0; x < 8; x++) {
+    for (int x = 0; x < CPU_MAX; x++) {
         cpuEnabled[x] = false;
-        cpuPriority[x] = 0;
+        cpuPriority[x] = 0xff;
         cpuBpr[x] = 0;
         // Initialize cpu highest int
         cpuHighestInt[x] = SPURIOUS_INT;
+        postIntEvent[x] = new PostIntEvent(x, p->platform);
     }
+    DPRINTF(Interrupt, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled[0],
+            cpuEnabled[1]);
 
-    for (int x = 0; x < 32; x++) {
+    for (int x = 0; x < INT_BITS_MAX; x++) {
         intEnabled[x] = 0;
         pendingInt[x] = 0;
         activeInt[x] = 0;
     }
 
-    for (int x = 0; x < 1020; x++) {
+    for (int x = 0; x < INT_LINES_MAX; x++) {
         intPriority[x] = 0;
         cpuTarget[x] = 0;
     }
 
-    for (int x = 0; x < 64; x++) {
+    for (int x = 0; x < INT_BITS_MAX*2; x++) {
         intConfig[x] = 0;
     }
+
+    for (int x = 0; x < SGI_MAX; x++) {
+        cpuSgiActive[x] = 0;
+        cpuSgiPending[x] = 0;
+    }
 }
 
 Tick
@@ -117,7 +124,7 @@
     Addr daddr = pkt->getAddr() - distAddr;
     pkt->allocate();
 
-    DPRINTF(Interrupt, "gic distributor read register %#x\n", daddr);
+    DPRINTF(GIC, "gic distributor read register %#x\n", daddr);
 
     if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) {
         assert((daddr-ICDISER_ST) >> 2 < 32);
@@ -152,9 +159,9 @@
     if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
         Addr int_num;
         int_num = daddr - ICDIPR_ST;
-        assert(int_num < 1020);
+        assert(int_num < INT_LINES_MAX);
         DPRINTF(Interrupt, "Reading interrupt priority at int# %#x 
\n",int_num);
-        switch(pkt->getSize()){
+        switch(pkt->getSize()) {
           case 1:
             pkt->set<uint8_t>(intPriority[int_num]);
             break;
@@ -169,25 +176,35 @@
                                intPriority[int_num+3] << 24);
             break;
           default:
-            panic("Invalid access size while reading, priority registers in 
Gic: %d", pkt->getSize());
+            panic("Invalid size while reading priority regs in GIC: %d\n",
+                   pkt->getSize());
         }
         goto done;
     }
 
     if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) {
         Addr int_num;
-        int_num = (daddr-ICDIPTR_ST) << 2;
-        assert(int_num < 1020);
+        int_num = (daddr-ICDIPTR_ST) ;
+        DPRINTF(GIC, "Reading processor target register for int# %#x \n",
+                 int_num);
+        assert(int_num < INT_LINES_MAX);
 
-        // First 31 interrupts only target single processor
+        // First 31 interrupts only target single processor (SGI)
         if (int_num > 31) {
-            pkt->set<uint32_t>(cpuTarget[int_num] |
-                               cpuTarget[int_num+1] << 8 |
-                               cpuTarget[int_num+2] << 16 |
-                               cpuTarget[int_num+3] << 24) ;
+            if (pkt->getSize() == 1) {
+                pkt->set<uint8_t>(cpuTarget[int_num]);
+            } else {
+                assert(pkt->getSize() == 4);
+                int_num = mbits(int_num, 31, 2);
+                pkt->set<uint32_t>(cpuTarget[int_num] |
+                                   cpuTarget[int_num+1] << 8 |
+                                   cpuTarget[int_num+2] << 16 |
+                                   cpuTarget[int_num+3] << 24) ;
+            }
         } else {
-            /** @todo should be processor id */
-            pkt->set<uint32_t>(0);
+            int ctx_id = pkt->req->contextId();
+            assert(ctx_id < sys->numRunningContexts());
+            pkt->set<uint32_t>(ctx_id);
         }
         goto done;
     }
@@ -206,10 +223,9 @@
         pkt->set<uint32_t>(enabled);
         break;
       case ICDICTR:
-        /* @todo this needs to refelct the number of CPUs in the system */
         uint32_t tmp;
-        tmp = 0 << 5 | // cpu number
-              (itLines/32 -1);
+        tmp = ((sys->numRunningContexts() - 1) << 5) |
+              (itLines/INT_BITS_MAX -1);
         pkt->set<uint32_t>(tmp);
         break;
       default:
@@ -227,30 +243,59 @@
     Addr daddr = pkt->getAddr() - cpuAddr;
     pkt->allocate();
 
-    DPRINTF(Interrupt, "gic cpu read register %#x\n", daddr);
+    assert(pkt->req->hasContextId());
+    int ctx_id = pkt->req->contextId();
+    assert(ctx_id < sys->numRunningContexts());
+
+    DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr,
+            ctx_id);
 
     switch(daddr) {
       case ICCICR:
-        pkt->set<uint32_t>(cpuEnabled[0]);
+        pkt->set<uint32_t>(cpuEnabled[ctx_id]);
         break;
       case ICCPMR:
-        pkt->set<uint32_t>(cpuPriority[0]);
+        pkt->set<uint32_t>(cpuPriority[ctx_id]);
         break;
       case ICCBPR:
-        pkt->set<uint32_t>(cpuBpr[0]);
+        pkt->set<uint32_t>(cpuBpr[ctx_id]);
         break;
       case ICCIAR:
-        DPRINTF(Interrupt, "CPU reading IAR = %d\n", cpuHighestInt[0]);
-        if(enabled && cpuEnabled[0]){
-            pkt->set<uint32_t>(cpuHighestInt[0]);
-            activeInt[intNumToWord(cpuHighestInt[0])] |=
-                1 << intNumToBit(cpuHighestInt[0]);
-            updateRunPri();
-            pendingInt[intNumToWord(cpuHighestInt[0])] &=
-                ~(1 << intNumToBit(cpuHighestInt[0]));
-            cpuHighestInt[0] = SPURIOUS_INT;
+        if (enabled && cpuEnabled[ctx_id]) {
+            int active_int = cpuHighestInt[ctx_id];
+            IAR iar = 0;
+            iar.ack_id = active_int;
+            iar.cpu_id = 0;
+            if (active_int < SGI_MAX) {
+                // this is a software interrupt from another CPU
+                if (!cpuSgiPending[active_int])
+                    panic("Interrupt %d active but no CPU generated it?\n",
+                            active_int);
+                for (int x = 0; x < CPU_MAX; x++) {
+                    // See which CPU generated the interrupt
+                    uint8_t cpugen =
+                        bits(cpuSgiPending[active_int], 7 + 8 * x, 8 * x);
+                    if (cpugen & (1 << ctx_id)) {
+                        iar.cpu_id = x;
+                        break;
+                    }
+                }
+                uint64_t sgi_num = ULL(1) << (ctx_id + 8 * iar.cpu_id);
+                cpuSgiActive[iar.ack_id] |= sgi_num;
+                cpuSgiPending[iar.ack_id] &= ~sgi_num;
+            } else {
+                uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx_id]);
+                activeInt[intNumToWord(cpuHighestInt[ctx_id])] |= int_num;
+                updateRunPri();
+                pendingInt[intNumToWord(cpuHighestInt[ctx_id])] &= ~int_num;
+            }
+
+            DPRINTF(Interrupt,"CPU %d reading IAR.id=%d IAR.cpu=%d, 
iar=0x%x\n",
+                    ctx_id, iar.ack_id, iar.cpu_id, iar);
+            cpuHighestInt[ctx_id] = SPURIOUS_INT;
             updateIntState(-1);
-            platform->intrctrl->clear(0, ArmISA::INT_IRQ, 0);
+            pkt->set<uint32_t>(iar);
+            platform->intrctrl->clear(ctx_id, ArmISA::INT_IRQ, 0);
         } else {
              pkt->set<uint32_t>(SPURIOUS_INT);
         }
@@ -278,58 +323,64 @@
     Addr daddr = pkt->getAddr() - distAddr;
     pkt->allocate();
 
-    DPRINTF(Interrupt, "gic distributor write register %#x size %#x\n",
-            daddr, pkt->getSize());
+    assert(pkt->req->hasContextId());
+    int ctx_id = pkt->req->contextId();
+
+    DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
+            daddr, pkt->getSize(), pkt->get<uint32_t>());
 
     if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) {
         assert((daddr-ICDISER_ST) >> 2 < 32);
-        intEnabled[(daddr-ICDISER_ST)>>2] |= pkt->get<uint32_t>();
+        intEnabled[(daddr-ICDISER_ST) >> 2] |= pkt->get<uint32_t>();
         goto done;
     }
 
     if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) {
         assert((daddr-ICDICER_ST) >> 2 < 32);
-        intEnabled[(daddr-ICDICER_ST)>>2] &= ~pkt->get<uint32_t>();
+        intEnabled[(daddr-ICDICER_ST) >> 2] &= ~pkt->get<uint32_t>();
         goto done;
     }
 
     if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) {
         assert((daddr-ICDISPR_ST) >> 2 < 32);
-        pendingInt[(daddr-ICDISPR_ST)>>2] |= pkt->get<uint32_t>();
-        updateIntState((daddr-ICDISPR_ST)>>2);
+        pendingInt[(daddr-ICDISPR_ST) >> 2] |= pkt->get<uint32_t>();
+        pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
+        updateIntState((daddr-ICDISPR_ST) >> 2);
         goto done;
     }
 
     if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) {
         assert((daddr-ICDICPR_ST) >> 2 < 32);
-        pendingInt[(daddr-ICDICPR_ST)>>2] &= ~pkt->get<uint32_t>();
-        updateIntState((daddr-ICDICPR_ST)>>2);
+        pendingInt[(daddr-ICDICPR_ST) >> 2] &= ~pkt->get<uint32_t>();
+        pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
+        updateIntState((daddr-ICDICPR_ST) >> 2);
         goto done;
     }
 
     if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
         Addr int_num = daddr - ICDIPR_ST;
-        assert(int_num < 1020);
+        assert(int_num < INT_LINES_MAX);
         uint32_t tmp;
-        switch(pkt->getSize()){
+        switch(pkt->getSize()) {
           case 1:
             tmp = pkt->get<uint8_t>();
-            intPriority[int_num] = tmp & 0xff;
+            intPriority[int_num] = bits(tmp, 7, 0);
             break;
           case 2:
             tmp = pkt->get<uint16_t>();
-            intPriority[int_num] = tmp & 0xff;
-            intPriority[int_num + 1] = (tmp >> 8) & 0xff;
+            intPriority[int_num] = bits(tmp, 7, 0);
+            intPriority[int_num + 1] = bits(tmp, 15, 8);
             break;
           case 4:
             tmp = pkt->get<uint32_t>();
-            intPriority[int_num] = tmp & 0xff;
-            intPriority[int_num + 1] = (tmp >> 8) & 0xff;
-            intPriority[int_num + 2] = (tmp >> 16) & 0xff;
_______________________________________________
m5-dev mailing list
m5-dev@m5sim.org
http://m5sim.org/mailman/listinfo/m5-dev

Reply via email to