cpu: fix problem with forwarding and locked load
authorAlec Roelke <ar4jc@virginia.edu>
Sun, 9 Apr 2017 19:23:23 +0000 (15:23 -0400)
committerAlec Roelke <ar4jc@virginia.edu>
Mon, 15 May 2017 19:30:14 +0000 (19:30 +0000)
If a (regular) store is followed closely enough by a locked load that
overlaps, the LSQ will forward the store's data to the locked load and
never tell the cache about the locked load.  As a result, the cache will
not lock the address and all future store-conditional requests on that
address will fail.  This patch fixes that by preventing forwarding if
the memory request is a locked load and adding another case to the LSQ
forwarding logic that delays the locked load request if a store in the
LSQ contains all or part of the data that is requested.

[Merge second and last if blocks because their bodies are the same.]

Change-Id: I895cc2b9570035267bdf6ae3fdc8a09049969841
Reviewed-on: https://gem5-review.googlesource.com/2400
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-by: Tony Gutierrez <anthony.gutierrez@amd.com>
Maintainer: Jason Lowe-Power <jason@lowepower.com>

src/cpu/o3/lsq_unit.hh

index 10d4966e87c3bddea0d707d717433f1d7bdcc013..9d885302ba25a0664cda3c658f8b3265d1fea440 100644 (file)
@@ -671,8 +671,9 @@ LSQUnit<Impl>::read(Request *req, Request *sreqLow, Request *sreqHigh,
             (req->getVaddr() + req->getSize()) >
             storeQueue[store_idx].inst->effAddr;
 
-        // If the store's data has all of the data needed, we can forward.
-        if ((store_has_lower_limit && store_has_upper_limit)) {
+        // If the store's data has all of the data needed and the load isn't
+        // LLSC, we can forward.
+        if (store_has_lower_limit && store_has_upper_limit && !req->isLLSC()) {
             // Get shift amount for offset into the store's data.
             int shift_amt = req->getVaddr() - storeQueue[store_idx].inst->effAddr;
 
@@ -707,11 +708,18 @@ LSQUnit<Impl>::read(Request *req, Request *sreqLow, Request *sreqHigh,
 
             ++lsqForwLoads;
             return NoFault;
-        } else if ((store_has_lower_limit && lower_load_has_store_part) ||
-                   (store_has_upper_limit && upper_load_has_store_part) ||
-                   (lower_load_has_store_part && upper_load_has_store_part)) {
+        } else if (
+                (!req->isLLSC() &&
+                 ((store_has_lower_limit && lower_load_has_store_part) ||
+                  (store_has_upper_limit && upper_load_has_store_part) ||
+                  (lower_load_has_store_part && upper_load_has_store_part))) ||
+                (req->isLLSC() &&
+                 ((store_has_lower_limit || upper_load_has_store_part) &&
+                  (store_has_upper_limit || lower_load_has_store_part)))) {
             // This is the partial store-load forwarding case where a store
-            // has only part of the load's data.
+            // has only part of the load's data and the load isn't LLSC or
+            // the load is LLSC and the store has all or part of the load's
+            // data
 
             // If it's already been written back, then don't worry about
             // stalling on it.