From c8c406bc305a6bf52304d5f158f5d8def0dea51f Mon Sep 17 00:00:00 2001 From: Alec Roelke Date: Sun, 9 Apr 2017 15:23:23 -0400 Subject: cpu: fix problem with forwarding and locked load 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 Reviewed-by: Nikos Nikoleris Reviewed-by: Tony Gutierrez Maintainer: Jason Lowe-Power --- src/cpu/o3/lsq_unit.hh | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'src/cpu/o3') diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh index 10d4966e8..9d885302b 100644 --- a/src/cpu/o3/lsq_unit.hh +++ b/src/cpu/o3/lsq_unit.hh @@ -671,8 +671,9 @@ LSQUnit::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::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. -- cgit v1.2.3