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