arm: bank GIC registers per CPU
authorCurtis Dunham <Curtis.Dunham@arm.com>
Tue, 2 Aug 2016 12:35:45 +0000 (13:35 +0100)
committerCurtis Dunham <Curtis.Dunham@arm.com>
Tue, 2 Aug 2016 12:35:45 +0000 (13:35 +0100)
Updated according to GICv2 documentation.

Change-Id: I5d926d1abf665eecc43ff0f7d6e561e1ee1c390a
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
src/dev/arm/gic_pl390.cc
src/dev/arm/gic_pl390.hh
util/cpt_upgraders/arm-gicv2-banked-regs.py [new file with mode: 0644]

index 7b84be6fc96c62220c5def3fc9af610f68dde117..0256db69c565f7b81d9de73d58f452e08dcd9588 100644 (file)
 #include "mem/packet.hh"
 #include "mem/packet_access.hh"
 
+const AddrRange Pl390::GICD_ISENABLER (0x100, 0x17f);
+const AddrRange Pl390::GICD_ICENABLER (0x180, 0x1ff);
+const AddrRange Pl390::GICD_ISPENDR   (0x200, 0x27f);
+const AddrRange Pl390::GICD_ICPENDR   (0x280, 0x2ff);
+const AddrRange Pl390::GICD_ISACTIVER (0x300, 0x37f);
+const AddrRange Pl390::GICD_ICACTIVER (0x380, 0x3ff);
+const AddrRange Pl390::GICD_IPRIORITYR(0x400, 0x7ff);
+const AddrRange Pl390::GICD_ITARGETSR (0x800, 0xbff);
+const AddrRange Pl390::GICD_ICFGR     (0xc00, 0xcff);
+
 Pl390::Pl390(const Params *p)
     : BaseGic(p), distAddr(p->dist_addr),
       cpuAddr(p->cpu_addr), distPioDelay(p->dist_pio_delay),
       cpuPioDelay(p->cpu_pio_delay), intLatency(p->int_latency),
-      enabled(false), itLines(p->it_lines),
-      haveGem5Extensions(p->gem5_extensions), irqEnable(false)
+      enabled(false), haveGem5Extensions(p->gem5_extensions),
+      itLines(p->it_lines),
+      intEnabled {}, pendingInt {}, activeInt {},
+      intPriority {}, cpuTarget {}, intConfig {},
+      cpuSgiPending {}, cpuSgiActive {},
+      cpuSgiPendingExt {}, cpuSgiActiveExt {},
+      cpuPpiPending {}, cpuPpiActive {},
+      irqEnable(false)
 {
-    itLinesLog2 = ceilLog2(itLines);
-
     for (int x = 0; x < CPU_MAX; x++) {
         iccrpr[x] = 0xff;
         cpuEnabled[x] = false;
@@ -72,38 +86,6 @@ Pl390::Pl390(const Params *p)
     DPRINTF(Interrupt, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled[0],
             cpuEnabled[1]);
 
-    for (int x = 0; x < INT_BITS_MAX; x++) {
-        intEnabled[x] = 0;
-        pendingInt[x] = 0;
-        activeInt[x] = 0;
-    }
-
-    for (int x = 0; x < INT_LINES_MAX; x++) {
-        intPriority[x] = 0;
-        cpuTarget[x] = 0;
-    }
-
-    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;
-    }
-    for (int x = 0; x < CPU_MAX; x++) {
-        cpuPpiActive[x] = 0;
-        cpuPpiPending[x] = 0;
-        cpuSgiActiveExt[x] = 0;
-        cpuSgiPendingExt[x] = 0;
-    }
-
-    for (int i = 0; i < CPU_MAX; i++) {
-        for (int j = 0; j < (SGI_MAX + PPI_MAX); j++) {
-            bankedIntPriority[i][j] = 0;
-        }
-    }
-
     gem5ExtensionsEnabled = false;
 }
 
@@ -145,63 +127,68 @@ Pl390::readDistributor(PacketPtr pkt)
 
     DPRINTF(GIC, "gic distributor read register %#x\n", daddr);
 
