arm, dev: add basic support for GICC_BPR register
authorCurtis Dunham <Curtis.Dunham@arm.com>
Thu, 9 Mar 2017 17:30:59 +0000 (17:30 +0000)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Mon, 3 Apr 2017 16:51:46 +0000 (16:51 +0000)
The Binary Point Register (BPR) specifies which bits belong to the
group priority field (which are used for preemption) and which to the
subpriority field (which are ignored for preemption).

Change-Id: If51e669d23b49047b69b82ab363dd01a936cc93b
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/2443
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Weiping Liao <weipingliao@google.com>
src/dev/arm/gic_pl390.cc
src/dev/arm/gic_pl390.hh

index e7f3e32efc6cb281377c84979b75e60645bfc7e6..c114604aba53c82342260be8d43731bad24d47e7 100644 (file)
@@ -83,7 +83,7 @@ Pl390::Pl390(const Params *p)
         iccrpr[x] = 0xff;
         cpuEnabled[x] = false;
         cpuPriority[x] = 0xff;
-        cpuBpr[x] = 0;
+        cpuBpr[x] = GICC_BPR_MINIMUM;
         // Initialize cpu highest int
         cpuHighestInt[x] = SPURIOUS_INT;
         postIntEvent[x] = new PostIntEvent(*this, x);
@@ -538,9 +538,13 @@ Pl390::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
       case GICC_PMR:
         cpuPriority[ctx] = data;
         break;
-      case GICC_BPR:
-        cpuBpr[ctx] = data;
+      case GICC_BPR: {
+        auto bpr = data & 0x7;
+        if (bpr < GICC_BPR_MINIMUM)
+            bpr = GICC_BPR_MINIMUM;
+        cpuBpr[ctx] = bpr;
         break;
+      }
       case GICC_EOIR: {
         const IAR iar = data;
         if (iar.ack_id < SGI_MAX) {
@@ -666,6 +670,17 @@ Pl390::genSwiMask(int cpu)
     return ULL(0x0101010101010101) << cpu;
 }
 
+uint8_t
+Pl390::getCpuPriority(unsigned cpu)
+{
+    // see Table 3-2 in IHI0048B.b (GICv2)
+    // mask some low-order priority bits per BPR value
+    // NB: the GIC prioritization scheme is upside down:
+    // lower values are higher priority; masking off bits
+    // actually creates a higher priority, not lower.
+    return cpuPriority[cpu] & (0xff00 >> (7 - cpuBpr[cpu]));
+}
+
 void
 Pl390::updateIntState(int hint)
 {
@@ -676,7 +691,7 @@ Pl390::updateIntState(int hint)
         /*@todo use hint to do less work. */
         int highest_int = SPURIOUS_INT;
         // Priorities below that set in GICC_PMR can be ignored
-        uint8_t highest_pri = cpuPriority[cpu];
+        uint8_t highest_pri = getCpuPriority(cpu);
 
         // Check SGIs
         for (int swi = 0; swi < SGI_MAX; swi++) {
@@ -733,7 +748,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]) &&
+        if (enabled && cpuEnabled[cpu] &&
+            (highest_pri < getCpuPriority(cpu)) &&
             !(getActiveInt(cpu, intNumToWord(highest_int))
               & (1 << intNumToBit(highest_int)))) {
 
index 210f91cfc95094c987bc9c71dd405c53bf8f6d3a..8beb5e2d50b4b4854d1138e5ecc5f7c8e543501e 100644 (file)
@@ -111,6 +111,10 @@ class Pl390 : public BaseGic
     static const int INT_LINES_MAX = 1020;
     static const int GLOBAL_INT_LINES = INT_LINES_MAX - SGI_MAX - PPI_MAX;
 
+    /** minimum value for Binary Point Register ("IMPLEMENTATION DEFINED");
+        chosen for consistency with Linux's in-kernel KVM GIC model */
+    static const int GICC_BPR_MINIMUM = 2;
+
     BitUnion32(SWI)
         Bitfield<3,0> sgi_id;
         Bitfield<23,16> cpu_list;
@@ -276,6 +280,7 @@ class Pl390 : public BaseGic
 
     /** CPU priority */
     uint8_t cpuPriority[CPU_MAX];
+    uint8_t getCpuPriority(unsigned cpu); // BPR-adjusted priority value
 
     /** Binary point registers */
     uint8_t cpuBpr[CPU_MAX];