dev-arm: Implement Generic Watchdog
authorGiacomo Travaglini <giacomo.travaglini@arm.com>
Mon, 13 Jul 2020 20:31:50 +0000 (21:31 +0100)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Tue, 26 Jan 2021 15:14:18 +0000 (15:14 +0000)
Change-Id: I53bcb6ae77c0bcc080f4be0bd2339d4d1f6a4b28
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/39699
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/dev/arm/RealView.py
src/dev/arm/SConscript
src/dev/arm/watchdog_generic.cc [new file with mode: 0644]
src/dev/arm/watchdog_generic.hh [new file with mode: 0644]

index 7d90111fdff4f25c06d1aa67f03df65a06207ce2..588e4a901cf30d8924e6d68e38882423f58c4201 100644 (file)
@@ -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"
index cc3efcf641689f3849ac9bea2ca7df35af018eed..c78483f2c6f53ff4ca52777425a00031d970aafe 100644 (file)
@@ -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 (file)
index 0000000..3361665
--- /dev/null
@@ -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<RefreshOffset>(
+        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<ControlOffset>(
+        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<RefreshOffset>(
+        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<ControlOffset>(
+        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 (file)
index 0000000..24d3999
--- /dev/null
@@ -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 &params);
+
+    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__