X86: Implement broadcast IPIs.
authorGabe Black <gblack@eecs.umich.edu>
Sun, 19 Apr 2009 11:14:01 +0000 (04:14 -0700)
committerGabe Black <gblack@eecs.umich.edu>
Sun, 19 Apr 2009 11:14:01 +0000 (04:14 -0700)
src/arch/x86/interrupts.cc
src/arch/x86/interrupts.hh

index e51fef6231c1bc3a3751a9f3db881f025572d200..60ea6215be00dba6929d751b24e9dbf6f1843aad 100644 (file)
@@ -338,10 +338,12 @@ X86ISA::Interrupts::recvResponse(PacketPtr pkt)
 {
     assert(!pkt->isError());
     assert(pkt->cmd == MemCmd::MessageResp);
-    InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
-    // Record that the ICR is now idle.
-    low.deliveryStatus = 0;
-    regs[APIC_INTERRUPT_COMMAND_LOW] = low;
+    if (--pendingIPIs == 0) {
+        InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
+        // Record that the ICR is now idle.
+        low.deliveryStatus = 0;
+        regs[APIC_INTERRUPT_COMMAND_LOW] = low;
+    }
     delete pkt->req;
     delete pkt;
     DPRINTF(LocalApic, "ICR is now idle.\n");
@@ -496,17 +498,40 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
             regs[APIC_INTERRUPT_COMMAND_LOW] = low;
             switch (low.destShorthand) {
               case 0:
+                pendingIPIs++;
                 intPort->sendMessage(message, timing);
                 newVal = regs[APIC_INTERRUPT_COMMAND_LOW];
                 break;
               case 1:
-                panic("Self IPIs aren't implemented.\n");
+                newVal = val;
+                requestInterrupt(message.vector,
+                        message.deliveryMode, message.trigger);
                 break;
               case 2:
-                panic("Broadcast including self IPIs aren't implemented.\n");
-                break;
+                requestInterrupt(message.vector,
+                        message.deliveryMode, message.trigger);
+                // Fall through
               case 3:
-                panic("Broadcast excluding self IPIs aren't implemented.\n");
+                {
+                    int numContexts = sys->numContexts();
+                    pendingIPIs += (numContexts - 1);
+                    // We have no way to get at the thread context we're part
+                    // of, so we'll just have to go with the CPU for now.
+                    hack_once("Broadcast IPIs can't handle more than "
+                            "one context per CPU.\n");
+                    int myId = cpu->getContext(0)->contextId();
+                    for (int i = 0; i < numContexts; i++) {
+                        int thisId = sys->getThreadContext(i)->contextId();
+                        if (thisId != myId) {
+                            PacketPtr pkt = buildIntRequest(thisId, message);
+                            if (timing)
+                                intPort->sendMessageTiming(pkt, latency);
+                            else
+                                intPort->sendMessageAtomic(pkt);
+                        }
+                    }
+                }
+                newVal = regs[APIC_INTERRUPT_COMMAND_LOW];
                 break;
             }
         }
@@ -563,7 +588,8 @@ X86ISA::Interrupts::Interrupts(Params * p) :
     pendingExtInt(false), extIntVector(0),
     pendingInit(false), initVector(0),
     pendingStartup(false), startupVector(0),
-    startedUp(false), pendingUnmaskableInt(false)
+    startedUp(false), pendingUnmaskableInt(false),
+    pendingIPIs(0)
 {
     pioSize = PageBytes;
     memset(regs, 0, sizeof(regs));
index 6ae77d7e360d9e0d1e8210b929a0a8fd1903fc86..1f3a414ce4c104288733c011a4c416bdbd2bb0de 100644 (file)
@@ -136,6 +136,9 @@ class Interrupts : public BasicPioDevice, IntDev
     // This is a quick check whether any of the above (except ExtInt) are set.
     bool pendingUnmaskableInt;
 
+    // A count of how many IPIs are in flight.
+    int pendingIPIs;
+
     /*
      * IRR and ISR maintenance.
      */