mem: Add StreamID and SubstreamID

This patch adds StreamID and SubstreamID to Request. These fields can
be used by a SMMU/IOMMU model to pick up the correct translation
context for each request and they correspond to an ASID in a device.
For this reason they have been merged together with the request asid
in a union, so that a cpu will set the asid and a device will set
the Stream and Substream ID.

Change-Id: Iac2b5a1ba9c6598ee7635c30845dc68ba6787c34
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/12187
Reviewed-by: Anthony Gutierrez <anthony.gutierrez@amd.com>
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Jason Lowe-Power <jason@lowepower.com>
diff --git a/src/mem/request.hh b/src/mem/request.hh
index 189d160..3df29aa 100644
--- a/src/mem/request.hh
+++ b/src/mem/request.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013,2017 ARM Limited
+ * Copyright (c) 2012-2013,2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -257,7 +257,7 @@
     };
 
   private:
-    typedef uint8_t PrivateFlagsType;
+    typedef uint16_t PrivateFlagsType;
     typedef ::Flags<PrivateFlagsType> PrivateFlags;
 
     enum : PrivateFlagsType {
@@ -275,6 +275,9 @@
         VALID_CONTEXT_ID     = 0x00000020,
         /** Whether or not the sc result is valid. */
         VALID_EXTRA_DATA     = 0x00000080,
+        /** Whether or not the stream ID and substream ID is valid. */
+        VALID_STREAM_ID      = 0x00000100,
+        VALID_SUBSTREAM_ID   = 0x00000200,
         /**
          * These flags are *not* cleared when a Request object is reused
          * (assigned a new address).
@@ -343,8 +346,27 @@
      */
     uint32_t _taskId;
 
-    /** The address space ID. */
-    int _asid;
+    union {
+        struct {
+            /**
+             * The stream ID uniquely identifies a device behind the
+             * SMMU/IOMMU Each transaction arriving at the SMMU/IOMMU is
+             * associated with exactly one stream ID.
+             */
+            uint32_t  _streamId;
+
+            /**
+             * The substream ID identifies an "execution context" within a
+             * device behind an SMMU/IOMMU. It's intended to map 1-to-1 to
+             * PCIe PASID (Process Address Space ID). The presence of a
+             * substream ID is optional.
+             */
+            uint32_t _substreamId;
+        };
+
+        /** The address space ID. */
+        uint64_t _asid;
+    };
 
     /** The virtual address of the request. */
     Addr _vaddr;
@@ -431,8 +453,8 @@
         privateFlags.set(VALID_PC);
     }
 
-    Request(int asid, Addr vaddr, unsigned size, Flags flags, MasterID mid,
-            Addr pc, ContextID cid)
+    Request(uint64_t asid, Addr vaddr, unsigned size, Flags flags,
+            MasterID mid, Addr pc, ContextID cid)
         : _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
           _taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
           _extraData(0), _contextId(0), _pc(0),
@@ -443,8 +465,9 @@
         setContext(cid);
     }
 
-    Request(int asid, Addr vaddr, unsigned size, Flags flags, MasterID mid,
-            Addr pc, ContextID cid, AtomicOpFunctor *atomic_op)
+    Request(uint64_t asid, Addr vaddr, unsigned size, Flags flags,
+            MasterID mid, Addr pc, ContextID cid,
+            AtomicOpFunctor *atomic_op)
     {
         setVirt(asid, vaddr, size, flags, mid, pc, atomic_op);
         setContext(cid);
@@ -486,13 +509,28 @@
         privateFlags.set(VALID_CONTEXT_ID);
     }
 
+    void
+    setStreamId(uint32_t sid)
+    {
+        _streamId = sid;
+        privateFlags.set(VALID_STREAM_ID);
+    }
+
+    void
+    setSubStreamId(uint32_t ssid)
+    {
+        assert(privateFlags.isSet(VALID_STREAM_ID));
+        _substreamId = ssid;
+        privateFlags.set(VALID_SUBSTREAM_ID);
+    }
+
     /**
      * Set up a virtual (e.g., CPU) request in a previously
      * allocated Request object.
      */
     void
-    setVirt(int asid, Addr vaddr, unsigned size, Flags flags, MasterID mid,
-            Addr pc, AtomicOpFunctor *amo_op = nullptr)
+    setVirt(uint64_t asid, Addr vaddr, unsigned size, Flags flags,
+            MasterID mid, Addr pc, AtomicOpFunctor *amo_op = nullptr)
     {
         _asid = asid;
         _vaddr = vaddr;
@@ -673,7 +711,7 @@
     }
 
     /** Accessor function for asid.*/
-    int
+    uint64_t
     getAsid() const
     {
         assert(privateFlags.isSet(VALID_VADDR));
@@ -682,7 +720,7 @@
 
     /** Accessor function for asid.*/
     void
-    setAsid(int asid)
+    setAsid(uint64_t asid)
     {
         _asid = asid;
     }
@@ -732,6 +770,26 @@
         return _contextId;
     }
 
+    uint32_t
+    streamId() const
+    {
+        assert(privateFlags.isSet(VALID_STREAM_ID));
+        return _streamId;
+    }
+
+    bool
+    hasSubstreamId() const
+    {
+        return privateFlags.isSet(VALID_SUBSTREAM_ID);
+    }
+
+    uint32_t
+    substreamId() const
+    {
+        assert(privateFlags.isSet(VALID_SUBSTREAM_ID));
+        return _substreamId;
+    }
+
     void
     setPC(Addr pc)
     {