cpu: Add CPU support for generatig wake up events when LLSC adresses are snooped.
authorAli Saidi <Ali.Saidi@ARM.com>
Fri, 24 Jan 2014 21:29:30 +0000 (15:29 -0600)
committerAli Saidi <Ali.Saidi@ARM.com>
Fri, 24 Jan 2014 21:29:30 +0000 (15:29 -0600)
This patch add support for generating wake-up events in the CPU when an address
that is currently in the exclusive state is hit by a snoop. This mechanism is required
for ARMv8 multi-processor support.

14 files changed:
src/arch/alpha/locked_mem.hh
src/arch/arm/locked_mem.hh
src/arch/mips/locked_mem.hh
src/arch/power/locked_mem.hh
src/arch/sparc/locked_mem.hh
src/arch/x86/locked_mem.hh
src/cpu/base.hh
src/cpu/base_dyn_inst.hh
src/cpu/inorder/resources/cache_unit.cc
src/cpu/o3/lsq_unit_impl.hh
src/cpu/simple/atomic.cc
src/cpu/simple/atomic.hh
src/cpu/simple/timing.cc
src/cpu/simple/timing.hh

index e62ed16548f03ae5b9c1c62abc9aa798c48257f9..253b94be4f4ccfbd31beca1e6d3b03dc36bb8005 100644 (file)
@@ -93,10 +93,15 @@ handleLockedRead(XC *xc, Request *req)
     xc->setMiscReg(MISCREG_LOCKFLAG, true);
 }
 
+template <class XC>
+inline void
+handleLockedSnoopHit(XC *xc)
+{
+}
 
 template <class XC>
 inline bool
