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>
This commit is contained in:
parent
27665af26d
commit
0dd0d4ee7a
2 changed files with 61 additions and 20 deletions
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -381,6 +381,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);
|
||||
|
|
Loading…
Reference in a new issue