From 4a4f994ff1f2363ce29826d05a1bd70641b64c12 Mon Sep 17 00:00:00 2001 From: Giacomo Travaglini Date: Mon, 13 Jul 2020 21:31:50 +0100 Subject: [PATCH] dev-arm: Implement Generic Watchdog Change-Id: I53bcb6ae77c0bcc080f4be0bd2339d4d1f6a4b28 Signed-off-by: Giacomo Travaglini Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/39699 Reviewed-by: Andreas Sandberg Maintainer: Andreas Sandberg Tested-by: kokoro --- src/dev/arm/RealView.py | 15 ++ src/dev/arm/SConscript | 1 + src/dev/arm/watchdog_generic.cc | 263 ++++++++++++++++++++++++++++++++ src/dev/arm/watchdog_generic.hh | 156 +++++++++++++++++++ 4 files changed, 435 insertions(+) create mode 100644 src/dev/arm/watchdog_generic.cc create mode 100644 src/dev/arm/watchdog_generic.hh diff --git a/src/dev/arm/RealView.py b/src/dev/arm/RealView.py index 7d90111fd..588e4a901 100644 --- a/src/dev/arm/RealView.py +++ b/src/dev/arm/RealView.py @@ -441,6 +441,21 @@ Reference: yield node +class GenericWatchdog(PioDevice): + type = 'GenericWatchdog' + cxx_header = 'dev/arm/watchdog_generic.hh' + + refresh_start = Param.Addr("Start address for the refresh frame") + control_start = Param.Addr("Start address for the control frame") + pio_latency = Param.Latency('10ns', "Delay for PIO r/w") + + ws0 = Param.ArmInterruptPin("WS0 Signal") + ws1 = Param.ArmInterruptPin("WS1 Signal") + + system_counter = Param.SystemCounter(Parent.any, + "The Watchdog uses the Generic Timer system counter as the timebase " + "against which the decision to trigger an interrupt is made.") + class A9GlobalTimer(BasicPioDevice): type = 'A9GlobalTimer' cxx_header = "dev/arm/timer_a9global.hh" diff --git a/src/dev/arm/SConscript b/src/dev/arm/SConscript index cc3efcf64..c78483f2c 100644 --- a/src/dev/arm/SConscript +++ b/src/dev/arm/SConscript @@ -81,6 +81,7 @@ if env['TARGET_ISA'] == 'arm': Source('smmu_v3_deviceifc.cc'); Source('smmu_v3_transl.cc'); Source('timer_sp804.cc') + Source('watchdog_generic.cc') Source('watchdog_sp805.cc') Source('gpu_nomali.cc') Source('pci_host.cc') diff --git a/src/dev/arm/watchdog_generic.cc b/src/dev/arm/watchdog_generic.cc new file mode 100644 index 000000000..33616652a --- /dev/null +++ b/src/dev/arm/watchdog_generic.cc @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2020 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "dev/arm/watchdog_generic.hh" + +#include "dev/arm/base_gic.hh" +#include "params/GenericWatchdog.hh" + + +GenericWatchdog::GenericWatchdog(const GenericWatchdogParams &p) + : PioDevice(p), + timeoutEvent([this]{ timeout(); }, name()), + controlStatus(0), + offset(0), + compare(0), + iidr(0), + refreshFrame(p.refresh_start, p.refresh_start + 0x10000), + controlFrame(p.control_start, p.control_start + 0x10000), + pioLatency(p.pio_latency), + cnt(*p.system_counter), + cntListener(*this), + ws0(p.ws0->get()), + ws1(p.ws1->get()) +{ + cnt.registerListener(&cntListener); +} + +AddrRangeList +GenericWatchdog::getAddrRanges() const +{ + AddrRangeList ranges; + ranges.push_back(refreshFrame); + ranges.push_back(controlFrame); + return ranges; +} + +Tick +GenericWatchdog::read(PacketPtr pkt) +{ + const Addr addr = pkt->getAddr(); + const size_t size = pkt->getSize(); + panic_if(size != 4, "GenericWatchdog::read: Invalid size %i\n", size); + + uint32_t resp = 0; + + if (refreshFrame.contains(addr)) { + resp = readRefresh(addr); + } else if (controlFrame.contains(addr)) { + resp = readControl(addr); + } else { + panic("%s unknown address %#x\n", __func__, addr); + } + + pkt->setUintX(resp, ByteOrder::little); + pkt->makeResponse(); + return pioLatency; +} + +uint32_t +GenericWatchdog::readRefresh(Addr addr) +{ + const auto daddr = static_cast( + addr - refreshFrame.start()); + + switch (daddr) { + case RefreshOffset::WRR: + // A read of the refresh register has no effect and returns 0 + return 0; + case RefreshOffset::W_IIDR: + return iidr; + default: + panic("%s unknown address %#x\n", __func__, addr); + } +} + +uint32_t +GenericWatchdog::readControl(Addr addr) +{ + const auto daddr = static_cast( + addr - controlFrame.start()); + + switch (daddr) { + case ControlOffset::WCS: + return controlStatus; + case ControlOffset::WOR: + return offset; + case ControlOffset::WCV_LO: + return bits(compare, 31, 0); + case ControlOffset::WCV_HI: + return bits(compare, 63, 32); + case ControlOffset::W_IIDR: + return iidr; + default: + panic("%s unknown address %#x\n", __func__, addr); + } +} + +Tick +GenericWatchdog::write(PacketPtr pkt) +{ + const Addr addr = pkt->getAddr(); + const size_t size = pkt->getSize(); + panic_if(size != 4, "GenericWatchdog::write: Invalid size %i\n", size); + + uint32_t data = pkt->getUintX(ByteOrder::little); + + if (refreshFrame.contains(addr)) { + writeRefresh(addr, data); + } else if (controlFrame.contains(addr)) { + writeControl(addr, data); + } else { + panic("%s unknown address %#x\n", __func__, addr); + } + + pkt->makeResponse(); + return pioLatency; +} + +void +GenericWatchdog::writeRefresh(Addr addr, uint32_t data) +{ + const auto daddr = static_cast( + addr - refreshFrame.start()); + + switch (daddr) { + case RefreshOffset::WRR: + explicitRefresh(); + break; + default: + panic("%s unknown address %#x\n", __func__, addr); + } +} + +void +GenericWatchdog::writeControl(Addr addr, uint32_t data) +{ + const auto daddr = static_cast( + addr - controlFrame.start()); + + switch (daddr) { + case ControlOffset::WCS: + controlStatus = data & 0x1; + explicitRefresh(); + break; + case ControlOffset::WOR: + offset = data; + explicitRefresh(); + break; + case ControlOffset::WCV_LO: + compare = insertBits(compare, 31, 0, data); + break; + case ControlOffset::WCV_HI: + compare = insertBits(compare, 63, 32, data); + break; + default: + panic("%s unknown address %#x\n", __func__, addr); + } +} + +void +GenericWatchdog::explicitRefresh() +{ + // Watchdog signals are cleared in case of an explicit refresh + controlStatus.ws0 = 0; + controlStatus.ws1 = 0; + ws0->clear(); + ws1->clear(); + + refresh(); +} + +void +GenericWatchdog::refresh() +{ + // Update compare value + compare = cnt.value() + offset; + + // Ask the System Counter how long we have to wait until + // it reaches the new compare value + Tick timeout_time = cnt.whenValue(compare); + + reschedule(timeoutEvent, timeout_time, true); +} + +void +GenericWatchdog::timeout() +{ + if (!controlStatus.enabled) + return; + + if (!controlStatus.ws0) { + controlStatus.ws0 = 1; + ws0->raise(); + } else { + controlStatus.ws1 = 1; + ws1->raise(); + } + + refresh(); +} + +void +GenericWatchdog::serialize(CheckpointOut &cp) const +{ + SERIALIZE_SCALAR(controlStatus); + SERIALIZE_SCALAR(offset); + SERIALIZE_SCALAR(compare); + + bool ev_scheduled = timeoutEvent.scheduled(); + SERIALIZE_SCALAR(ev_scheduled); + if (ev_scheduled) + SERIALIZE_SCALAR(timeoutEvent.when()); +} + +void +GenericWatchdog::unserialize(CheckpointIn &cp) +{ + UNSERIALIZE_SCALAR(controlStatus); + UNSERIALIZE_SCALAR(offset); + UNSERIALIZE_SCALAR(compare); + + bool ev_scheduled; + UNSERIALIZE_SCALAR(ev_scheduled); + if (ev_scheduled) { + Tick when; + UNSERIALIZE_SCALAR(when); + reschedule(timeoutEvent, when, true); + } +} diff --git a/src/dev/arm/watchdog_generic.hh b/src/dev/arm/watchdog_generic.hh new file mode 100644 index 000000000..24d399928 --- /dev/null +++ b/src/dev/arm/watchdog_generic.hh @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2020 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DEV_ARM_WATCHDOG_GENERIC_HH__ +#define __DEV_ARM_WATCHDOG_GENERIC_HH__ + +#include "dev/arm/generic_timer.hh" +#include "dev/io_device.hh" + +class ArmInterruptPin; +class GenericWatchdogParams; + +/** + * @file + * Arm SBSA Generic Watchdog + * Reference: + * Arm Server Base System Architecture (SBSA) + * Doc. ID: ARM-DEN-0029A Version 3.1 + */ +class GenericWatchdog : public PioDevice +{ + public: + GenericWatchdog(const GenericWatchdogParams ¶ms); + + void serialize(CheckpointOut &cp) const override; + void unserialize(CheckpointIn &cp) override; + + bool enabled() const { return controlStatus.enabled; } + + protected: + AddrRangeList getAddrRanges() const override; + + Tick read(PacketPtr pkt) override; + Tick write(PacketPtr pkt) override; + + uint32_t readRefresh(Addr addr); + uint32_t readControl(Addr addr); + + void writeRefresh(Addr addr, uint32_t data); + void writeControl(Addr addr, uint32_t data); + + protected: + /** + * System Counter Listener: This object is being notified + * any time there is a change in the SystemCounter. + * (Like a change in the counter frequency) + * This is needed since the Generic Watchdog doesn't have + * a standalone counter and it is instead relying on the + * global System Counter. + */ + class Listener : public SystemCounterListener + { + public: + explicit Listener(GenericWatchdog& _parent) + : parent(_parent) + {} + + void notify(void) override + { + panic_if(parent.enabled(), + "The Generic Watchdog shall be disabled when " + "the System Counter is being updated, or " + "the results are unpredictable"); + } + + protected: + GenericWatchdog &parent; + }; + + void explicitRefresh(); + void refresh(); + void timeout(); + EventFunctionWrapper timeoutEvent; + + private: + enum class RefreshOffset : Addr + { + WRR = 0x000, // Watchdog Refresh Register + W_IIDR = 0xfcc, // Watchdog Interface Identification Register + }; + + enum class ControlOffset : Addr + { + WCS = 0x000, // Watchdog Control and Status Register + WOR = 0x008, // Watchdog Offset Register + WCV_LO = 0x010, // Watchdog Compare Register [31:0] + WCV_HI = 0x014, // Watchdog Compare Register [63:32] + W_IIDR = 0xfcc, // Watchdog Interface Identification Register + }; + + BitUnion32(WCTRLS) + Bitfield<2> ws1; // Watchdog Signal 1 Status + Bitfield<1> ws0; // Watchdog Signal 0 Status + Bitfield<0> enabled; // Watchdog Enable + EndBitUnion(WCTRLS) + + /** Control and Status Register */ + WCTRLS controlStatus; + + /** Offset Register */ + uint32_t offset; + + /** Compare Register */ + uint64_t compare; + + /** Interface Identification Register */ + const uint32_t iidr; + + const AddrRange refreshFrame; + const AddrRange controlFrame; + + const Tick pioLatency; + + SystemCounter &cnt; + Listener cntListener; + + /** Watchdog Signals (IRQs) */ + ArmInterruptPin * const ws0; + ArmInterruptPin * const ws1; +}; + +#endif // __DEV_ARM_WATCHDOG_GENERIC_HH__ -- 2.30.2