energy_ctrl.cc revision 10905:a6ca6831e775
1/* 2 * Copyright (c) 2012-2014 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Vasileios Spiliopoulos 38 * Akash Bagdia 39 * Stephan Diestelhorst 40 */ 41 42#include "debug/EnergyCtrl.hh" 43#include "dev/arm/energy_ctrl.hh" 44#include "mem/packet.hh" 45#include "mem/packet_access.hh" 46#include "params/EnergyCtrl.hh" 47#include "sim/dvfs_handler.hh" 48 49EnergyCtrl::EnergyCtrl(const Params *p) 50 : BasicPioDevice(p, PIO_NUM_FIELDS * 4), // each field is 32 bit 51 dvfsHandler(p->dvfs_handler), 52 domainID(0), 53 domainIDIndexToRead(0), 54 perfLevelAck(0), 55 perfLevelToRead(0), 56 updateAckEvent(this) 57{ 58 fatal_if(!p->dvfs_handler, "EnergyCtrl: Needs a DVFSHandler for a " 59 "functioning system.\n"); 60} 61 62Tick 63EnergyCtrl::read(PacketPtr pkt) 64{ 65 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 66 assert(pkt->getSize() == 4); 67 68 Addr daddr = pkt->getAddr() - pioAddr; 69 assert((daddr & 3) == 0); 70 Registers reg = Registers(daddr / 4); 71 72 if (!dvfsHandler->isEnabled()) { 73 // NB: Zero is a good response if the handler is disabled 74 pkt->set<uint32_t>(0); 75 warn_once("EnergyCtrl: Disabled handler, ignoring read from reg %i\n", 76 reg); 77 DPRINTF(EnergyCtrl, "dvfs handler disabled, return 0 for read from "\ 78 "reg %i\n", reg); 79 pkt->makeAtomicResponse(); 80 return pioDelay; 81 } 82 83 uint32_t result = 0; 84 Tick period; 85 double voltage; 86 87 switch(reg) { 88 case DVFS_HANDLER_STATUS: 89 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