dev: Fixing EtherDevice stats initialization order
[gem5.git] / src / dev / sparc / iob.cc
1 /*
2 * Copyright (c) 2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /** @file
30 * This device implemetns the niagara I/O bridge chip. It manages incomming
31 * interrupts and posts them to the CPU when needed. It holds mask registers and
32 * various status registers for CPUs to check what interrupts are pending as
33 * well as facilities to send IPIs to other cpus.
34 */
35
36 #include "dev/sparc/iob.hh"
37
38 #include <cstring>
39
40 #include "arch/sparc/faults.hh"
41 #include "arch/sparc/interrupts.hh"
42 #include "arch/sparc/isa_traits.hh"
43 #include "base/bitfield.hh"
44 #include "base/trace.hh"
45 #include "cpu/intr_control.hh"
46 #include "cpu/thread_context.hh"
47 #include "debug/Iob.hh"
48 #include "dev/platform.hh"
49 #include "mem/packet_access.hh"
50 #include "mem/port.hh"
51 #include "sim/faults.hh"
52 #include "sim/system.hh"
53
54 Iob::Iob(const Params &p)
55 : PioDevice(p), ic(p.platform->intrctrl)
56 {
57 iobManAddr = ULL(0x9800000000);
58 iobManSize = ULL(0x0100000000);
59 iobJBusAddr = ULL(0x9F00000000);
60 iobJBusSize = ULL(0x0100000000);
61 assert(params().system->threads.size() <= MaxNiagaraProcs);
62
63 pioDelay = p.pio_latency;
64
65 for (int x = 0; x < NumDeviceIds; ++x) {
66 intMan[x].cpu = 0;
67 intMan[x].vector = 0;
68 intCtl[x].mask = true;
69 intCtl[x].pend = false;
70 }
71
72 }
73
74 Tick
75 Iob::read(PacketPtr pkt)
76 {
77
78 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
79 readIob(pkt);
80 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
81 readJBus(pkt);
82 else
83 panic("Invalid address reached Iob\n");
84
85 pkt->makeAtomicResponse();
86 return pioDelay;
87 }
88
89 void
90 Iob::readIob(PacketPtr pkt)
91 {
92 Addr accessAddr = pkt->getAddr() - iobManAddr;
93
94 assert(IntManAddr == 0);
95 if (accessAddr < IntManAddr + IntManSize) {
96 int index = (accessAddr - IntManAddr) >> 3;
97 uint64_t data = intMan[index].cpu << 8 | intMan[index].vector << 0;
98 pkt->setBE(data);
99 return;
100 }
101
102 if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
103 int index = (accessAddr - IntCtlAddr) >> 3;
104 uint64_t data = intCtl[index].mask ? 1 << 2 : 0 |
105 intCtl[index].pend ? 1 << 0 : 0;
106 pkt->setBE(data);
107 return;
108 }
109
110 if (accessAddr == JIntVecAddr) {
111 pkt->setBE(jIntVec);
112 return;
113 }
114
115 panic("Read to unknown IOB offset 0x%x\n", accessAddr);
116 }
117
118 void
119 Iob::readJBus(PacketPtr pkt)
120 {
121 Addr accessAddr = pkt->getAddr() - iobJBusAddr;
122 ContextID cpuid = pkt->req->contextId();
123 int index;
124 uint64_t data;
125
126
127
128
129 if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) {
130 index = (accessAddr - JIntData0Addr) >> 3;
131 pkt->setBE(jBusData0[index]);
132 return;
133 }
134
135 if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) {
136 index = (accessAddr - JIntData1Addr) >> 3;
137 pkt->setBE(jBusData1[index]);
138 return;
139 }
140
141 if (accessAddr == JIntDataA0Addr) {
142 pkt->setBE(jBusData0[cpuid]);
143 return;
144 }
145
146 if (accessAddr == JIntDataA1Addr) {
147 pkt->setBE(jBusData1[cpuid]);
148 return;
149 }
150
151 if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
152 index = (accessAddr - JIntBusyAddr) >> 3;
153 data = jIntBusy[index].busy ? 1 << 5 : 0 |
154 jIntBusy[index].source;
155 pkt->setBE(data);
156 return;
157 }
158 if (accessAddr == JIntABusyAddr) {
159 data = jIntBusy[cpuid].busy ? 1 << 5 : 0 |
160 jIntBusy[cpuid].source;
161 pkt->setBE(data);
162 return;
163 };
164
165 panic("Read to unknown JBus offset 0x%x\n", accessAddr);
166 }
167
168 Tick
169 Iob::write(PacketPtr pkt)
170 {
171 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
172 writeIob(pkt);
173 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
174 writeJBus(pkt);
175 else
176 panic("Invalid address reached Iob\n");
177
178
179 pkt->makeAtomicResponse();
180 return pioDelay;
181 }
182
183 void
184 Iob::writeIob(PacketPtr pkt)
185 {
186 Addr accessAddr = pkt->getAddr() - iobManAddr;
187 int index;
188 uint64_t data;
189
190 assert(IntManAddr == 0);
191 if (accessAddr < IntManAddr + IntManSize) {
192 index = (accessAddr - IntManAddr) >> 3;
193 data = pkt->getBE<uint64_t>();
194 intMan[index].cpu = bits(data,12,8);
195 intMan[index].vector = bits(data,5,0);
196 DPRINTF(Iob, "Wrote IntMan %d cpu %d, vec %d\n", index,
197 intMan[index].cpu, intMan[index].vector);
198 return;
199 }
200
201 if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
202 index = (accessAddr - IntCtlAddr) >> 3;
203 data = pkt->getBE<uint64_t>();
204 intCtl[index].mask = bits(data,2,2);
205 if (bits(data,1,1))
206 intCtl[index].pend = false;
207 DPRINTF(Iob, "Wrote IntCtl %d pend %d cleared %d\n", index,
208 intCtl[index].pend, bits(data,2,2));
209 return;
210 }
211
212 if (accessAddr == JIntVecAddr) {
213 jIntVec = bits(pkt->getBE<uint64_t>(), 5,0);
214 DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec);
215 return;
216 }
217
218 if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) {
219 Type type;
220 int cpu_id;
221 int vector;
222 index = (accessAddr - IntManAddr) >> 3;
223 data = pkt->getBE<uint64_t>();
224 type = (Type)bits(data,17,16);
225 cpu_id = bits(data, 12,8);
226 vector = bits(data,5,0);
227 generateIpi(type,cpu_id, vector);
228 return;
229 }
230
231 panic("Write to unknown IOB offset 0x%x\n", accessAddr);
232 }
233
234 void
235 Iob::writeJBus(PacketPtr pkt)
236 {
237 Addr accessAddr = pkt->getAddr() - iobJBusAddr;
238 ContextID cpuid = pkt->req->contextId();
239 int index;
240 uint64_t data;
241
242 if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
243 index = (accessAddr - JIntBusyAddr) >> 3;
244 data = pkt->getBE<uint64_t>();
245 jIntBusy[index].busy = bits(data,5,5);
246 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", index,
247 jIntBusy[index].busy);
248 return;
249 }
250 if (accessAddr == JIntABusyAddr) {
251 data = pkt->getBE<uint64_t>();
252 jIntBusy[cpuid].busy = bits(data,5,5);
253 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", cpuid,
254 jIntBusy[cpuid].busy);
255 return;
256 };
257
258 panic("Write to unknown JBus offset 0x%x\n", accessAddr);
259 }
260
261 void
262 Iob::receiveDeviceInterrupt(DeviceId devid)
263 {
264 assert(devid < NumDeviceIds);
265 if (intCtl[devid].mask)
266 return;
267 intCtl[devid].mask = true;
268 intCtl[devid].pend = true;
269 DPRINTF(Iob, "Receiving Device interrupt: %d for cpu %d vec %d\n",
270 devid, intMan[devid].cpu, intMan[devid].vector);
271 ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector);
272 }
273
274
275 void
276 Iob::generateIpi(Type type, int cpu_id, int vector)
277 {
278 SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
279 if (cpu_id >= sys->threads.size())
280 return;
281
282 switch (type) {
283 case 0: // interrupt
284 DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n",
285 cpu_id, vector);
286 ic->post(cpu_id, SparcISA::IT_INT_VEC, vector);
287 break;
288 case 1: // reset
289 warn("Sending reset to CPU: %d\n", cpu_id);
290 if (vector != por->trapType())
291 panic("Don't know how to set non-POR reset to cpu\n");
292 por->invoke(sys->threads[cpu_id]);
293 sys->threads[cpu_id]->activate();
294 break;
295 case 2: // idle -- this means stop executing and don't wake on interrupts
296 DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id);
297 sys->threads[cpu_id]->halt();
298 break;
299 case 3: // resume
300 DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id);
301 sys->threads[cpu_id]->activate();
302 break;
303 default:
304 panic("Invalid type to generate ipi\n");
305 }
306 }
307
308 bool
309 Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1)
310 {
311 // If we are already dealing with an interrupt for that cpu we can't deal
312 // with another one right now... come back later
313 if (jIntBusy[cpu_id].busy)
314 return false;
315
316 DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n",
317 source, cpu_id, jIntVec);
318
319 jIntBusy[cpu_id].busy = true;
320 jIntBusy[cpu_id].source = source;
321 jBusData0[cpu_id] = d0;
322 jBusData1[cpu_id] = d1;
323
324 ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec);
325 return true;
326 }
327
328 AddrRangeList
329 Iob::getAddrRanges() const
330 {
331 AddrRangeList ranges;
332 ranges.push_back(RangeSize(iobManAddr, iobManSize));
333 ranges.push_back(RangeSize(iobJBusAddr, iobJBusSize));
334 return ranges;
335 }
336
337
338 void
339 Iob::serialize(CheckpointOut &cp) const
340 {
341
342 SERIALIZE_SCALAR(jIntVec);
343 SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
344 SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
345 for (int x = 0; x < NumDeviceIds; x++) {
346 ScopedCheckpointSection sec(cp, csprintf("Int%d", x));
347 paramOut(cp, "cpu", intMan[x].cpu);
348 paramOut(cp, "vector", intMan[x].vector);
349 paramOut(cp, "mask", intCtl[x].mask);
350 paramOut(cp, "pend", intCtl[x].pend);
351 };
352 for (int x = 0; x < MaxNiagaraProcs; x++) {
353 ScopedCheckpointSection sec(cp, csprintf("jIntBusy%d", x));
354 paramOut(cp, "busy", jIntBusy[x].busy);
355 paramOut(cp, "source", jIntBusy[x].source);
356 };
357 }
358
359 void
360 Iob::unserialize(CheckpointIn &cp)
361 {
362 UNSERIALIZE_SCALAR(jIntVec);
363 UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
364 UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
365 for (int x = 0; x < NumDeviceIds; x++) {
366 ScopedCheckpointSection sec(cp, csprintf("Int%d", x));
367 paramIn(cp, "cpu", intMan[x].cpu);
368 paramIn(cp, "vector", intMan[x].vector);
369 paramIn(cp, "mask", intCtl[x].mask);
370 paramIn(cp, "pend", intCtl[x].pend);
371 };
372 for (int x = 0; x < MaxNiagaraProcs; x++) {
373 ScopedCheckpointSection sec(cp, csprintf("jIntBusy%d", x));
374 paramIn(cp, "busy", jIntBusy[x].busy);
375 paramIn(cp, "source", jIntBusy[x].source);
376 };
377 }