mem: Add support for cache maintenance operation requests

This change adds new packet cmds and request flags for cache
maintenance operations.

1) A cache clean operation writes dirty data in the first memory below
the specified xbar and updates any old copies in the memories above
it.
2) A cache invalidate operation invalidates all copies of the
specified block in the memories above the specified xbar
3) A clean and invalidate operation is a combination of the two
operations above

Change-Id: If45702848bdd568de532cd57cba58499e5e4354c
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Curtis Dunham <curtis.dunham@arm.com>
Reviewed-by: Anouk Van Laer <anouk.vanlaer@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/5047
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
diff --git a/src/mem/packet.cc b/src/mem/packet.cc
index 8c44172..ffda3d5 100644
--- a/src/mem/packet.cc
+++ b/src/mem/packet.cc
@@ -184,6 +184,24 @@
     {SET2(IsRequest, NeedsResponse), MemFenceResp, "MemFenceReq"},
     /* MemFenceResp -- for synchronization responses */
     {SET1(IsResponse), InvalidCmd, "MemFenceResp"},
+    /* Cache Clean Request -- Update with the latest data all existing
+       copies of the block down to the point indicated by the
+       request */
+    { SET4(IsRequest, IsClean, NeedsResponse, FromCache),
+      CleanSharedResp, "CleanSharedReq" },
+    /* Cache Clean Response - Indicates that all caches up to the
+       specified point of reference have a up-to-date copy of the
+       cache block or no copy at all */
+    { SET2(IsResponse, IsClean), InvalidCmd, "CleanSharedResp" },
+    /* Cache Clean and Invalidate Request -- Invalidate all existing
+       copies down to the point indicated by the request */
+    { SET5(IsRequest, IsInvalidate, IsClean, NeedsResponse, FromCache),
+      CleanInvalidResp, "CleanInvalidReq" },
+     /* Cache Clean and Invalidate Respose -- Indicates that no cache
+        above the specified point holds the block and that the block
+        was written to a memory below the specified point. */
+    { SET3(IsResponse, IsInvalidate, IsClean),
+      InvalidCmd, "CleanInvalidResp" },
     /* InvalidDestError  -- packet dest field invalid */
     { SET2(IsResponse, IsError), InvalidCmd, "InvalidDestError" },
     /* BadAddressError   -- memory address invalid */
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
index 325cd3a..fcdd73a 100644
--- a/src/mem/packet.hh
+++ b/src/mem/packet.hh
@@ -114,6 +114,10 @@
         MessageResp,
         MemFenceReq,
         MemFenceResp,
+        CleanSharedReq,
+        CleanSharedResp,
+        CleanInvalidReq,
+        CleanInvalidResp,
         // Error responses
         // @TODO these should be classified as responses rather than
         // requests; coding them as requests initially for backwards
@@ -140,6 +144,7 @@
         IsWrite,        //!< Data flows from requester to responder
         IsUpgrade,
         IsInvalidate,
+        IsClean,        //!< Cleans any existing dirty blocks
         NeedsWritable,  //!< Requires writable copy to complete in-cache
         IsRequest,      //!< Issued by requester
         IsResponse,     //!< Issue by responder
@@ -195,6 +200,7 @@
     bool needsResponse() const     { return testCmdAttrib(NeedsResponse); }
     bool isInvalidate() const      { return testCmdAttrib(IsInvalidate); }
     bool isEviction() const        { return testCmdAttrib(IsEviction); }
+    bool isClean() const           { return testCmdAttrib(IsClean); }
     bool fromCache() const         { return testCmdAttrib(FromCache); }
 
     /**
@@ -521,6 +527,7 @@
     bool needsResponse() const       { return cmd.needsResponse(); }
     bool isInvalidate() const        { return cmd.isInvalidate(); }
     bool isEviction() const          { return cmd.isEviction(); }
+    bool isClean() const             { return cmd.isClean(); }
     bool fromCache() const           { return cmd.fromCache(); }
     bool isWriteback() const         { return cmd.isWriteback(); }
     bool hasData() const             { return cmd.hasData(); }
@@ -815,7 +822,12 @@
             return MemCmd::StoreCondReq;
         else if (req->isSwap())
             return MemCmd::SwapReq;
-        else
+        else if (req->isCacheInvalidate()) {
+          return req->isCacheClean() ? MemCmd::CleanInvalidReq :
+              MemCmd::InvalidateReq;
+        } else if (req->isCacheClean()) {
+            return MemCmd::CleanSharedReq;
+        } else
             return MemCmd::WriteReq;
     }
 
diff --git a/src/mem/request.hh b/src/mem/request.hh
index 6fc9850..2586935 100644
--- a/src/mem/request.hh
+++ b/src/mem/request.hh
@@ -182,6 +182,11 @@
         /** The request is a page table walk */
         PT_WALK                     = 0x20000000,
 
+        /** The request invalidates a memory location */
+        INVALIDATE                  = 0x0000000100000000,
+        /** The request cleans a memory location */
+        CLEAN                       = 0x0000000200000000,
+
         /** The request targets the point of unification */
         DST_POU                     = 0x0000001000000000,
 
@@ -889,6 +894,23 @@
     {
         return _memSpaceConfigFlags.isSet(ARG_SEGMENT);
     }
+
+    /**
+     * Accessor functions to determine whether this request is part of
+     * a cache maintenance operation. At the moment three operations
+     * are supported:
+
+     * 1) A cache clean operation updates all copies of a memory
+     * location to the point of reference,
+     * 2) A cache invalidate operation invalidates all copies of the
+     * specified block in the memory above the point of reference,
+     * 3) A clean and invalidate operation is a combination of the two
+     * operations.
+     * @{ */
+    bool isCacheClean() const { return _flags.isSet(CLEAN); }
+    bool isCacheInvalidate() const { return _flags.isSet(INVALIDATE); }
+    bool isCacheMaintenance() const { return _flags.isSet(CLEAN|INVALIDATE); }
+    /** @} */
 };
 
 #endif // __MEM_REQUEST_HH__