-handleLockedWrite(XC *xc, Request *req)
+handleLockedWrite(XC *xc, Request *req, Addr cacheBlockMask)
 {
     if (req->isUncacheable()) {
         // Funky Turbolaser mailbox access...don't update
index 37973ff9832bffcdd49454d0bd1547f1aeb3e4b2..f2601f00cd6d460847141d5f164096e046b1ea3c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012-2013 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -66,26 +66,30 @@ handleLockedSnoop(XC *xc, PacketPtr pkt, Addr cacheBlockMask)
         return;
 
     Addr locked_addr = xc->readMiscReg(MISCREG_LOCKADDR) & cacheBlockMask;
-    Addr snoop_addr = pkt->getAddr();
-
-    assert((cacheBlockMask & snoop_addr) == snoop_addr);
+    Addr snoop_addr = pkt->getAddr() & cacheBlockMask;
 
     if (locked_addr == snoop_addr)
         xc->setMiscReg(MISCREG_LOCKFLAG, false);
 }
 
+template <class XC>
+inline void
+handleLockedSnoopHit(XC *xc)
+{
+}
+
 template <class XC>
 inline void
 handleLockedRead(XC *xc, Request *req)
 {
-    xc->setMiscReg(MISCREG_LOCKADDR, req->getPaddr() & ~0xf);
+    xc->setMiscReg(MISCREG_LOCKADDR, req->getPaddr());
     xc->setMiscReg(MISCREG_LOCKFLAG, true);
 }
 
 
 template <class XC>
 inline bool
-handleLockedWrite(XC *xc, Request *req)
+handleLockedWrite(XC *xc, Request *req, Addr cacheBlockMask)
 {
     if (req->isSwap())
         return true;
@@ -93,8 +97,8 @@ handleLockedWrite(XC *xc, Request *req)
     // Verify that the lock flag is still set and the address
     // is correct
     bool lock_flag = xc->readMiscReg(MISCREG_LOCKFLAG);
-    Addr lock_addr = xc->readMiscReg(MISCREG_LOCKADDR);
-    if (!lock_flag || (req->getPaddr() & ~0xf) != lock_addr) {
+    Addr lock_addr = xc->readMiscReg(MISCREG_LOCKADDR) & cacheBlockMask;
+    if (!lock_flag || (req->getPaddr() & cacheBlockMask) != lock_addr) {
         // Lock flag not set or addr mismatch in CPU;
         // don't even bother sending to memory system
         req->setExtraData(0);
index b4003fea96700ddb9b62850fecaefe99fdd6be25..5b0f8a1b8e5ca76b6edb2a75b3331fcf16668297 100644 (file)
@@ -86,9 +86,15 @@ handleLockedRead(XC *xc, Request *req)
             req->threadId(), req->getPaddr() & ~0xf);
 }
 
+template <class XC>
+inline void
+handleLockedSnoopHit(XC *xc)
+{
+}
+
 template <class XC>
 inline bool
-handleLockedWrite(XC *xc, Request *req)
+handleLockedWrite(XC *xc, Request *req, Addr cacheBlockMask)
 {
     if (req->isUncacheable()) {
         // Funky Turbolaser mailbox access...don't update
index f3d042d5c45f7723088f575d76ca52275114e292..d962f9aff9598fdcfd685e99bc53d4adfc9a3886 100644 (file)
@@ -59,9 +59,15 @@ handleLockedRead(XC *xc, Request *req)
 {
 }
 
+template <class XC>
+inline void
+handleLockedSnoopHit(XC *xc)
+{
+}
+
 template <class XC>
 inline bool
-handleLockedWrite(XC *xc, Request *req)
+handleLockedWrite(XC *xc, Request *req, Addr cacheBlockMask)
 {
     return true;
 }
index 8277ef487931aa09a43b41933ad7eaded376b51e..b28179481f2dd0a2839f338ea9db4c97eb629d0d 100644 (file)
@@ -54,10 +54,16 @@ handleLockedRead(XC *xc, Request *req)
 {
 }
 
+template <class XC>
+inline void
+handleLockedSnoopHit(XC *xc)
+{
+}
+
 
 template <class XC>
 inline bool
-handleLockedWrite(XC *xc, Request *req)
+handleLockedWrite(XC *xc, Request *req, Addr cacheBlockMask)
 {
     return true;
 }
index c2a8395aa4b0ea5df6f796fb78aa975280677156..51cfb2ea32e8f895c0b0c7b1345f5d699308e9b9 100644 (file)
@@ -56,10 +56,16 @@ namespace X86ISA
 
     template <class XC>
     inline bool
-    handleLockedWrite(XC *xc, Request *req)
+    handleLockedWrite(XC *xc, Request *req, Addr cacheBlockMask)
     {
         return true;
     }
+
+    template <class XC>
+    inline void
+    handleLockedSnoopHit(XC *xc)
+    {
+    }
 }
 
 #endif // __ARCH_X86_LOCKEDMEM_HH__
index 540c728336666ed6a43ac7be0aeff02b6cb7a179..515f6a5a20074d4ab2fe4887b0ff2722e93e3195 100644 (file)
@@ -261,6 +261,9 @@ class BaseCPU : public MemObject
    /// Given a thread num get tho thread context for it
    virtual ThreadContext *getContext(int tn) { return threadContexts[tn]; }
 
+   /// Get the number of thread contexts available
+   unsigned numContexts() { return threadContexts.size(); }
+
   public:
     typedef BaseCPUParams Params;
     const Params *params() const
index f12a89bbd614eba600e722f2c2509b9c15436398..3ce7de75d16aded96adfde6851b79f18c2468302 100644 (file)
@@ -164,6 +164,8 @@ class BaseDynInst : public RefCounted
     /** Pointer to the Impl's CPU object. */
     ImplCPU *cpu;
 
+    BaseCPU *getCpuPtr() { return cpu; }
+
     /** Pointer to the thread state. */
     ImplState *thread;
 
index 9a46641ac5f9f47b3ddfcf9d7b255e72f5ae807f..c71678a916ecc7f22cfbf1d92eb85ccf5eaa13da 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2013 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.
+ *
  * Copyright (c) 2007 MIPS Technologies, Inc.
  * All rights reserved.
  *
@@ -863,7 +875,7 @@ CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res,
         if (mem_req->isLLSC()) {
             assert(cache_req->inst->isStoreConditional());
             DPRINTF(InOrderCachePort, "Evaluating Store Conditional access\n");
-            do_access = TheISA::handleLockedWrite(inst.get(), mem_req);
+            do_access = TheISA::handleLockedWrite(inst.get(), mem_req, cacheBlkSize);
         }
      }
 
index 277fe48d27b1a91608edc90509ce7ad0453b8393..7ec59e38d7c66d53e69041ba4657057f5696bf61 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * Copyright (c) 2010-2012 ARM Limited
+ * Copyright (c) 2010-2013 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -433,12 +433,13 @@ void
 LSQUnit<Impl>::checkSnoop(PacketPtr pkt)
 {
     int load_idx = loadHead;
+    DPRINTF(LSQUnit, "Got snoop for address %#x\n", pkt->getAddr());
 
     // Unlock the cpu-local monitor when the CPU sees a snoop to a locked
     // address. The CPU can speculatively execute a LL operation after a pending
     // SC operation in the pipeline and that can make the cache monitor the CPU
     // is connected to valid while it really shouldn't be.
-    for (int x = 0; x < cpu->numActiveThreads(); x++) {
+    for (int x = 0; x < cpu->numContexts(); x++) {
         ThreadContext *tc = cpu->getContext(x);
         bool no_squash = cpu->thread[x]->noSquashFromTC;
         cpu->thread[x]->noSquashFromTC = true;
@@ -446,13 +447,23 @@ LSQUnit<Impl>::checkSnoop(PacketPtr pkt)
         cpu->thread[x]->noSquashFromTC = no_squash;
     }
 
+    Addr invalidate_addr = pkt->getAddr() & cacheBlockMask;
+
+    DynInstPtr ld_inst = loadQueue[load_idx];
+    if (ld_inst) {
+        Addr load_addr = ld_inst->physEffAddr & cacheBlockMask;
+        // Check that this snoop didn't just invalidate our lock flag
+        if (ld_inst->effAddrValid() && load_addr == invalidate_addr &&
+            ld_inst->memReqFlags & Request::LLSC)
+            TheISA::handleLockedSnoopHit(ld_inst.get());
+    }
+
     // If this is the only load in the LSQ we don't care
     if (load_idx == loadTail)
         return;
+
     incrLdIdx(load_idx);
 
-    DPRINTF(LSQUnit, "Got snoop for address %#x\n", pkt->getAddr());
-    Addr invalidate_addr = pkt->getAddr() & cacheBlockMask;
     while (load_idx != loadTail) {
         DynInstPtr ld_inst = loadQueue[load_idx];
 
@@ -468,11 +479,20 @@ LSQUnit<Impl>::checkSnoop(PacketPtr pkt)
         if (load_addr == invalidate_addr) {
             if (ld_inst->possibleLoadViolation()) {
                 DPRINTF(LSQUnit, "Conflicting load at addr %#x [sn:%lli]\n",
-                        ld_inst->physEffAddr, pkt->getAddr(), ld_inst->seqNum);
+                        pkt->getAddr(), ld_inst->seqNum);
 
                 // Mark the load for re-execution
                 ld_inst->fault = new ReExec;
             } else {
+                DPRINTF(LSQUnit, "HitExternal Snoop for addr %#x [sn:%lli]\n",
+                        pkt->getAddr(), ld_inst->seqNum);
+
+                // Make sure that we don't lose a snoop hitting a LOCKED
+                // address since the LOCK* flags don't get updated until
+                // commit.
+                if (ld_inst->memReqFlags & Request::LLSC)
+                    TheISA::handleLockedSnoopHit(ld_inst.get());
+
                 // If a older load checks this and it's true
                 // then we might have missed the snoop
                 // in which case we need to invalidate to be sure
@@ -849,7 +869,7 @@ LSQUnit<Impl>::writebackStores()
             // misc regs normally updates the result, but this is not
             // the desired behavior when handling store conditionals.
             inst->recordResult(false);
-            bool success = TheISA::handleLockedWrite(inst.get(), req);
+            bool success = TheISA::handleLockedWrite(inst.get(), req, cacheBlockMask);
             inst->recordResult(true);
 
             if (!success) {
index 617e845a550b2c417ad602419bcd2a9c3305897c..b1efbc5ceae6f2e1bd98ecad0311ac4da8f31cec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012-2013 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -278,6 +278,36 @@ AtomicSimpleCPU::suspendContext(ThreadID thread_num)
 }
 
 
+Tick
+AtomicSimpleCPU::AtomicCPUDPort::recvAtomicSnoop(PacketPtr pkt)
+{
+    DPRINTF(SimpleCPU, "received snoop pkt for addr:%#x %s\n", pkt->getAddr(),
+            pkt->cmdString());
+
+    // if snoop invalidates, release any associated locks
+    if (pkt->isInvalidate()) {
+        DPRINTF(SimpleCPU, "received invalidation for addr:%#x\n",
+                pkt->getAddr());
+        TheISA::handleLockedSnoop(cpu->thread, pkt, cacheBlockMask);
+    }
+
+    return 0;
+}
+
+void
+AtomicSimpleCPU::AtomicCPUDPort::recvFunctionalSnoop(PacketPtr pkt)
+{
+    DPRINTF(SimpleCPU, "received snoop pkt for addr:%#x %s\n", pkt->getAddr(),
+            pkt->cmdString());
+
+    // if snoop invalidates, release any associated locks
+    if (pkt->isInvalidate()) {
+        DPRINTF(SimpleCPU, "received invalidation for addr:%#x\n",
+                pkt->getAddr());
+        TheISA::handleLockedSnoop(cpu->thread, pkt, cacheBlockMask);
+    }
+}
+
 Fault
 AtomicSimpleCPU::readMem(Addr addr, uint8_t * data,
                          unsigned size, unsigned flags)
@@ -402,7 +432,7 @@ AtomicSimpleCPU::writeMem(uint8_t *data, unsigned size,
 
             if (req->isLLSC()) {
                 cmd = MemCmd::StoreCondReq;
-                do_access = TheISA::handleLockedWrite(thread, req);
+                do_access = TheISA::handleLockedWrite(thread, req, dcachePort.cacheBlockMask);
             } else if (req->isSwap()) {
                 cmd = MemCmd::SwapReq;
                 if (req->isCondSwap()) {
index 7366213f86f21c21ab9457c06c31f99602171e7b..7426139e7e8d63e640d0ae8ab76f56f6baed0aa4 100644 (file)
@@ -147,17 +147,12 @@ class AtomicSimpleCPU : public BaseSimpleCPU
 
       public:
 
-        AtomicCPUPort(const std::string &_name, BaseCPU* _cpu)
+        AtomicCPUPort(const std::string &_name, BaseSimpleCPU* _cpu)
             : MasterPort(_name, _cpu)
         { }
 
       protected:
-
-        virtual Tick recvAtomicSnoop(PacketPtr pkt)
-        {
-            // Snooping a coherence request, just return
-            return 0;
-        }
+        virtual Tick recvAtomicSnoop(PacketPtr pkt) { return 0; }
 
         bool recvTimingResp(PacketPtr pkt)
         {
@@ -172,8 +167,30 @@ class AtomicSimpleCPU : public BaseSimpleCPU
 
     };
 
+    class AtomicCPUDPort : public AtomicCPUPort
+    {
+
+      public:
+
+        AtomicCPUDPort(const std::string &_name, BaseSimpleCPU* _cpu)
+            : AtomicCPUPort(_name, _cpu), cpu(_cpu)
+        {
+            cacheBlockMask = ~(cpu->cacheLineSize() - 1);
+        }
+
+        bool isSnooping() const { return true; }
+
+        Addr cacheBlockMask;
+      protected:
+        BaseSimpleCPU *cpu;
+
+        virtual Tick recvAtomicSnoop(PacketPtr pkt);
+        virtual void recvFunctionalSnoop(PacketPtr pkt);
+    };
+
+
     AtomicCPUPort icachePort;
-    AtomicCPUPort dcachePort;
+    AtomicCPUDPort dcachePort;
 
     bool fastmem;
     Request ifetch_req;
index 7996a6ddd96a6131213bddf60ab85e3ac4c8eb65..366164e36f0a074e6e0192f1851ce85d3ae9006d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012 ARM Limited
+ * Copyright (c) 2010-2013 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -96,6 +96,7 @@ TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
 }
 
 
+
 TimingSimpleCPU::~TimingSimpleCPU()
 {
 }
@@ -273,7 +274,7 @@ TimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res,
         bool do_access = true;  // flag to suppress cache access
 
         if (req->isLLSC()) {
-            do_access = TheISA::handleLockedWrite(thread, req);
+            do_access = TheISA::handleLockedWrite(thread, req, dcachePort.cacheBlockMask);
         } else if (req->isCondSwap()) {
             assert(res);
             req->setExtraData(*res);
@@ -813,6 +814,13 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
     advanceInst(fault);
 }
 
+void
+TimingSimpleCPU::DcachePort::recvTimingSnoopReq(PacketPtr pkt)
+{
+    TheISA::handleLockedSnoop(cpu->thread, pkt, cacheBlockMask);
+}
+
+
 bool
 TimingSimpleCPU::DcachePort::recvTimingResp(PacketPtr pkt)
 {
index 03264315e93803fd4e4491951204a15355b2e8d6..4a5a204299c8a49e1b92b8809c8ad26eb84a098b 100644 (file)
@@ -165,7 +165,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
         /**
          * Snooping a coherence request, do nothing.
          */
-        virtual void recvTimingSnoopReq(PacketPtr pkt) { }
+        virtual void recvTimingSnoopReq(PacketPtr pkt) {}
 
         TimingSimpleCPU* cpu;
 
@@ -217,10 +217,18 @@ class TimingSimpleCPU : public BaseSimpleCPU
         DcachePort(TimingSimpleCPU *_cpu)
             : TimingCPUPort(_cpu->name() + ".dcache_port", _cpu),
               tickEvent(_cpu)
-        { }
+        {
+           cacheBlockMask = ~(cpu->cacheLineSize() - 1);
+        }
 
+        Addr cacheBlockMask;
       protected:
 
+        /** Snoop a coherence request, we need to check if this causes
+         * a wakeup event on a cpu that is monitoring an address
+         */
+        virtual void recvTimingSnoopReq(PacketPtr pkt);
+
         virtual bool recvTimingResp(PacketPtr pkt);
 
         virtual void recvRetry();