-    if (daddr >= GICD_ISENABLER_ST && daddr < GICD_ISENABLER_ED + 4) {
-        assert((daddr-GICD_ISENABLER_ST) >> 2 < 32);
-        pkt->set<uint32_t>(intEnabled[(daddr-GICD_ISENABLER_ST)>>2]);
+    if (GICD_ISENABLER.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
+        assert(ix < 32);
+        pkt->set<uint32_t>(getIntEnabled(ctx_id, ix));
+        goto done;
+    }
+
+    if (GICD_ICENABLER.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
+        assert(ix < 32);
+        pkt->set<uint32_t>(getIntEnabled(ctx_id, ix));
         goto done;
     }
 
-    if (daddr >= GICD_ICENABLER_ST && daddr < GICD_ICENABLER_ED + 4) {
-        assert((daddr-GICD_ICENABLER_ST) >> 2 < 32);
-        pkt->set<uint32_t>(intEnabled[(daddr-GICD_ICENABLER_ST)>>2]);
+    if (GICD_ISPENDR.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
+        assert(ix < 32);
+        pkt->set<uint32_t>(getPendingInt(ctx_id, ix));
         goto done;
     }
 
-    if (daddr >= GICD_ISPENDR_ST && daddr < GICD_ISPENDR_ED + 4) {
-        assert((daddr-GICD_ISPENDR_ST) >> 2 < 32);
-        pkt->set<uint32_t>(pendingInt[(daddr-GICD_ISPENDR_ST)>>2]);
+    if (GICD_ICPENDR.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
+        assert(ix < 32);
+        pkt->set<uint32_t>(getPendingInt(ctx_id, ix));
         goto done;
     }
 
-    if (daddr >= GICD_ICPENDR_ST && daddr < GICD_ICPENDR_ED + 4) {
-        assert((daddr-GICD_ICPENDR_ST) >> 2 < 32);
-        pkt->set<uint32_t>(pendingInt[(daddr-GICD_ICPENDR_ST)>>2]);
+    if (GICD_ISACTIVER.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
+        assert(ix < 32);
+        pkt->set<uint32_t>(getPendingInt(ctx_id, ix));
         goto done;
     }
 
-    if (daddr >= GICD_ISACTIVER_ST && daddr < GICD_ISACTIVER_ED + 4) {
-        assert((daddr-GICD_ISACTIVER_ST) >> 2 < 32);
-        pkt->set<uint32_t>(activeInt[(daddr-GICD_ISACTIVER_ST)>>2]);
+    if (GICD_ICACTIVER.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
+        assert(ix < 32);
+        pkt->set<uint32_t>(getPendingInt(ctx_id, ix));
         goto done;
     }
 
-    if (daddr >= GICD_IPRIORITYR_ST && daddr < GICD_IPRIORITYR_ED + 4) {
-        Addr int_num;
-        int_num = daddr - GICD_IPRIORITYR_ST;
+    if (GICD_IPRIORITYR.contains(daddr)) {
+        Addr int_num = daddr - GICD_IPRIORITYR.start();
         assert(int_num < INT_LINES_MAX);
         DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",int_num);
 
-        uint8_t* int_p;
-        if (int_num < (SGI_MAX + PPI_MAX))
-            int_p = bankedIntPriority[ctx_id];
-        else
-            int_p = intPriority;
-
         switch (pkt->getSize()) {
           case 1:
-            pkt->set<uint8_t>(int_p[int_num]);
+            pkt->set<uint8_t>(getIntPriority(ctx_id, int_num));
             break;
           case 2:
             assert((int_num + 1) < INT_LINES_MAX);
-            pkt->set<uint16_t>(int_p[int_num] |
-                               int_p[int_num+1] << 8);
+            pkt->set<uint16_t>(getIntPriority(ctx_id, int_num) |
+                               getIntPriority(ctx_id, int_num+1) << 8);
             break;
           case 4:
             assert((int_num + 3) < INT_LINES_MAX);
-            pkt->set<uint32_t>(int_p[int_num] |
-                               int_p[int_num+1] << 8 |
-                               int_p[int_num+2] << 16 |
-                               int_p[int_num+3] << 24);
+            pkt->set<uint32_t>(getIntPriority(ctx_id, int_num) |
+                               getIntPriority(ctx_id, int_num+1) << 8 |
+                               getIntPriority(ctx_id, int_num+2) << 16 |
+                               getIntPriority(ctx_id, int_num+3) << 24);
             break;
           default:
             panic("Invalid size while reading priority regs in GIC: %d\n",
@@ -210,9 +197,8 @@ Pl390::readDistributor(PacketPtr pkt)
         goto done;
     }
 
-    if (daddr >= GICD_ITARGETSR_ST && daddr < GICD_ITARGETSR_ED + 4) {
-        Addr int_num;
-        int_num = (daddr-GICD_ITARGETSR_ST) ;
+    if (GICD_ITARGETSR.contains(daddr)) {
+        Addr int_num = daddr - GICD_ITARGETSR.start();
         DPRINTF(GIC, "Reading processor target register for int# %#x \n",
                  int_num);
         assert(int_num < INT_LINES_MAX);
@@ -246,12 +232,12 @@ Pl390::readDistributor(PacketPtr pkt)
         goto done;
     }
 
-    if (daddr >= GICD_ICFGR_ST && daddr < GICD_ICFGR_ED + 4) {
-        assert((daddr-GICD_ICFGR_ST) >> 2 < 64);
-        /** @todo software generated interrutps and PPIs
-         * can't be configured in some ways
-         */
-        pkt->set<uint32_t>(intConfig[(daddr-GICD_ICFGR_ST)>>2]);
+    if (GICD_ICFGR.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ICFGR.start()) >> 2;
+        assert(ix < 64);
+        /** @todo software generated interrupts and PPIs
+         * can't be configured in some ways */
+        pkt->set<uint32_t>(intConfig[ix]);
         goto done;
     }
 
@@ -262,8 +248,7 @@ Pl390::readDistributor(PacketPtr pkt)
       case GICD_TYPER: {
         /* The 0x100 is a made-up flag to show that gem5 extensions
          * are available,
-         * write 0x200 to this register to enable it.
-         */
+         * write 0x200 to this register to enable it.  */
         uint32_t tmp = ((sys->numRunningContexts() - 1) << 5) |
             (itLines/INT_BITS_MAX -1) |
             (haveGem5Extensions ? 0x100 : 0x0);
@@ -342,7 +327,8 @@ Pl390::readCpu(PacketPtr pkt)
                 uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx_id]);
                 activeInt[intNumToWord(cpuHighestInt[ctx_id])] |= int_num;
                 updateRunPri();
-                pendingInt[intNumToWord(cpuHighestInt[ctx_id])] &= ~int_num;
+                getPendingInt(ctx_id, intNumToWord(cpuHighestInt[ctx_id]))
+                  &= ~int_num;
             }
 
             DPRINTF(Interrupt,"CPU %d reading IAR.id=%d IAR.cpu=%d, iar=0x%x\n",
@@ -399,60 +385,70 @@ Pl390::writeDistributor(PacketPtr pkt)
     DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
             daddr, pkt->getSize(), pkt_data);
 
-    if (daddr >= GICD_ISENABLER_ST && daddr < GICD_ISENABLER_ED + 4) {
-        assert((daddr-GICD_ISENABLER_ST) >> 2 < 32);
-        intEnabled[(daddr-GICD_ISENABLER_ST) >> 2] |= pkt->get<uint32_t>();
+    if (GICD_ISENABLER.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
+        assert(ix < 32);
+        getIntEnabled(ctx_id, ix) |= pkt->get<uint32_t>();
         goto done;
     }
 
-    if (daddr >= GICD_ICENABLER_ST && daddr < GICD_ICENABLER_ED + 4) {
-        assert((daddr-GICD_ICENABLER_ST) >> 2 < 32);
-        intEnabled[(daddr-GICD_ICENABLER_ST) >> 2] &= ~pkt->get<uint32_t>();
+    if (GICD_ICENABLER.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
+        assert(ix < 32);
+        getIntEnabled(ctx_id, ix) &= ~pkt->get<uint32_t>();
         goto done;
     }
 
-    if (daddr >= GICD_ISPENDR_ST && daddr < GICD_ISPENDR_ED + 4) {
-        assert((daddr-GICD_ISPENDR_ST) >> 2 < 32);
-        pendingInt[(daddr-GICD_ISPENDR_ST) >> 2] |= pkt->get<uint32_t>();
-        pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
-        updateIntState((daddr-GICD_ISPENDR_ST) >> 2);
+    if (GICD_ISPENDR.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
+        auto mask = pkt->get<uint32_t>();
+        if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
+        getPendingInt(ctx_id, ix) |= mask;
+        updateIntState(ix);
         goto done;
     }
 
-    if (daddr >= GICD_ICPENDR_ST && daddr < GICD_ICPENDR_ED + 4) {
-        assert((daddr-GICD_ICPENDR_ST) >> 2 < 32);
-        pendingInt[(daddr-GICD_ICPENDR_ST) >> 2] &= ~pkt->get<uint32_t>();
-        pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
-        updateIntState((daddr-GICD_ICPENDR_ST) >> 2);
+    if (GICD_ICPENDR.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
+        auto mask = pkt->get<uint32_t>();
+        if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
+        getPendingInt(ctx_id, ix) &= ~mask;
+        updateIntState(ix);
         goto done;
     }
 
-    if (daddr >= GICD_IPRIORITYR_ST && daddr < GICD_IPRIORITYR_ED + 4) {
-        Addr int_num = daddr - GICD_IPRIORITYR_ST;
-        assert(int_num < INT_LINES_MAX);
-        uint8_t* int_p;
-        if (int_num < (SGI_MAX + PPI_MAX))
-            int_p = bankedIntPriority[ctx_id];
-        else
-            int_p = intPriority;
-        uint32_t tmp;
+    if (GICD_ISACTIVER.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
+        getActiveInt(ctx_id, ix) |= pkt->get<uint32_t>();
+        goto done;
+    }
+
+    if (GICD_ICACTIVER.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
+        getActiveInt(ctx_id, ix) &= ~pkt->get<uint32_t>();
+        goto done;
+    }
+
+    if (GICD_IPRIORITYR.contains(daddr)) {
+        Addr int_num = daddr - GICD_IPRIORITYR.start();
         switch(pkt->getSize()) {
           case 1:
-            tmp = pkt->get<uint8_t>();
-            int_p[int_num] = bits(tmp, 7, 0);
+            getIntPriority(ctx_id, int_num) = pkt->get<uint8_t>();
             break;
-          case 2:
-            tmp = pkt->get<uint16_t>();
-            int_p[int_num] = bits(tmp, 7, 0);
-            int_p[int_num + 1] = bits(tmp, 15, 8);
+          case 2: {
+            auto tmp16 = pkt->get<uint16_t>();
+            getIntPriority(ctx_id, int_num) = bits(tmp16, 7, 0);
+            getIntPriority(ctx_id, int_num + 1) = bits(tmp16, 15, 8);
             break;
-          case 4:
-            tmp = pkt->get<uint32_t>();
-            int_p[int_num] = bits(tmp, 7, 0);
-            int_p[int_num + 1] = bits(tmp, 15, 8);
-            int_p[int_num + 2] = bits(tmp, 23, 16);
-            int_p[int_num + 3] = bits(tmp, 31, 24);
+          }
+          case 4: {
+            auto tmp32 = pkt->get<uint32_t>();
+            getIntPriority(ctx_id, int_num) = bits(tmp32, 7, 0);
+            getIntPriority(ctx_id, int_num + 1) = bits(tmp32, 15, 8);
+            getIntPriority(ctx_id, int_num + 2) = bits(tmp32, 23, 16);
+            getIntPriority(ctx_id, int_num + 3) = bits(tmp32, 31, 24);
             break;
+          }
           default:
             panic("Invalid size when writing to priority regs in Gic: %d\n",
                    pkt->getSize());
@@ -463,9 +459,8 @@ Pl390::writeDistributor(PacketPtr pkt)
         goto done;
     }
 
-    if (daddr >= GICD_ITARGETSR_ST && daddr < GICD_ITARGETSR_ED + 4) {
-        Addr int_num = (daddr-GICD_ITARGETSR_ST) ;
-        assert(int_num < INT_LINES_MAX);
+    if (GICD_ITARGETSR.contains(daddr)) {
+        Addr int_num = daddr - GICD_ITARGETSR.start();
         // First 31 interrupts only target single processor
         if (int_num >= SGI_MAX) {
             if (pkt->getSize() == 1) {
@@ -480,14 +475,15 @@ Pl390::writeDistributor(PacketPtr pkt)
                 cpuTarget[int_num+2] = bits(tmp, 23, 16);
                 cpuTarget[int_num+3] = bits(tmp, 31, 24);
             }
-            updateIntState((daddr-GICD_ITARGETSR_ST)>>2);
+            updateIntState(int_num >> 2);
         }
         goto done;
     }
 
-    if (daddr >= GICD_ICFGR_ST && daddr < GICD_ICFGR_ED + 4) {
-        assert((daddr-GICD_ICFGR_ST) >> 2 < 64);
-        intConfig[(daddr-GICD_ICFGR_ST)>>2] = pkt->get<uint32_t>();
+    if (GICD_ICFGR.contains(daddr)) {
+        uint32_t ix = (daddr - GICD_ICFGR.start()) >> 2;
+        assert(ix < INT_BITS_MAX*2);
+        intConfig[ix] = pkt->get<uint32_t>();
         if (pkt->get<uint32_t>() & NN_CONFIG_MASK)
             warn("GIC N:N mode selected and not supported at this time\n");
         goto done;
@@ -562,10 +558,10 @@ Pl390::writeCpu(PacketPtr pkt)
             cpuPpiActive[ctx_id] &= ~int_num;
         } else {
             uint32_t int_num = 1 << intNumToBit(iar.ack_id);
-            if (!(activeInt[intNumToWord(iar.ack_id)] & int_num))
+            if (!(getActiveInt(ctx_id, intNumToWord(iar.ack_id)) & int_num))
                 warn("Done handling interrupt that isn't active: %d\n",
                       intNumToBit(iar.ack_id));
-            activeInt[intNumToWord(iar.ack_id)] &= ~int_num;
+            getActiveInt(ctx_id, intNumToWord(iar.ack_id)) &= ~int_num;
         }
         updateRunPri();
         DPRINTF(Interrupt, "CPU %d done handling intr IAR = %d from cpu %d\n",
@@ -580,6 +576,16 @@ Pl390::writeCpu(PacketPtr pkt)
     return cpuPioDelay;
 }
 
+Pl390::BankedRegs&
+Pl390::getBankedRegs(ContextID ctx_id) {
+    if (bankedRegs.size() <= ctx_id)
+        bankedRegs.resize(ctx_id + 1);
+
+    if (!bankedRegs[ctx_id])
+        bankedRegs[ctx_id] = new BankedRegs;
+    return *bankedRegs[ctx_id];
+}
+
 void
 Pl390::softInt(ContextID ctx_id, SWI swi)
 {
@@ -676,8 +682,8 @@ Pl390::updateIntState(int hint)
                 continue;
             if ((cpuSgiPending[swi] & genSwiMask(cpu)) ||
                 (cpuSgiPendingExt[cpu] & (1 << swi)))
-                if (highest_pri > bankedIntPriority[cpu][swi]) {
-                    highest_pri = bankedIntPriority[cpu][swi];
+                if (highest_pri > getIntPriority(cpu, swi)) {
+                    highest_pri = getIntPriority(cpu, swi);
                     highest_int = swi;
                 }
         }
@@ -686,8 +692,8 @@ Pl390::updateIntState(int hint)
         if (cpuPpiPending[cpu]) {
         for (int ppi = 0; ppi < PPI_MAX; ppi++) {
             if (cpuPpiPending[cpu] & (1 << ppi))
-                if (highest_pri > bankedIntPriority[cpu][SGI_MAX + ppi]) {
-                    highest_pri = bankedIntPriority[cpu][SGI_MAX + ppi];
+                if (highest_pri > getIntPriority(cpu, SGI_MAX + ppi)) {
+                    highest_pri = getIntPriority(cpu, SGI_MAX + ppi);
                     highest_int = SGI_MAX + ppi;
                 }
             }
@@ -696,21 +702,22 @@ Pl390::updateIntState(int hint)
         bool mp_sys = sys->numRunningContexts() > 1;
         // Check other ints
         for (int x = 0; x < (itLines/INT_BITS_MAX); x++) {
-            if (intEnabled[x] & pendingInt[x]) {
+            if (getIntEnabled(cpu, x) & getPendingInt(cpu, x)) {
                 for (int y = 0; y < INT_BITS_MAX; y++) {
                    uint32_t int_nm = x * INT_BITS_MAX + y;
                    DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm);
                     /* Set current pending int as highest int for current cpu
-                       if the interrupt's priority higher than current prioirty
+                       if the interrupt's priority higher than current priority
                        and if currrent cpu is the target (for mp configs only)
                      */
-                    if ((bits(intEnabled[x], y) & bits(pendingInt[x], y)) &&
-                        (intPriority[int_nm] < highest_pri))
-                        if ( (!mp_sys) ||
-                             (!gem5ExtensionsEnabled && (cpuTarget[int_nm] & (1 << cpu))) ||
-                             (gem5ExtensionsEnabled && (cpuTarget[int_nm] == cpu))
-                            ) {
-                            highest_pri = intPriority[int_nm];
+                    if ((bits(getIntEnabled(cpu, x), y)
+                        &bits(getPendingInt(cpu, x), y)) &&
+                        (getIntPriority(cpu, int_nm) < highest_pri))
+                        if ((!mp_sys) ||
+                            (gem5ExtensionsEnabled
+                               ? (cpuTarget[int_nm] == cpu)
+                               : (cpuTarget[int_nm] & (1 << cpu)))) {
+                            highest_pri = getIntPriority(cpu, int_nm);
                             highest_int = int_nm;
                         }
                 }
@@ -725,8 +732,8 @@ Pl390::updateIntState(int hint)
         /* @todo make this work for more than one cpu, need to handle 1:N, N:N
          * models */
         if (enabled && cpuEnabled[cpu] && (highest_pri < cpuPriority[cpu]) &&
-            !(activeInt[intNumToWord(highest_int)]
-            & (1 << intNumToBit(highest_int)))) {
+            !(getActiveInt(cpu, intNumToWord(highest_int))
+              & (1 << intNumToBit(highest_int)))) {
 
             DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int,
                     cpu);
@@ -742,21 +749,22 @@ Pl390::updateRunPri()
         if (!cpuEnabled[cpu])
             continue;
         uint8_t maxPriority = 0xff;
-        for (int i = 0; i < itLines; i++){
+        for (int i = 0; i < itLines; i++) {
             if (i < SGI_MAX) {
                 if (((cpuSgiActive[i] & genSwiMask(cpu)) ||
                      (cpuSgiActiveExt[cpu] & (1 << i))) &&
-                        (bankedIntPriority[cpu][i] < maxPriority))
-                    maxPriority = bankedIntPriority[cpu][i];
+                        (getIntPriority(cpu, i) < maxPriority))
+                    maxPriority = getIntPriority(cpu, i);
             } else if (i < (SGI_MAX + PPI_MAX)) {
                 if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) &&
-                        (bankedIntPriority[cpu][i] < maxPriority))
-                    maxPriority = bankedIntPriority[cpu][i];
+                        (getIntPriority(cpu, i) < maxPriority))
+                    maxPriority = getIntPriority(cpu, i);
 
             } else {
-                if (activeInt[intNumToWord(i)] & (1 << intNumToBit(i)))
-                    if (intPriority[i] < maxPriority)
-                        maxPriority = intPriority[i];
+                if (getActiveInt(cpu, intNumToWord(i))
+                    & (1 << intNumToBit(i)))
+                    if (getIntPriority(cpu, i) < maxPriority)
+                        maxPriority = getIntPriority(cpu, i);
             }
         }
         iccrpr[cpu] = maxPriority;
@@ -770,9 +778,10 @@ Pl390::sendInt(uint32_t num)
             num, cpuTarget[num]);
     if ((cpuTarget[num] & (cpuTarget[num] - 1)) && !gem5ExtensionsEnabled)
         panic("Multiple targets for peripheral interrupts is not supported\n");
-    pendingInt[intNumToWord(num)] |= 1 << intNumToBit(num);
+    panic_if(num < SGI_MAX + PPI_MAX,
+             "sentInt() must only be used for interrupts 32 and higher");
+    getPendingInt(cpuTarget[num], intNumToWord(num)) |= 1 << intNumToBit(num);
     updateIntState(intNumToWord(num));
-
 }
 
 void
@@ -827,13 +836,12 @@ Pl390::serialize(CheckpointOut &cp) const
     SERIALIZE_SCALAR(cpuPioDelay);
     SERIALIZE_SCALAR(enabled);
     SERIALIZE_SCALAR(itLines);
-    SERIALIZE_SCALAR(itLinesLog2);
-    SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
-    SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
-    SERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
+    SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1);
+    SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1);
+    SERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1);
     SERIALIZE_ARRAY(iccrpr, CPU_MAX);
-    SERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
-    SERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
+    SERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES);
+    SERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES);
     SERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
     SERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
     SERIALIZE_ARRAY(cpuPriority, CPU_MAX);
@@ -845,7 +853,6 @@ Pl390::serialize(CheckpointOut &cp) const
     SERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX);
     SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
     SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
-    SERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
     SERIALIZE_SCALAR(irqEnable);
     Tick interrupt_time[CPU_MAX];
     for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
@@ -856,6 +863,22 @@ Pl390::serialize(CheckpointOut &cp) const
     }
     SERIALIZE_ARRAY(interrupt_time, CPU_MAX);
     SERIALIZE_SCALAR(gem5ExtensionsEnabled);
+
+    for (uint32_t i=0; i < bankedRegs.size(); ++i) {
+        if (!bankedRegs[i])
+            continue;
+        bankedRegs[i]->serializeSection(cp, csprintf("bankedRegs%i", i));
+    }
+}
+
+void
+Pl390::BankedRegs::serialize(CheckpointOut &cp) const
+{
+    SERIALIZE_SCALAR(intEnabled);
+    SERIALIZE_SCALAR(pendingInt);
+    SERIALIZE_SCALAR(activeInt);
+    SERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
+    SERIALIZE_ARRAY(cpuTarget, SGI_MAX + PPI_MAX);
 }
 
 void
@@ -869,13 +892,12 @@ Pl390::unserialize(CheckpointIn &cp)
     UNSERIALIZE_SCALAR(cpuPioDelay);
     UNSERIALIZE_SCALAR(enabled);
     UNSERIALIZE_SCALAR(itLines);
-    UNSERIALIZE_SCALAR(itLinesLog2);
-    UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
-    UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
-    UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
+    UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1);
+    UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1);
+    UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1);
     UNSERIALIZE_ARRAY(iccrpr, CPU_MAX);
-    UNSERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
-    UNSERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
+    UNSERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES);
+    UNSERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES);
     UNSERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
     UNSERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
     UNSERIALIZE_ARRAY(cpuPriority, CPU_MAX);
@@ -887,7 +909,6 @@ Pl390::unserialize(CheckpointIn &cp)
     UNSERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX);
     UNSERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
     UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
-    UNSERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
     UNSERIALIZE_SCALAR(irqEnable);
 
     Tick interrupt_time[CPU_MAX];
@@ -899,6 +920,23 @@ Pl390::unserialize(CheckpointIn &cp)
     }
     if (!UNSERIALIZE_OPT_SCALAR(gem5ExtensionsEnabled))
         gem5ExtensionsEnabled = false;
+
+    for (uint32_t i=0; i < CPU_MAX; ++i) {
+        ScopedCheckpointSection sec(cp, csprintf("bankedRegs%i", i));
+        if (cp.sectionExists(Serializable::currentSection())) {
+            getBankedRegs(i).unserialize(cp);
+        }
+    }
+}
+
+void
+Pl390::BankedRegs::unserialize(CheckpointIn &cp)
+{
+    UNSERIALIZE_SCALAR(intEnabled);
+    UNSERIALIZE_SCALAR(pendingInt);
+    UNSERIALIZE_SCALAR(activeInt);
+    UNSERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
+    UNSERIALIZE_ARRAY(cpuTarget, SGI_MAX + PPI_MAX);
 }
 
 Pl390 *
