energy_ctrl.cc revision 13230
110396Sakash.bagdia@arm.com/* 210396Sakash.bagdia@arm.com * Copyright (c) 2012-2014 ARM Limited 310396Sakash.bagdia@arm.com * All rights reserved 410396Sakash.bagdia@arm.com * 510396Sakash.bagdia@arm.com * The license below extends only to copyright in the software and shall 610396Sakash.bagdia@arm.com * not be construed as granting a license to any other intellectual 710396Sakash.bagdia@arm.com * property including but not limited to intellectual property relating 810396Sakash.bagdia@arm.com * to a hardware implementation of the functionality of the software 910396Sakash.bagdia@arm.com * licensed hereunder. You may use the software subject to the license 1010396Sakash.bagdia@arm.com * terms below provided that you ensure that this notice is replicated 1110396Sakash.bagdia@arm.com * unmodified and in its entirety in all distributions of the software, 1210396Sakash.bagdia@arm.com * modified or unmodified, in source code or in binary form. 1310396Sakash.bagdia@arm.com * 1410396Sakash.bagdia@arm.com * Redistribution and use in source and binary forms, with or without 1510396Sakash.bagdia@arm.com * modification, are permitted provided that the following conditions are 1610396Sakash.bagdia@arm.com * met: redistributions of source code must retain the above copyright 1710396Sakash.bagdia@arm.com * notice, this list of conditions and the following disclaimer; 1810396Sakash.bagdia@arm.com * redistributions in binary form must reproduce the above copyright 1910396Sakash.bagdia@arm.com * notice, this list of conditions and the following disclaimer in the 2010396Sakash.bagdia@arm.com * documentation and/or other materials provided with the distribution; 2110396Sakash.bagdia@arm.com * neither the name of the copyright holders nor the names of its 2210396Sakash.bagdia@arm.com * contributors may be used to endorse or promote products derived from 2310396Sakash.bagdia@arm.com * this software without specific prior written permission. 2410396Sakash.bagdia@arm.com * 2510396Sakash.bagdia@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2610396Sakash.bagdia@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2710396Sakash.bagdia@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2810396Sakash.bagdia@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910396Sakash.bagdia@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010396Sakash.bagdia@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3110396Sakash.bagdia@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3210396Sakash.bagdia@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3310396Sakash.bagdia@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3410396Sakash.bagdia@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3510396Sakash.bagdia@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3610396Sakash.bagdia@arm.com * 3710396Sakash.bagdia@arm.com * Authors: Vasileios Spiliopoulos 3810396Sakash.bagdia@arm.com * Akash Bagdia 3910396Sakash.bagdia@arm.com * Stephan Diestelhorst 4010396Sakash.bagdia@arm.com */ 4110396Sakash.bagdia@arm.com 4211793Sbrandon.potter@amd.com#include "dev/arm/energy_ctrl.hh" 4311793Sbrandon.potter@amd.com 4410396Sakash.bagdia@arm.com#include "debug/EnergyCtrl.hh" 4510396Sakash.bagdia@arm.com#include "mem/packet.hh" 4610396Sakash.bagdia@arm.com#include "mem/packet_access.hh" 4710396Sakash.bagdia@arm.com#include "params/EnergyCtrl.hh" 4810396Sakash.bagdia@arm.com#include "sim/dvfs_handler.hh" 4910396Sakash.bagdia@arm.com 5010396Sakash.bagdia@arm.comEnergyCtrl::EnergyCtrl(const Params *p) 5110396Sakash.bagdia@arm.com : BasicPioDevice(p, PIO_NUM_FIELDS * 4), // each field is 32 bit 5210396Sakash.bagdia@arm.com dvfsHandler(p->dvfs_handler), 5310396Sakash.bagdia@arm.com domainID(0), 5410396Sakash.bagdia@arm.com domainIDIndexToRead(0), 5510396Sakash.bagdia@arm.com perfLevelAck(0), 5610396Sakash.bagdia@arm.com perfLevelToRead(0), 5712086Sspwilson2@wisc.edu updateAckEvent([this]{ updatePLAck(); }, name()) 5810396Sakash.bagdia@arm.com{ 5910396Sakash.bagdia@arm.com fatal_if(!p->dvfs_handler, "EnergyCtrl: Needs a DVFSHandler for a " 6010396Sakash.bagdia@arm.com "functioning system.\n"); 6110396Sakash.bagdia@arm.com} 6210396Sakash.bagdia@arm.com 6310396Sakash.bagdia@arm.comTick 6410396Sakash.bagdia@arm.comEnergyCtrl::read(PacketPtr pkt) 6510396Sakash.bagdia@arm.com{ 6610396Sakash.bagdia@arm.com assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 6710396Sakash.bagdia@arm.com assert(pkt->getSize() == 4); 6810396Sakash.bagdia@arm.com 6910396Sakash.bagdia@arm.com Addr daddr = pkt->getAddr() - pioAddr; 7010396Sakash.bagdia@arm.com assert((daddr & 3) == 0); 7110396Sakash.bagdia@arm.com Registers reg = Registers(daddr / 4); 7210396Sakash.bagdia@arm.com 7310396Sakash.bagdia@arm.com if (!dvfsHandler->isEnabled()) { 7410396Sakash.bagdia@arm.com // NB: Zero is a good response if the handler is disabled 7513230Sgabeblack@google.com pkt->setLE<uint32_t>(0); 7610396Sakash.bagdia@arm.com warn_once("EnergyCtrl: Disabled handler, ignoring read from reg %i\n", 7710396Sakash.bagdia@arm.com reg); 7810396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "dvfs handler disabled, return 0 for read from "\ 7910396Sakash.bagdia@arm.com "reg %i\n", reg); 8010396Sakash.bagdia@arm.com pkt->makeAtomicResponse(); 8110396Sakash.bagdia@arm.com return pioDelay; 8210396Sakash.bagdia@arm.com } 8310396Sakash.bagdia@arm.com 8410396Sakash.bagdia@arm.com uint32_t result = 0; 8510396Sakash.bagdia@arm.com Tick period; 8610396Sakash.bagdia@arm.com double voltage; 8710396Sakash.bagdia@arm.com 8810396Sakash.bagdia@arm.com switch(reg) { 8910396Sakash.bagdia@arm.com case DVFS_HANDLER_STATUS: 9010396Sakash.bagdia@arm.com result = 1; 9110396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "dvfs handler enabled\n"); 9210396Sakash.bagdia@arm.com break; 9310396Sakash.bagdia@arm.com case DVFS_NUM_DOMAINS: 9410396Sakash.bagdia@arm.com result = dvfsHandler->numDomains(); 9510396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "reading number of domains %d\n", result); 9610396Sakash.bagdia@arm.com break; 9710396Sakash.bagdia@arm.com case DVFS_DOMAINID_AT_INDEX: 9810396Sakash.bagdia@arm.com result = dvfsHandler->domainID(domainIDIndexToRead); 9910396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "reading domain id at index %d as %d\n", 10010396Sakash.bagdia@arm.com domainIDIndexToRead, result); 10110396Sakash.bagdia@arm.com break; 10210396Sakash.bagdia@arm.com case DVFS_HANDLER_TRANS_LATENCY: 10310396Sakash.bagdia@arm.com // Return transition latency in nanoseconds 10410396Sakash.bagdia@arm.com result = dvfsHandler->transLatency() / SimClock::Int::ns; 10510396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "reading dvfs handler trans latency %d ns\n", 10610396Sakash.bagdia@arm.com result); 10710396Sakash.bagdia@arm.com break; 10810396Sakash.bagdia@arm.com case DOMAIN_ID: 10910396Sakash.bagdia@arm.com result = domainID; 11010396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "reading domain id:%d\n", result); 11110396Sakash.bagdia@arm.com break; 11210396Sakash.bagdia@arm.com case PERF_LEVEL: 11310396Sakash.bagdia@arm.com result = dvfsHandler->perfLevel(domainID); 11410396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "reading domain %d perf level: %d\n", 11510396Sakash.bagdia@arm.com domainID, result); 11610396Sakash.bagdia@arm.com break; 11710396Sakash.bagdia@arm.com case PERF_LEVEL_ACK: 11810396Sakash.bagdia@arm.com result = perfLevelAck; 11910396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "reading ack:%d\n", result); 12010396Sakash.bagdia@arm.com // Signal is set for a single read only 12110396Sakash.bagdia@arm.com if (result == 1) 12210396Sakash.bagdia@arm.com perfLevelAck = 0; 12310396Sakash.bagdia@arm.com break; 12410396Sakash.bagdia@arm.com case NUM_OF_PERF_LEVELS: 12510396Sakash.bagdia@arm.com result = dvfsHandler->numPerfLevels(domainID); 12610396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "reading num of perf level:%d\n", result); 12710396Sakash.bagdia@arm.com break; 12810396Sakash.bagdia@arm.com case FREQ_AT_PERF_LEVEL: 12910396Sakash.bagdia@arm.com period = dvfsHandler->clkPeriodAtPerfLevel(domainID, perfLevelToRead); 13010396Sakash.bagdia@arm.com result = ticksTokHz(period); 13110396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "reading freq %d KHz at perf level: %d\n", 13210396Sakash.bagdia@arm.com result, perfLevelToRead); 13310396Sakash.bagdia@arm.com break; 13410396Sakash.bagdia@arm.com case VOLT_AT_PERF_LEVEL: 13510396Sakash.bagdia@arm.com voltage = dvfsHandler->voltageAtPerfLevel(domainID, perfLevelToRead); 13610396Sakash.bagdia@arm.com result = toMicroVolt(voltage); 13710396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "reading voltage %d u-volt at perf level: %d\n", 13810396Sakash.bagdia@arm.com result, perfLevelToRead); 13910396Sakash.bagdia@arm.com break; 14010396Sakash.bagdia@arm.com default: 14110396Sakash.bagdia@arm.com panic("Tried to read EnergyCtrl at offset %#x / reg %i\n", daddr, 14210396Sakash.bagdia@arm.com reg); 14310396Sakash.bagdia@arm.com } 14413230Sgabeblack@google.com pkt->setLE<uint32_t>(result); 14510396Sakash.bagdia@arm.com pkt->makeAtomicResponse(); 14610396Sakash.bagdia@arm.com return pioDelay; 14710396Sakash.bagdia@arm.com} 14810396Sakash.bagdia@arm.com 14910396Sakash.bagdia@arm.comTick 15010396Sakash.bagdia@arm.comEnergyCtrl::write(PacketPtr pkt) 15110396Sakash.bagdia@arm.com{ 15210396Sakash.bagdia@arm.com assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 15310396Sakash.bagdia@arm.com assert(pkt->getSize() == 4); 15410396Sakash.bagdia@arm.com 15510396Sakash.bagdia@arm.com uint32_t data; 15613230Sgabeblack@google.com data = pkt->getLE<uint32_t>(); 15710396Sakash.bagdia@arm.com 15810396Sakash.bagdia@arm.com Addr daddr = pkt->getAddr() - pioAddr; 15910396Sakash.bagdia@arm.com assert((daddr & 3) == 0); 16010396Sakash.bagdia@arm.com Registers reg = Registers(daddr / 4); 16110396Sakash.bagdia@arm.com 16210396Sakash.bagdia@arm.com if (!dvfsHandler->isEnabled()) { 16310396Sakash.bagdia@arm.com // Ignore writes to a disabled controller 16410396Sakash.bagdia@arm.com warn_once("EnergyCtrl: Disabled handler, ignoring write %u to "\ 16510396Sakash.bagdia@arm.com "reg %i\n", data, reg); 16610396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "dvfs handler disabled, ignoring write %u to "\ 16710396Sakash.bagdia@arm.com "reg %i\n", data, reg); 16810396Sakash.bagdia@arm.com pkt->makeAtomicResponse(); 16910396Sakash.bagdia@arm.com return pioDelay; 17010396Sakash.bagdia@arm.com } 17110396Sakash.bagdia@arm.com 17210396Sakash.bagdia@arm.com switch(reg) { 17310396Sakash.bagdia@arm.com case DVFS_DOMAINID_AT_INDEX: 17410396Sakash.bagdia@arm.com domainIDIndexToRead = data; 17510396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "writing domain id index:%d\n", 17610396Sakash.bagdia@arm.com domainIDIndexToRead); 17710396Sakash.bagdia@arm.com break; 17810396Sakash.bagdia@arm.com case DOMAIN_ID: 17910396Sakash.bagdia@arm.com // Extra check to ensure that a valid domain ID is being queried 18010396Sakash.bagdia@arm.com if (dvfsHandler->validDomainID(data)) { 18110396Sakash.bagdia@arm.com domainID = data; 18210396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "writing domain id:%d\n", domainID); 18310396Sakash.bagdia@arm.com } else { 18410396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "invalid domain id:%d\n", domainID); 18510396Sakash.bagdia@arm.com } 18610396Sakash.bagdia@arm.com break; 18710396Sakash.bagdia@arm.com case PERF_LEVEL: 18810396Sakash.bagdia@arm.com if (dvfsHandler->perfLevel(domainID, data)) { 18910396Sakash.bagdia@arm.com if (updateAckEvent.scheduled()) { 19010396Sakash.bagdia@arm.com // The OS driver is trying to change the perf level while 19110396Sakash.bagdia@arm.com // another change is in flight. This is fine, but only a 19210396Sakash.bagdia@arm.com // single acknowledgment will be sent. 19310396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "descheduling previous pending ack "\ 19410396Sakash.bagdia@arm.com "event\n"); 19510396Sakash.bagdia@arm.com deschedule(updateAckEvent); 19610396Sakash.bagdia@arm.com } 19710396Sakash.bagdia@arm.com schedule(updateAckEvent, curTick() + dvfsHandler->transLatency()); 19810396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "writing domain %d perf level: %d\n", 19910396Sakash.bagdia@arm.com domainID, data); 20010396Sakash.bagdia@arm.com } else { 20110396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "invalid / ineffective perf level:%d for "\ 20210396Sakash.bagdia@arm.com "domain:%d\n", data, domainID); 20310396Sakash.bagdia@arm.com } 20410396Sakash.bagdia@arm.com break; 20510396Sakash.bagdia@arm.com case PERF_LEVEL_TO_READ: 20610396Sakash.bagdia@arm.com perfLevelToRead = data; 20710396Sakash.bagdia@arm.com DPRINTF(EnergyCtrl, "writing perf level to read opp at: %d\n", 20810396Sakash.bagdia@arm.com data); 20910396Sakash.bagdia@arm.com break; 21010396Sakash.bagdia@arm.com default: 21110396Sakash.bagdia@arm.com panic("Tried to write EnergyCtrl at offset %#x\n", daddr); 21210396Sakash.bagdia@arm.com break; 21310396Sakash.bagdia@arm.com } 21410396Sakash.bagdia@arm.com 21510396Sakash.bagdia@arm.com pkt->makeAtomicResponse(); 21610396Sakash.bagdia@arm.com return pioDelay; 21710396Sakash.bagdia@arm.com} 21810396Sakash.bagdia@arm.com 21910396Sakash.bagdia@arm.comvoid 22010905Sandreas.sandberg@arm.comEnergyCtrl::serialize(CheckpointOut &cp) const 22110396Sakash.bagdia@arm.com{ 22210396Sakash.bagdia@arm.com SERIALIZE_SCALAR(domainID); 22310396Sakash.bagdia@arm.com SERIALIZE_SCALAR(domainIDIndexToRead); 22410396Sakash.bagdia@arm.com SERIALIZE_SCALAR(perfLevelToRead); 22510396Sakash.bagdia@arm.com SERIALIZE_SCALAR(perfLevelAck); 22610396Sakash.bagdia@arm.com 22710396Sakash.bagdia@arm.com Tick next_event = updateAckEvent.scheduled() ? updateAckEvent.when() : 0; 22810396Sakash.bagdia@arm.com SERIALIZE_SCALAR(next_event); 22910396Sakash.bagdia@arm.com} 23010396Sakash.bagdia@arm.com 23110396Sakash.bagdia@arm.comvoid 23210905Sandreas.sandberg@arm.comEnergyCtrl::unserialize(CheckpointIn &cp) 23310396Sakash.bagdia@arm.com{ 23410396Sakash.bagdia@arm.com UNSERIALIZE_SCALAR(domainID); 23510396Sakash.bagdia@arm.com UNSERIALIZE_SCALAR(domainIDIndexToRead); 23610396Sakash.bagdia@arm.com UNSERIALIZE_SCALAR(perfLevelToRead); 23710396Sakash.bagdia@arm.com UNSERIALIZE_SCALAR(perfLevelAck); 23810396Sakash.bagdia@arm.com Tick next_event = 0; 23910396Sakash.bagdia@arm.com UNSERIALIZE_SCALAR(next_event); 24010396Sakash.bagdia@arm.com 24110396Sakash.bagdia@arm.com // restore scheduled events 24210396Sakash.bagdia@arm.com if (next_event != 0) { 24310396Sakash.bagdia@arm.com schedule(updateAckEvent, next_event); 24410396Sakash.bagdia@arm.com } 24510396Sakash.bagdia@arm.com} 24610396Sakash.bagdia@arm.com 24710396Sakash.bagdia@arm.comEnergyCtrl * EnergyCtrlParams::create() 24810396Sakash.bagdia@arm.com{ 24910396Sakash.bagdia@arm.com return new EnergyCtrl(this); 25010396Sakash.bagdia@arm.com} 25110396Sakash.bagdia@arm.com 25210396Sakash.bagdia@arm.comvoid 25310396Sakash.bagdia@arm.comEnergyCtrl::startup() 25410396Sakash.bagdia@arm.com{ 25510396Sakash.bagdia@arm.com if (!dvfsHandler->isEnabled()) { 25610396Sakash.bagdia@arm.com warn("Existing EnergyCtrl, but no enabled DVFSHandler found.\n"); 25710396Sakash.bagdia@arm.com } 25810396Sakash.bagdia@arm.com} 25910396Sakash.bagdia@arm.com 26010396Sakash.bagdia@arm.comvoid 26110396Sakash.bagdia@arm.comEnergyCtrl::init() 26210396Sakash.bagdia@arm.com{ 26310396Sakash.bagdia@arm.com BasicPioDevice::init(); 26410396Sakash.bagdia@arm.com} 265