energy_ctrl.cc revision 10905
15217Ssaidi@eecs.umich.edu/* 25217Ssaidi@eecs.umich.edu * Copyright (c) 2012-2014 ARM Limited 35217Ssaidi@eecs.umich.edu * All rights reserved 45217Ssaidi@eecs.umich.edu * 55217Ssaidi@eecs.umich.edu * The license below extends only to copyright in the software and shall 65217Ssaidi@eecs.umich.edu * not be construed as granting a license to any other intellectual 75217Ssaidi@eecs.umich.edu * property including but not limited to intellectual property relating 85217Ssaidi@eecs.umich.edu * to a hardware implementation of the functionality of the software 95217Ssaidi@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 105217Ssaidi@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 115217Ssaidi@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 125217Ssaidi@eecs.umich.edu * modified or unmodified, in source code or in binary form. 135217Ssaidi@eecs.umich.edu * 145217Ssaidi@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 155217Ssaidi@eecs.umich.edu * modification, are permitted provided that the following conditions are 165217Ssaidi@eecs.umich.edu * met: redistributions of source code must retain the above copyright 175217Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 185217Ssaidi@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 195217Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 205217Ssaidi@eecs.umich.edu * documentation and/or other materials provided with the distribution; 215217Ssaidi@eecs.umich.edu * neither the name of the copyright holders nor the names of its 225217Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from 235217Ssaidi@eecs.umich.edu * this software without specific prior written permission. 245217Ssaidi@eecs.umich.edu * 255217Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 265217Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 275217Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 285217Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 295217Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 305217Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 315217Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 325217Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 336658Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 345217Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 355217Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 365217Ssaidi@eecs.umich.edu * 375217Ssaidi@eecs.umich.edu * Authors: Vasileios Spiliopoulos 385217Ssaidi@eecs.umich.edu * Akash Bagdia 395217Ssaidi@eecs.umich.edu * Stephan Diestelhorst 405217Ssaidi@eecs.umich.edu */ 415217Ssaidi@eecs.umich.edu 425217Ssaidi@eecs.umich.edu#include "debug/EnergyCtrl.hh" 435217Ssaidi@eecs.umich.edu#include "dev/arm/energy_ctrl.hh" 445217Ssaidi@eecs.umich.edu#include "mem/packet.hh" 455217Ssaidi@eecs.umich.edu#include "mem/packet_access.hh" 465217Ssaidi@eecs.umich.edu#include "params/EnergyCtrl.hh" 475217Ssaidi@eecs.umich.edu#include "sim/dvfs_handler.hh" 485217Ssaidi@eecs.umich.edu 495217Ssaidi@eecs.umich.eduEnergyCtrl::EnergyCtrl(const Params *p) 505217Ssaidi@eecs.umich.edu : BasicPioDevice(p, PIO_NUM_FIELDS * 4), // each field is 32 bit 515217Ssaidi@eecs.umich.edu dvfsHandler(p->dvfs_handler), 525217Ssaidi@eecs.umich.edu domainID(0), 535217Ssaidi@eecs.umich.edu domainIDIndexToRead(0), 545217Ssaidi@eecs.umich.edu perfLevelAck(0), 555217Ssaidi@eecs.umich.edu perfLevelToRead(0), 565217Ssaidi@eecs.umich.edu updateAckEvent(this) 575217Ssaidi@eecs.umich.edu{ 585217Ssaidi@eecs.umich.edu fatal_if(!p->dvfs_handler, "EnergyCtrl: Needs a DVFSHandler for a " 595217Ssaidi@eecs.umich.edu "functioning system.\n"); 605217Ssaidi@eecs.umich.edu} 615217Ssaidi@eecs.umich.edu 625217Ssaidi@eecs.umich.eduTick 635217Ssaidi@eecs.umich.eduEnergyCtrl::read(PacketPtr pkt) 645217Ssaidi@eecs.umich.edu{ 655217Ssaidi@eecs.umich.edu assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 665217Ssaidi@eecs.umich.edu assert(pkt->getSize() == 4); 675217Ssaidi@eecs.umich.edu 685217Ssaidi@eecs.umich.edu Addr daddr = pkt->getAddr() - pioAddr; 695217Ssaidi@eecs.umich.edu assert((daddr & 3) == 0); 705217Ssaidi@eecs.umich.edu Registers reg = Registers(daddr / 4); 715217Ssaidi@eecs.umich.edu 725217Ssaidi@eecs.umich.edu if (!dvfsHandler->isEnabled()) { 735217Ssaidi@eecs.umich.edu // NB: Zero is a good response if the handler is disabled 745217Ssaidi@eecs.umich.edu pkt->set<uint32_t>(0); 755217Ssaidi@eecs.umich.edu warn_once("EnergyCtrl: Disabled handler, ignoring read from reg %i\n", 765217Ssaidi@eecs.umich.edu reg); 775217Ssaidi@eecs.umich.edu DPRINTF(EnergyCtrl, "dvfs handler disabled, return 0 for read from "\ 785712Shsul@eecs.umich.edu "reg %i\n", reg); 795712Shsul@eecs.umich.edu pkt->makeAtomicResponse(); 805217Ssaidi@eecs.umich.edu return pioDelay; 815217Ssaidi@eecs.umich.edu } 825714Shsul@eecs.umich.edu 835714Shsul@eecs.umich.edu uint32_t result = 0; 845714Shsul@eecs.umich.edu Tick period; 855714Shsul@eecs.umich.edu double voltage; 865714Shsul@eecs.umich.edu 875714Shsul@eecs.umich.edu switch(reg) { 885714Shsul@eecs.umich.edu case DVFS_HANDLER_STATUS: 895217Ssaidi@eecs.umich.edu result = 1; 90 DPRINTF(EnergyCtrl, "dvfs handler enabled\n"); 91 break; 92 case DVFS_NUM_DOMAINS: 93 result = dvfsHandler->numDomains(); 94 DPRINTF(EnergyCtrl, "reading number of domains %d\n", result); 95 break; 96 case DVFS_DOMAINID_AT_INDEX: 97 result = dvfsHandler->domainID(domainIDIndexToRead); 98 DPRINTF(EnergyCtrl, "reading domain id at index %d as %d\n", 99 domainIDIndexToRead, result); 100 break; 101 case DVFS_HANDLER_TRANS_LATENCY: 102 // Return transition latency in nanoseconds 103 result = dvfsHandler->transLatency() / SimClock::Int::ns; 104 DPRINTF(EnergyCtrl, "reading dvfs handler trans latency %d ns\n", 105 result); 106 break; 107 case DOMAIN_ID: 108 result = domainID; 109 DPRINTF(EnergyCtrl, "reading domain id:%d\n", result); 110 break; 111 case PERF_LEVEL: 112 result = dvfsHandler->perfLevel(domainID); 113 DPRINTF(EnergyCtrl, "reading domain %d perf level: %d\n", 114 domainID, result); 115 break; 116 case PERF_LEVEL_ACK: 117 result = perfLevelAck; 118 DPRINTF(EnergyCtrl, "reading ack:%d\n", result); 119 // Signal is set for a single read only 120 if (result == 1) 121 perfLevelAck = 0; 122 break; 123 case NUM_OF_PERF_LEVELS: 124 result = dvfsHandler->numPerfLevels(domainID); 125 DPRINTF(EnergyCtrl, "reading num of perf level:%d\n", result); 126 break; 127 case FREQ_AT_PERF_LEVEL: 128 period = dvfsHandler->clkPeriodAtPerfLevel(domainID, perfLevelToRead); 129 result = ticksTokHz(period); 130 DPRINTF(EnergyCtrl, "reading freq %d KHz at perf level: %d\n", 131 result, perfLevelToRead); 132 break; 133 case VOLT_AT_PERF_LEVEL: 134 voltage = dvfsHandler->voltageAtPerfLevel(domainID, perfLevelToRead); 135 result = toMicroVolt(voltage); 136 DPRINTF(EnergyCtrl, "reading voltage %d u-volt at perf level: %d\n", 137 result, perfLevelToRead); 138 break; 139 default: 140 panic("Tried to read EnergyCtrl at offset %#x / reg %i\n", daddr, 141 reg); 142 } 143 pkt->set<uint32_t>(result); 144 pkt->makeAtomicResponse(); 145 return pioDelay; 146} 147 148Tick 149EnergyCtrl::write(PacketPtr pkt) 150{ 151 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 152 assert(pkt->getSize() == 4); 153 154 uint32_t data; 155 data = pkt->get<uint32_t>(); 156 157 Addr daddr = pkt->getAddr() - pioAddr; 158 assert((daddr & 3) == 0); 159 Registers reg = Registers(daddr / 4); 160 161 if (!dvfsHandler->isEnabled()) { 162 // Ignore writes to a disabled controller 163 warn_once("EnergyCtrl: Disabled handler, ignoring write %u to "\ 164 "reg %i\n", data, reg); 165 DPRINTF(EnergyCtrl, "dvfs handler disabled, ignoring write %u to "\ 166 "reg %i\n", data, reg); 167 pkt->makeAtomicResponse(); 168 return pioDelay; 169 } 170 171 switch(reg) { 172 case DVFS_DOMAINID_AT_INDEX: 173 domainIDIndexToRead = data; 174 DPRINTF(EnergyCtrl, "writing domain id index:%d\n", 175 domainIDIndexToRead); 176 break; 177 case DOMAIN_ID: 178 // Extra check to ensure that a valid domain ID is being queried 179 if (dvfsHandler->validDomainID(data)) { 180 domainID = data; 181 DPRINTF(EnergyCtrl, "writing domain id:%d\n", domainID); 182 } else { 183 DPRINTF(EnergyCtrl, "invalid domain id:%d\n", domainID); 184 } 185 break; 186 case PERF_LEVEL: 187 if (dvfsHandler->perfLevel(domainID, data)) { 188 if (updateAckEvent.scheduled()) { 189 // The OS driver is trying to change the perf level while 190 // another change is in flight. This is fine, but only a 191 // single acknowledgment will be sent. 192 DPRINTF(EnergyCtrl, "descheduling previous pending ack "\ 193 "event\n"); 194 deschedule(updateAckEvent); 195 } 196 schedule(updateAckEvent, curTick() + dvfsHandler->transLatency()); 197 DPRINTF(EnergyCtrl, "writing domain %d perf level: %d\n", 198 domainID, data); 199 } else { 200 DPRINTF(EnergyCtrl, "invalid / ineffective perf level:%d for "\ 201 "domain:%d\n", data, domainID); 202 } 203 break; 204 case PERF_LEVEL_TO_READ: 205 perfLevelToRead = data; 206 DPRINTF(EnergyCtrl, "writing perf level to read opp at: %d\n", 207 data); 208 break; 209 default: 210 panic("Tried to write EnergyCtrl at offset %#x\n", daddr); 211 break; 212 } 213 214 pkt->makeAtomicResponse(); 215 return pioDelay; 216} 217 218void 219EnergyCtrl::serialize(CheckpointOut &cp) const 220{ 221 SERIALIZE_SCALAR(domainID); 222 SERIALIZE_SCALAR(domainIDIndexToRead); 223 SERIALIZE_SCALAR(perfLevelToRead); 224 SERIALIZE_SCALAR(perfLevelAck); 225 226 Tick next_event = updateAckEvent.scheduled() ? updateAckEvent.when() : 0; 227 SERIALIZE_SCALAR(next_event); 228} 229 230void 231EnergyCtrl::unserialize(CheckpointIn &cp) 232{ 233 UNSERIALIZE_SCALAR(domainID); 234 UNSERIALIZE_SCALAR(domainIDIndexToRead); 235 UNSERIALIZE_SCALAR(perfLevelToRead); 236 UNSERIALIZE_SCALAR(perfLevelAck); 237 Tick next_event = 0; 238 UNSERIALIZE_SCALAR(next_event); 239 240 // restore scheduled events 241 if (next_event != 0) { 242 schedule(updateAckEvent, next_event); 243 } 244} 245 246EnergyCtrl * EnergyCtrlParams::create() 247{ 248 return new EnergyCtrl(this); 249} 250 251void 252EnergyCtrl::startup() 253{ 254 if (!dvfsHandler->isEnabled()) { 255 warn("Existing EnergyCtrl, but no enabled DVFSHandler found.\n"); 256 } 257} 258 259void 260EnergyCtrl::init() 261{ 262 BasicPioDevice::init(); 263} 264