summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
authorWendy Elsasser <wendy.elsasser@arm.com>2016-10-13 19:22:11 +0100
committerWendy Elsasser <wendy.elsasser@arm.com>2016-10-13 19:22:11 +0100
commit0dd0d4ee7adb561e89a47c3e8284c237bebdc4ab (patch)
treea82aca322b5ba7be0bb924c7c12424aaeae39f15 /src/mem
parent27665af26d8bfdeaab3f3877da9158c9fc5f93ac (diff)
downloadgem5-0dd0d4ee7adb561e89a47c3e8284c237bebdc4ab.tar.xz
mem: Modify drain to ensure banks and power are idled
Add constraint that all ranks have to be in PWR_IDLE before signaling drain complete This will ensure that the banks are all closed and the rank has exited any low-power states. On suspend, update the power stats to sync the DRAM power logic The logic maintains the location of the signalDrainDone method, which is still triggered from either: 1) Read response event 2) Next request event This ensures that the drain will complete in the READ bus state and minimizes the changes required. Change-Id: If1476e631ea7d5999fe50a0c9379c5967a90e3d1 Reviewed-by: Radhika Jagtap <radhika.jagtap@arm.com>
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/dram_ctrl.cc61
-rw-r--r--src/mem/dram_ctrl.hh20
2 files changed, 61 insertions, 20 deletions
diff --git a/src/mem/dram_ctrl.cc b/src/mem/dram_ctrl.cc
index 51131a6a7..e13c2af02 100644
--- a/src/mem/dram_ctrl.cc
+++ b/src/mem/dram_ctrl.cc
@@ -684,7 +684,7 @@ DRAMCtrl::processRespondEvent()
} else {
// if there is nothing left in any queue, signal a drain
if (drainState() == DrainState::Draining &&
- writeQueue.empty() && readQueue.empty()) {
+ writeQueue.empty() && readQueue.empty() && allRanksDrained()) {
DPRINTF(Drain, "DRAM controller done draining\n");
signalDrainDone();
@@ -1288,8 +1288,11 @@ DRAMCtrl::processNextReqEvent()
switch_to_writes = true;
} else {
// check if we are drained
+ // not done draining until in PWR_IDLE state
+ // ensuring all banks are closed and
+ // have exited low power states
if (drainState() == DrainState::Draining &&
- respQueue.empty()) {
+ respQueue.empty() && allRanksDrained()) {
DPRINTF(Drain, "DRAM controller done draining\n");
signalDrainDone();
@@ -1538,6 +1541,9 @@ void
DRAMCtrl::Rank::suspend()
{
deschedule(refreshEvent);
+
+ // Update the stats
+ updatePowerStats();
}
void
@@ -1708,23 +1714,6 @@ DRAMCtrl::Rank::processRefreshEvent()
// at the moment this affects all ranks
cmdList.push_back(Command(MemCommand::REF, 0, curTick()));
- // All commands up to refresh have completed
- // flush cmdList to DRAMPower
- flushCmdList();
-
- // update the counters for DRAMPower, passing false to
- // indicate that this is not the last command in the
- // list. DRAMPower requires this information for the
- // correct calculation of the background energy at the end
- // of the simulation. Ideally we would want to call this
- // function with true once at the end of the
- // simulation. However, the discarded energy is extremly
- // small and does not effect the final results.
- power.powerlib.updateCounters(false);
-
- // call the energy function
- power.powerlib.calcEnergy();
-
// Update the stats
updatePowerStats();
@@ -1833,6 +1822,23 @@ DRAMCtrl::Rank::processPowerEvent()
void
DRAMCtrl::Rank::updatePowerStats()
{
+ // All commands up to refresh have completed
+ // flush cmdList to DRAMPower
+ flushCmdList();
+
+ // update the counters for DRAMPower, passing false to
+ // indicate that this is not the last command in the
+ // list. DRAMPower requires this information for the
+ // correct calculation of the background energy at the end
+ // of the simulation. Ideally we would want to call this
+ // function with true once at the end of the
+ // simulation. However, the discarded energy is extremly
+ // small and does not effect the final results.
+ power.powerlib.updateCounters(false);
+
+ // call the energy function
+ power.powerlib.calcEnergy();
+
// Get the energy and power from DRAMPower
Data::MemoryPowerModel::Energy energy =
power.powerlib.getEnergy();
@@ -2182,7 +2188,9 @@ DRAMCtrl::drain()
{
// if there is anything in any of our internal queues, keep track
// of that as well
- if (!(writeQueue.empty() && readQueue.empty() && respQueue.empty())) {
+ if (!(writeQueue.empty() && readQueue.empty() && respQueue.empty() &&
+ allRanksDrained())) {
+
DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d,"
" resp: %d\n", writeQueue.size(), readQueue.size(),
respQueue.size());
@@ -2198,6 +2206,19 @@ DRAMCtrl::drain()
}
}
+bool
+DRAMCtrl::allRanksDrained() const
+{
+ // true until proven false
+ bool all_ranks_drained = true;
+ for (auto r : ranks) {
+ // then verify that the power state is IDLE
+ // ensuring all banks are closed and rank is not in a low power state
+ all_ranks_drained = r->inPwrIdleState() && all_ranks_drained;
+ }
+ return all_ranks_drained;
+}
+
void
DRAMCtrl::drainResume()
{
diff --git a/src/mem/dram_ctrl.hh b/src/mem/dram_ctrl.hh
index 70b737652..79a68af4b 100644
--- a/src/mem/dram_ctrl.hh
+++ b/src/mem/dram_ctrl.hh
@@ -382,6 +382,15 @@ class DRAMCtrl : public AbstractMemory
bool isAvailable() const { return refreshState == REF_IDLE; }
/**
+ * Check if the current rank has all banks closed and is not
+ * in a low power state
+ *
+ * @param Return true if the rank is idle from a bank
+ * and power point of view
+ */
+ bool inPwrIdleState() const { return pwrState == PWR_IDLE; }
+
+ /**
* Let the rank check if it was waiting for requests to drain
* to allow it to transition states.
*/
@@ -913,6 +922,17 @@ class DRAMCtrl : public AbstractMemory
virtual void startup() override;
virtual void drainResume() override;
+ /**
+ * Return true once refresh is complete for all ranks and there are no
+ * additional commands enqueued. (only evaluated when draining)
+ * This will ensure that all banks are closed, power state is IDLE, and
+ * power stats have been updated
+ *
+ * @return true if all ranks have refreshed, with no commands enqueued
+ *
+ */
+ bool allRanksDrained() const;
+
protected:
Tick recvAtomic(PacketPtr pkt);