@@ -909,10 +947,10 @@ Pl390Params::create()
 
 /* Functions for debugging and testing */
 void
-Pl390::driveSPI(unsigned int spiVect)
+Pl390::driveSPI(uint32_t spiVect)
 {
     DPRINTF(GIC, "Received SPI Vector:%x Enable: %d\n", spiVect, irqEnable);
-    pendingInt[1] |= spiVect;
+    getPendingInt(0, 1) |= spiVect;
     if (irqEnable && enabled) {
         updateIntState(-1);
     }
index a05cf43bf65e0b391122be0e3bcdf3c489102b0e..e406bc260e0abafc00dc246d3884d746df3170cc 100644 (file)
 
 
 /** @file
- * Implementiation of a PL390 GIC
+ * Implementation of a PL390 GIC
  */
 
 #ifndef __DEV_ARM_GIC_PL390_H__
 #define __DEV_ARM_GIC_PL390_H__
 
+#include <vector>
+
+#include "base/addr_range.hh"
 #include "base/bitunion.hh"
 #include "cpu/intr_control.hh"
 #include "dev/arm/base_gic.hh"
 #include "dev/platform.hh"
 #include "params/Pl390.hh"
 
-/** @todo this code only assumes one processor for now. Low word
- * of intEnabled and pendingInt need to be replicated per CPU.
- * bottom 31 interrupts (7 words) need to be replicated for
- * for interrupt priority register, processor target registers
- * interrupt config registers  */
-
 class Pl390 : public BaseGic
 {
   protected:
@@ -69,28 +66,22 @@ class Pl390 : public BaseGic
         GICD_CTLR          = 0x000, // control register
         GICD_TYPER         = 0x004, // controller type
         GICD_IIDR          = 0x008, // implementer id
-        GICD_ISENABLER_ST  = 0x100, // interrupt set enable
-        GICD_ISENABLER_ED  = 0x17c,
-        GICD_ICENABLER_ST  = 0x180, // interrupt clear enable
-        GICD_ICENABLER_ED  = 0x1fc,
-        GICD_ISPENDR_ST    = 0x200, // set pending interrupt
-        GICD_ISPENDR_ED    = 0x27c,
-        GICD_ICPENDR_ST    = 0x280, // clear pending interrupt
-        GICD_ICPENDR_ED    = 0x2fc,
-        GICD_ISACTIVER_ST  = 0x300, // active bit registers
-        GICD_ISACTIVER_ED  = 0x37c,
-        GICD_IPRIORITYR_ST = 0x400, // interrupt priority registers
-        GICD_IPRIORITYR_ED = 0x7f8,
-        GICD_ITARGETSR_ST  = 0x800, // processor target registers
-        GICD_ITARGETSR_ED  = 0xbf8,
-        GICD_ICFGR_ST      = 0xc00, // interrupt config registers
-        GICD_ICFGR_ED      = 0xcfc,
         GICD_SGIR          = 0xf00, // software generated interrupt
 
         DIST_SIZE          = 0xfff
     };
 
-    // cpu memory addressesa
+    static const AddrRange GICD_ISENABLER;  // interrupt set enable
+    static const AddrRange GICD_ICENABLER;  // interrupt clear enable
+    static const AddrRange GICD_ISPENDR;    // set pending interrupt
+    static const AddrRange GICD_ICPENDR;    // clear pending interrupt
+    static const AddrRange GICD_ISACTIVER;  // active bit registers
+    static const AddrRange GICD_ICACTIVER;  // clear bit registers
+    static const AddrRange GICD_IPRIORITYR; // interrupt priority registers
+    static const AddrRange GICD_ITARGETSR;  // processor target registers
+    static const AddrRange GICD_ICFGR;      // interrupt config registers
+
+    // cpu memory addresses
     enum {
         GICC_CTLR  = 0x00, // CPU control register
         GICC_PMR   = 0x04, // Interrupt priority mask
@@ -118,6 +109,7 @@ class Pl390 : public BaseGic
     static const int SPURIOUS_INT = 1023;
     static const int INT_BITS_MAX = 32;
     static const int INT_LINES_MAX = 1020;
+    static const int GLOBAL_INT_LINES = INT_LINES_MAX - SGI_MAX - PPI_MAX;
 
     BitUnion32(SWI)
         Bitfield<3,0> sgi_id;
@@ -149,41 +141,121 @@ class Pl390 : public BaseGic
     /** Gic enabled */
     bool enabled;
 
+    /** Are gem5 extensions available? */
+    const bool haveGem5Extensions;
+
     /** gem5 many-core extension enabled by driver */
     bool gem5ExtensionsEnabled;
 
     /** Number of itLines enabled */
     uint32_t itLines;
 
-    uint32_t itLinesLog2;
+    /** Registers "banked for each connected processor" per ARM IHI0048B */
+    struct BankedRegs : public Serializable {
+        /** GICD_I{S,C}ENABLER0
+         * interrupt enable bits for first 32 interrupts, 1b per interrupt */
+        uint32_t intEnabled;
 
-    /** Are gem5 extensions available? */
-    const bool haveGem5Extensions;
+        /** GICD_I{S,C}PENDR0
+         * interrupt pending bits for first 32 interrupts, 1b per interrupt */
+        uint32_t pendingInt;
+
+        /** GICD_I{S,C}ACTIVER0
+         * interrupt active bits for first 32 interrupts, 1b per interrupt */
+        uint32_t activeInt;
+
+        /** GICD_IPRIORITYR{0..7}
+         * interrupt priority for SGIs and PPIs */
+        uint8_t intPriority[SGI_MAX + PPI_MAX];
 
-    /** interrupt enable bits for all possible 1020 interupts.
-     * one bit per interrupt, 32 bit per word = 32 words */
-    uint32_t intEnabled[INT_BITS_MAX];
+        /** GICD_ITARGETSR{0..7}
+         * 8b CPU target ID for each SGI and PPI */
+        uint8_t cpuTarget[SGI_MAX + PPI_MAX];
 
-    /** interrupt pending bits for all possible 1020 interupts.
-     * one bit per interrupt, 32 bit per word = 32 words */
-    uint32_t pendingInt[INT_BITS_MAX];
+        void serialize(CheckpointOut &cp) const override;
+        void unserialize(CheckpointIn &cp) override;
+
+        BankedRegs() :
+            intEnabled(0), pendingInt(0), activeInt(0),
+            intPriority {0}, cpuTarget {0}
+          {}
+    };
+    std::vector<BankedRegs*> bankedRegs;
 
-    /** interrupt active bits for all possible 1020 interupts.
-     * one bit per interrupt, 32 bit per word = 32 words */
-    uint32_t activeInt[INT_BITS_MAX];
+    BankedRegs& getBankedRegs(ContextID);
 
-    /** read only running priroity register, 1 per cpu*/
+    /** GICD_I{S,C}ENABLER{1..31}
+     * interrupt enable bits for global interrupts
+     * 1b per interrupt, 32 bits per word, 31 words */
+    uint32_t intEnabled[INT_BITS_MAX-1];
+
+    uint32_t& getIntEnabled(ContextID ctx_id, uint32_t ix) {
+        if (ix == 0) {
+            return getBankedRegs(ctx_id).intEnabled;
+        } else {
+            return intEnabled[ix - 1];
+        }
+    }
+
+    /** GICD_I{S,C}PENDR{1..31}
+     * interrupt pending bits for global interrupts
+     * 1b per interrupt, 32 bits per word, 31 words */
+    uint32_t pendingInt[INT_BITS_MAX-1];
+
+    uint32_t& getPendingInt(ContextID ctx_id, uint32_t ix) {
+        assert(ix < INT_BITS_MAX);
+        if (ix == 0) {
+            return getBankedRegs(ctx_id).pendingInt;
+        } else {
+            return pendingInt[ix - 1];
+        }
+    }
+
+    /** GICD_I{S,C}ACTIVER{1..31}
+     * interrupt active bits for global interrupts
+     * 1b per interrupt, 32 bits per word, 31 words */
+    uint32_t activeInt[INT_BITS_MAX-1];
+
+    uint32_t& getActiveInt(ContextID ctx_id, uint32_t ix) {
+        assert(ix < INT_BITS_MAX);
+        if (ix == 0) {
+            return getBankedRegs(ctx_id).activeInt;
+        } else {
+            return activeInt[ix - 1];
+        }
+    }
+
+    /** read only running priority register, 1 per cpu*/
     uint32_t iccrpr[CPU_MAX];
 
-    /** an 8 bit priority (lower is higher priority) for each
-     * of the 1020 possible supported interrupts.
+    /** GICD_IPRIORITYR{8..255}
+     * an 8 bit priority (lower is higher priority) for each
+     * of the global (not replicated per CPU) interrupts.
      */
-    uint8_t intPriority[INT_LINES_MAX];
+    uint8_t intPriority[GLOBAL_INT_LINES];
+
+    uint8_t& getIntPriority(ContextID ctx_id, uint32_t ix) {
+        assert(ix < INT_LINES_MAX);
+        if (ix < SGI_MAX + PPI_MAX) {
+            return getBankedRegs(ctx_id).intPriority[ix];
+        } else {
+            return intPriority[ix - (SGI_MAX + PPI_MAX)];
+        }
+    }
 
-    /** an 8 bit cpu target id for each shared peripheral interrupt
-     * of the 1020 possible supported interrupts.
+    /** GICD_ITARGETSR{8..255}
+     * an 8 bit cpu target id for each global interrupt.
      */
-    uint8_t cpuTarget[INT_LINES_MAX];
+    uint8_t cpuTarget[GLOBAL_INT_LINES];
+
+    uint8_t& getCpuTarget(ContextID ctx_id, uint32_t ix) {
+        assert(ix < INT_LINES_MAX);
+        if (ix < SGI_MAX + PPI_MAX) {
+            return getBankedRegs(ctx_id).cpuTarget[ix];
+        } else {
+            return cpuTarget[ix - (SGI_MAX + PPI_MAX)];
+        }
+    }
 
     /** 2 bit per interrupt signaling if it's level or edge sensitive
      * and if it is 1:N or N:N */
@@ -219,9 +291,6 @@ class Pl390 : public BaseGic
     uint32_t cpuPpiPending[CPU_MAX];
     uint32_t cpuPpiActive[CPU_MAX];
 
-    /** Banked interrupt prioirty registers for SGIs and PPIs */
-    uint8_t bankedIntPriority[CPU_MAX][SGI_MAX + PPI_MAX];
-
     /** IRQ Enable Used for debug */
     bool irqEnable;
 
diff --git a/util/cpt_upgraders/arm-gicv2-banked-regs.py b/util/cpt_upgraders/arm-gicv2-banked-regs.py
new file mode 100644 (file)
index 0000000..4cdb9e3
--- /dev/null
@@ -0,0 +1,81 @@
+# Copyright (c) 2016 ARM Limited
+# All rights reserved
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# duplicate banked registers into new per-cpu arrays.
+def upgrader(cpt):
+    if cpt.get('root','isa') == 'arm':
+        for sec in cpt.sections():
+            import re
+
+            if not re.search('\.gic$', sec):
+                continue
+            cpuEnabled  = cpt.get(sec, 'cpuEnabled' ).split()
+
+            intEnabled  = cpt.get(sec, 'intEnabled' ).split()
+            pendingInt  = cpt.get(sec, 'pendingInt' ).split()
+            activeInt   = cpt.get(sec, 'activeInt'  ).split()
+            intPriority = cpt.get(sec, 'intPriority').split()
+            cpuTarget   = cpt.get(sec, 'cpuTarget'  ).split()
+
+            b_intEnabled = intEnabled[0]
+            b_pendingInt = pendingInt[0]
+            b_activeInt  = activeInt[0]
+            b_cpuTarget  = cpuTarget[0:32]
+
+            del intEnabled[0]
+            del pendingInt[0]
+            del activeInt[0]
+            del intPriority[0:32] # unused; overlapped with bankedIntPriority
+            del cpuTarget[0:32]
+
+            cpt.set(sec, 'intEnabled', ' '.join(intEnabled))
+            cpt.set(sec, 'pendingInt', ' '.join(pendingInt))
+            cpt.set(sec, 'activeInt',  ' '.join(activeInt))
+            cpt.set(sec, 'intPriority',' '.join(intPriority))
+            cpt.set(sec, 'cpuTarget',  ' '.join(cpuTarget))
+
+            b_intPriority = cpt.get(sec, '*bankedIntPriority').split()
+            cpt.remove_option(sec, '*bankedIntPriority')
+
+            for cpu in xrange(0, 255):
+                if cpuEnabled[cpu] == 'true':
+                    intPriority = b_intPriority[cpu*32 : (cpu+1)*32]
+                    new_sec = "%s.bankedRegs%u" % (sec, cpu)
+                    cpt.add_section(new_sec)
+                    cpt.set(new_sec, 'intEnabled', b_intEnabled)
+                    cpt.set(new_sec, 'pendingInt', b_pendingInt)
+                    cpt.set(new_sec, 'activeInt',  b_activeInt)
+                    cpt.set(new_sec, 'intPriority',' '.join(intPriority))
+                    cpt.set(new_sec, 'cpuTarget',  ' '.join(b_cpuTarget))