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