The Pedigree Project 0.1
modules/drivers/x86/ib700_wdt/main.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/machine/Device.h"
22#include "pedigree/kernel/machine/Machine.h"
23#include "pedigree/kernel/machine/Timer.h"
24#include "pedigree/kernel/machine/TimerHandler.h"
25#include "pedigree/kernel/processor/IoBase.h"
26#include "pedigree/kernel/processor/state_forward.h"
27#include "pedigree/kernel/processor/types.h"
28#include "pedigree/kernel/time/Time.h"
29#include "pedigree/kernel/utilities/String.h"
30#include "pedigree/kernel/utilities/Vector.h"
31#include "pedigree/kernel/utilities/utility.h"
32
33#include "modules/Module.h"
34
35enum Ib700TimeEntries {
36 Seconds30 = 0,
37 Seconds28 = 1,
38 Seconds26 = 2,
39 Seconds24 = 3,
40 Seconds22 = 4,
41 Seconds20 = 5,
42 Seconds18 = 6,
43 Seconds16 = 7,
44 Seconds14 = 8,
45 Seconds12 = 9,
46 Seconds10 = 10,
47 Seconds8 = 11,
48 Seconds6 = 12,
49 Seconds4 = 13,
50 Seconds2 = 14,
51 Seconds0 = 15,
52};
53
54class Ib700Watchdog : public Device, public TimerHandler {
55 public:
56 Ib700Watchdog(Device* pDev);
57
58 virtual ~Ib700Watchdog();
59
60 virtual bool initialise();
61
62 void shutdown();
63
64 virtual void getName(String& str);
65
66 virtual void timer(uint64_t delta);
67
68 private:
69 IoBase* m_pBase;
70 Timer* m_pTimer;
71 uint64_t m_RefreshRemaining;
72};
73
74static Vector<Ib700Watchdog*> g_Watchdogs;
75
76static bool entry() {
77 auto f = [](Device* p) {
78 if (p->addresses().count() > 0) {
79 if (p->addresses()[0]->m_Name.compare("ib700-base")) {
80 Ib700Watchdog* pNewChild = new Ib700Watchdog(p);
81 if (pNewChild->initialise()) {
82 g_Watchdogs.pushBack(pNewChild);
83 return static_cast<Device*>(pNewChild);
84 } else {
85 ERROR("IB700 initialisation failed!");
86 delete pNewChild;
87 }
88 }
89 }
90
91 return p;
92 };
93
94 auto c = pedigree_std::make_callable(f);
95 Device::foreach (c, 0);
96
97 return true;
98}
99
100static void exit() {
101 auto f = [](Device* device) {
102 for (auto watchdog : g_Watchdogs) {
103 if (device == watchdog) {
104 // Restore a generic device node so a later reload can bind it again.
105 // Drain the timer callback before Device's transfer constructor takes
106 // away the watchdog's I/O mapping.
107 watchdog->shutdown();
108 return new Device(device);
109 }
110 }
111 return device;
112 };
113
114 auto c = pedigree_std::make_callable(f);
115 Device::foreach (c, 0);
116 g_Watchdogs.clear();
117}
118
119MODULE_INFO("ib700_wdt", &entry, &exit);
120
121Ib700Watchdog::Ib700Watchdog(Device* pDev)
122 : Device(pDev),
123 m_pBase(nullptr),
124 m_pTimer(nullptr),
125 m_RefreshRemaining(Time::Multiplier::Second) {
126 setSpecificType(String("watchdog-timer"));
127}
128
129Ib700Watchdog::~Ib700Watchdog() {
130 shutdown();
131}
132
133void Ib700Watchdog::shutdown() {
134 if (m_pTimer) {
135 if (!m_pTimer->unregisterHandler(this)) {
136 FATAL("IB700 watchdog could not drain its timer callback");
137 }
138 m_pTimer = nullptr;
139 }
140
141 if (m_pBase) {
142 // Offset 2 arms the watchdog; only offset 0 disables it.
143 m_pBase->write8(0, 0);
144 m_pBase = nullptr;
145 }
146}
147
148bool Ib700Watchdog::initialise() {
149 m_pBase = addresses()[0]->m_Io;
150 if (!m_pBase)
151 return false;
152
153 // Disable any existing timer.
154 m_pBase->write8(0, 0);
155
156 // Register ourselves with the core timer so we can continually
157 // reset the watchdog timer as needed.
158 Timer* t = Machine::instance().getTimer();
159 if (t && t->registerHandler(this)) {
160 m_pTimer = t;
161
162 // A word write also touches the next byte port and rearms QEMU's IB700
163 // with the high byte, replacing the intended 10-second timeout.
164 m_pBase->write8(Seconds10, 2);
165 if (t->supportsDeadlines() &&
166 !t->armHandler(this, Time::getTicks() + Time::Multiplier::Second)) {
167 shutdown();
168 return false;
169 }
170
171 return true;
172 }
173
174 return false;
175}
176
178 str.assign("ib700_wdt", 10);
179}
180
181void Ib700Watchdog::timer(uint64_t delta) {
182 if (delta < m_RefreshRemaining) {
183 m_RefreshRemaining -= delta;
184 if (m_pTimer && m_pTimer->supportsDeadlines() &&
185 !m_pTimer->armHandler(this, Time::getTicks() + m_RefreshRemaining)) {
186 FATAL("IB700 watchdog could not rearm its timer callback");
187 }
188 return;
189 }
190 // RTC callbacks are serialized by their IRQ worker. A delayed callback
191 // needs one refresh now, followed by a full interval until the next write.
192 m_RefreshRemaining = Time::Multiplier::Second;
193 m_pBase->write8(Seconds10, 2);
194 if (m_pTimer && m_pTimer->supportsDeadlines() &&
195 !m_pTimer->armHandler(this, Time::getTicks() + m_RefreshRemaining)) {
196 FATAL("IB700 watchdog could not rearm its timer callback");
197 }
198}
static void foreach(Callback callback, Device *root=0)
Definition Device.cc:107
virtual Vector< Address * > & addresses()
Definition Device.h:266
virtual void setSpecificType(String str)
Definition Device.h:187
virtual void timer(uint64_t delta)
virtual void getName(String &str)
Abstrace base class for hardware I/O capabilities.
Definition IoBase.h:32
virtual void write8(uint8_t value, size_t offset=0)=0
virtual Timer * getTimer()=0
virtual bool supportsDeadlines() const
virtual bool armHandler(TimerHandler *, uint64_t)
A vector / dynamic array.
Definition Vector.h:33