timer_cpulocal.cc revision 8993
1/* 2 * Copyright (c) 2010-2011 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: Ali Saidi 38 * Geoffrey Blake 39 */ 40 41#include "base/intmath.hh" 42#include "base/trace.hh" 43#include "debug/Checkpoint.hh" 44#include "debug/Timer.hh" 45#include "dev/arm/gic.hh" 46#include "dev/arm/timer_cpulocal.hh" 47#include "mem/packet.hh" 48#include "mem/packet_access.hh" 49 50CpuLocalTimer::CpuLocalTimer(Params *p) 51 : BasicPioDevice(p), gic(p->gic) 52{ 53 // Initialize the timer registers for each per cpu timer 54 for (int i = 0; i < CPU_MAX; i++) { 55 std::stringstream oss; 56 oss << name() << ".timer" << i; 57 localTimer[i]._name = oss.str(); 58 localTimer[i].parent = this; 59 localTimer[i].intNumTimer = p->int_num_timer; 60 localTimer[i].intNumWatchdog = p->int_num_watchdog; 61 localTimer[i].clock = p->clock; 62 localTimer[i].cpuNum = i; 63 } 64 pioSize = 0x38; 65} 66 67CpuLocalTimer::Timer::Timer() 68 : timerControl(0x0), watchdogControl(0x0), rawIntTimer(false), rawIntWatchdog(false), 69 rawResetWatchdog(false), watchdogDisableReg(0x0), pendingIntTimer(false), pendingIntWatchdog(false), 70 timerLoadValue(0x0), watchdogLoadValue(0x0), timerZeroEvent(this), watchdogZeroEvent(this) 71{ 72} 73 74Tick 75CpuLocalTimer::read(PacketPtr pkt) 76{ 77 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 78 assert(pkt->getSize() == 4); 79 Addr daddr = pkt->getAddr() - pioAddr; 80 pkt->allocate(); 81 int cpu_id = pkt->req->contextId(); 82 DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr); 83 assert(cpu_id >= 0); 84 assert(cpu_id < CPU_MAX); 85 86 if (daddr < Timer::Size) 87 localTimer[cpu_id].read(pkt, daddr); 88 else 89 panic("Tried to read CpuLocalTimer at offset %#x that doesn't exist\n", daddr); 90 pkt->makeAtomicResponse(); 91 return pioDelay; 92} 93 94 95void 96CpuLocalTimer::Timer::read(PacketPtr pkt, Addr daddr) 97{ 98 DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr); 99 Tick time; 100 101 switch(daddr) { 102 case TimerLoadReg: 103 pkt->set<uint32_t>(timerLoadValue); 104 break; 105 case TimerCounterReg: 106 DPRINTF(Timer, "Event schedule for timer %d, clock=%d, prescale=%d\n", 107 timerZeroEvent.when(), clock, timerControl.prescalar); 108 time = timerZeroEvent.when() - curTick(); 109 time = time / clock / power(16, timerControl.prescalar); 110 DPRINTF(Timer, "-- returning counter at %d\n", time); 111 pkt->set<uint32_t>(time); 112 break; 113 case TimerControlReg: 114 pkt->set<uint32_t>(timerControl); 115 break; 116 case TimerIntStatusReg: 117 pkt->set<uint32_t>(rawIntTimer); 118 break; 119 case WatchdogLoadReg: 120 pkt->set<uint32_t>(watchdogLoadValue); 121 break; 122 case WatchdogCounterReg: 123 DPRINTF(Timer, "Event schedule for watchdog %d, clock=%d, prescale=%d\n", 124 watchdogZeroEvent.when(), clock, watchdogControl.prescalar); 125 time = watchdogZeroEvent.when() - curTick(); 126 time = time / clock / power(16, watchdogControl.prescalar); 127 DPRINTF(Timer, "-- returning counter at %d\n", time); 128 pkt->set<uint32_t>(time); 129 break; 130 case WatchdogControlReg: 131 pkt->set<uint32_t>(watchdogControl); 132 break; 133 case WatchdogIntStatusReg: 134 pkt->set<uint32_t>(rawIntWatchdog); 135 break; 136 case WatchdogResetStatusReg: 137 pkt->set<uint32_t>(rawResetWatchdog); 138 break; 139 case WatchdogDisableReg: 140 panic("Tried to read from WatchdogDisableRegister\n"); 141 break; 142 default: 143 panic("Tried to read CpuLocalTimer at offset %#x\n", daddr); 144 break; 145 } 146} 147 148Tick 149CpuLocalTimer::write(PacketPtr pkt) 150{ 151 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 152 assert(pkt->getSize() == 4); 153 Addr daddr = pkt->getAddr() - pioAddr; 154 pkt->allocate(); 155 int cpu_id = pkt->req->contextId(); 156 DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr); 157 assert(cpu_id >= 0); 158 assert(cpu_id < CPU_MAX); 159 160 if (daddr < Timer::Size) 161 localTimer[cpu_id].write(pkt, daddr); 162 else 163 panic("Tried to write CpuLocalTimer at offset %#x that doesn't exist\n", daddr); 164 pkt->makeAtomicResponse(); 165 return pioDelay; 166} 167 168void 169CpuLocalTimer::Timer::write(PacketPtr pkt, Addr daddr) 170{ 171 DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr); 172 bool old_enable; 173 bool old_wd_mode; 174 uint32_t old_val; 175 176 switch (daddr) { 177 case TimerLoadReg: 178 // Writing to this register also resets the counter register and 179 // starts decrementing if the counter is enabled. 180 timerLoadValue = pkt->get<uint32_t>(); 181 restartTimerCounter(timerLoadValue); 182 break; 183 case TimerCounterReg: 184 // Can be written, doesn't start counting unless the timer is enabled 185 restartTimerCounter(pkt->get<uint32_t>()); 186 break; 187 case TimerControlReg: 188 old_enable = timerControl.enable; 189 timerControl = pkt->get<uint32_t>(); 190 if ((old_enable == 0) && timerControl.enable) 191 restartTimerCounter(timerLoadValue); 192 break; 193 case TimerIntStatusReg: 194 rawIntTimer = false; 195 if (pendingIntTimer) { 196 pendingIntTimer = false; 197 DPRINTF(Timer, "Clearing interrupt\n"); 198 } 199 break; 200 case WatchdogLoadReg: 201 watchdogLoadValue = pkt->get<uint32_t>(); 202 restartWatchdogCounter(watchdogLoadValue); 203 break; 204 case WatchdogCounterReg: 205 // Can't be written when in watchdog mode, but can in timer mode 206 if (!watchdogControl.watchdogMode) { 207 restartWatchdogCounter(pkt->get<uint32_t>()); 208 } 209 break; 210 case WatchdogControlReg: 211 old_enable = watchdogControl.enable; 212 old_wd_mode = watchdogControl.watchdogMode; 213 watchdogControl = pkt->get<uint32_t>(); 214 if ((old_enable == 0) && watchdogControl.enable) 215 restartWatchdogCounter(watchdogLoadValue); 216 // cannot disable watchdog using control register 217 if ((old_wd_mode == 1) && watchdogControl.watchdogMode == 0) 218 watchdogControl.watchdogMode = 1; 219 break; 220 case WatchdogIntStatusReg: 221 rawIntWatchdog = false; 222 if (pendingIntWatchdog) { 223 pendingIntWatchdog = false; 224 DPRINTF(Timer, "Clearing watchdog interrupt\n"); 225 } 226 break; 227 case WatchdogResetStatusReg: 228 rawResetWatchdog = false; 229 DPRINTF(Timer, "Clearing watchdog reset flag\n"); 230 break; 231 case WatchdogDisableReg: 232 old_val = watchdogDisableReg; 233 watchdogDisableReg = pkt->get<uint32_t>(); 234 // if this sequence is observed, turn off watchdog mode 235 if (old_val == 0x12345678 && watchdogDisableReg == 0x87654321) 236 watchdogControl.watchdogMode = 0; 237 break; 238 default: 239 panic("Tried to write CpuLocalTimer timer at offset %#x\n", daddr); 240 break; 241 } 242} 243 244//XXX: Two functions are needed because the control registers are different types 245void 246CpuLocalTimer::Timer::restartTimerCounter(uint32_t val) 247{ 248 DPRINTF(Timer, "Resetting timer counter with value %#x\n", val); 249 if (!timerControl.enable) 250 return; 251 252 Tick time = clock * power(16, timerControl.prescalar); 253 time *= val; 254 255 if (timerZeroEvent.scheduled()) { 256 DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); 257 parent->deschedule(timerZeroEvent); 258 } 259 parent->schedule(timerZeroEvent, curTick() + time); 260 DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time); 261} 262 263void 264CpuLocalTimer::Timer::restartWatchdogCounter(uint32_t val) 265{ 266 DPRINTF(Timer, "Resetting watchdog counter with value %#x\n", val); 267 if (!watchdogControl.enable) 268 return; 269 270 Tick time = clock * power(16, watchdogControl.prescalar); 271 time *= val; 272 273 if (watchdogZeroEvent.scheduled()) { 274 DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); 275 parent->deschedule(watchdogZeroEvent); 276 } 277 parent->schedule(watchdogZeroEvent, curTick() + time); 278 DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time); 279} 280////// 281 282void 283CpuLocalTimer::Timer::timerAtZero() 284{ 285 if (!timerControl.enable) 286 return; 287 288 DPRINTF(Timer, "Timer Counter reached zero\n"); 289 290 rawIntTimer = true; 291 bool old_pending = pendingIntTimer; 292 if (timerControl.intEnable) 293 pendingIntTimer = true; 294 if (pendingIntTimer && !old_pending) { 295 DPRINTF(Timer, "-- Causing interrupt\n"); 296 parent->gic->sendPPInt(intNumTimer, cpuNum); 297 } 298 299 if (!timerControl.autoReload) 300 return; 301 else 302 restartTimerCounter(timerLoadValue); 303} 304 305void 306CpuLocalTimer::Timer::watchdogAtZero() 307{ 308 if (!watchdogControl.enable) 309 return; 310 311 DPRINTF(Timer, "Watchdog Counter reached zero\n"); 312 313 rawIntWatchdog = true; 314 bool old_pending = pendingIntWatchdog; 315 // generates an interrupt only if the watchdog is in timer 316 // mode. 317 if (watchdogControl.intEnable && !watchdogControl.watchdogMode) 318 pendingIntWatchdog = true; 319 else if (watchdogControl.watchdogMode) { 320 rawResetWatchdog = true; 321 fatal("gem5 ARM Model does not support true watchdog operation!\n"); 322 //XXX: Should we ever support a true watchdog reset? 323 } 324 325 if (pendingIntWatchdog && !old_pending) { 326 DPRINTF(Timer, "-- Causing interrupt\n"); 327 parent->gic->sendPPInt(intNumWatchdog, cpuNum); 328 } 329 330 if (watchdogControl.watchdogMode) 331 return; 332 else if (watchdogControl.autoReload) 333 restartWatchdogCounter(watchdogLoadValue); 334} 335 336void 337CpuLocalTimer::Timer::serialize(std::ostream &os) 338{ 339 DPRINTF(Checkpoint, "Serializing Arm CpuLocalTimer\n"); 340 SERIALIZE_SCALAR(intNumTimer); 341 SERIALIZE_SCALAR(intNumWatchdog); 342 SERIALIZE_SCALAR(clock); 343 344 uint32_t timer_control_serial = timerControl; 345 uint32_t watchdog_control_serial = watchdogControl; 346 SERIALIZE_SCALAR(timer_control_serial); 347 SERIALIZE_SCALAR(watchdog_control_serial); 348 349 SERIALIZE_SCALAR(rawIntTimer); 350 SERIALIZE_SCALAR(rawIntWatchdog); 351 SERIALIZE_SCALAR(rawResetWatchdog); 352 SERIALIZE_SCALAR(watchdogDisableReg); 353 SERIALIZE_SCALAR(pendingIntTimer); 354 SERIALIZE_SCALAR(pendingIntWatchdog); 355 SERIALIZE_SCALAR(timerLoadValue); 356 SERIALIZE_SCALAR(watchdogLoadValue); 357 358 bool timer_is_in_event = timerZeroEvent.scheduled(); 359 SERIALIZE_SCALAR(timer_is_in_event); 360 bool watchdog_is_in_event = watchdogZeroEvent.scheduled(); 361 SERIALIZE_SCALAR(watchdog_is_in_event); 362 363 Tick timer_event_time; 364 if (timer_is_in_event){ 365 timer_event_time = timerZeroEvent.when(); 366 SERIALIZE_SCALAR(timer_event_time); 367 } 368 Tick watchdog_event_time; 369 if (watchdog_is_in_event){ 370 watchdog_event_time = watchdogZeroEvent.when(); 371 SERIALIZE_SCALAR(watchdog_event_time); 372 } 373} 374 375void 376CpuLocalTimer::Timer::unserialize(Checkpoint *cp, const std::string §ion) 377{ 378 DPRINTF(Checkpoint, "Unserializing Arm CpuLocalTimer\n"); 379 380 UNSERIALIZE_SCALAR(intNumTimer); 381 UNSERIALIZE_SCALAR(intNumWatchdog); 382 UNSERIALIZE_SCALAR(clock); 383 384 uint32_t timer_control_serial; 385 UNSERIALIZE_SCALAR(timer_control_serial); 386 timerControl = timer_control_serial; 387 uint32_t watchdog_control_serial; 388 UNSERIALIZE_SCALAR(watchdog_control_serial); 389 watchdogControl = watchdog_control_serial; 390 391 UNSERIALIZE_SCALAR(rawIntTimer); 392 UNSERIALIZE_SCALAR(rawIntWatchdog); 393 UNSERIALIZE_SCALAR(rawResetWatchdog); 394 UNSERIALIZE_SCALAR(watchdogDisableReg); 395 UNSERIALIZE_SCALAR(pendingIntTimer); 396 UNSERIALIZE_SCALAR(pendingIntWatchdog); 397 UNSERIALIZE_SCALAR(timerLoadValue); 398 UNSERIALIZE_SCALAR(watchdogLoadValue); 399 400 bool timer_is_in_event; 401 UNSERIALIZE_SCALAR(timer_is_in_event); 402 bool watchdog_is_in_event; 403 UNSERIALIZE_SCALAR(watchdog_is_in_event); 404 405 Tick timer_event_time; 406 if (timer_is_in_event){ 407 UNSERIALIZE_SCALAR(timer_event_time); 408 parent->schedule(timerZeroEvent, timer_event_time); 409 } 410 Tick watchdog_event_time; 411 if (watchdog_is_in_event) { 412 UNSERIALIZE_SCALAR(watchdog_event_time); 413 parent->schedule(watchdogZeroEvent, watchdog_event_time); 414 } 415} 416 417 418 419void 420CpuLocalTimer::serialize(std::ostream &os) 421{ 422 for (int i = 0; i < CPU_MAX; i++) { 423 nameOut(os, csprintf("%s.timer%d", name(), i)); 424 localTimer[i].serialize(os); 425 } 426} 427 428void 429CpuLocalTimer::unserialize(Checkpoint *cp, const std::string §ion) 430{ 431 for (int i = 0; i < CPU_MAX; i++) { 432 localTimer[i].unserialize(cp, csprintf("%s.timer%d", section, i)); 433 } 434} 435 436CpuLocalTimer * 437CpuLocalTimerParams::create() 438{ 439 return new CpuLocalTimer(this); 440} 441