Deleted Added
sdiff udiff text old ( 13231:c6c133f9e007 ) new ( 13912:53531772924f )
full compact
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 * Authors: Ali Saidi
29 */
30
31/** @file
32 * This device implemetns the niagara I/O bridge chip. It manages incomming
33 * interrupts and posts them to the CPU when needed. It holds mask registers and
34 * various status registers for CPUs to check what interrupts are pending as
35 * well as facilities to send IPIs to other cpus.
36 */
37
38#include "dev/sparc/iob.hh"
39
40#include <cstring>
41
42#include "arch/sparc/faults.hh"
43#include "arch/sparc/interrupts.hh"
44#include "arch/sparc/isa_traits.hh"
45#include "base/bitfield.hh"
46#include "base/trace.hh"
47#include "cpu/intr_control.hh"
48#include "cpu/thread_context.hh"
49#include "debug/Iob.hh"
50#include "dev/platform.hh"
51#include "mem/packet_access.hh"
52#include "mem/port.hh"
53#include "sim/faults.hh"
54#include "sim/system.hh"
55
56Iob::Iob(const Params *p)
57 : PioDevice(p), ic(p->platform->intrctrl)
58{
59 iobManAddr = ULL(0x9800000000);
60 iobManSize = ULL(0x0100000000);
61 iobJBusAddr = ULL(0x9F00000000);
62 iobJBusSize = ULL(0x0100000000);
63 assert (params()->system->threadContexts.size() <= MaxNiagaraProcs);
64
65 pioDelay = p->pio_latency;
66
67 for (int x = 0; x < NumDeviceIds; ++x) {
68 intMan[x].cpu = 0;
69 intMan[x].vector = 0;
70 intCtl[x].mask = true;
71 intCtl[x].pend = false;
72 }
73
74}
75
76Tick
77Iob::read(PacketPtr pkt)
78{
79
80 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
81 readIob(pkt);
82 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
83 readJBus(pkt);
84 else
85 panic("Invalid address reached Iob\n");
86
87 pkt->makeAtomicResponse();
88 return pioDelay;
89}
90
91void
92Iob::readIob(PacketPtr pkt)
93{
94 Addr accessAddr = pkt->getAddr() - iobManAddr;
95
96 assert(IntManAddr == 0);
97 if (accessAddr < IntManAddr + IntManSize) {
98 int index = (accessAddr - IntManAddr) >> 3;
99 uint64_t data = intMan[index].cpu << 8 | intMan[index].vector << 0;
100 pkt->setBE(data);
101 return;
102 }
103
104 if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
105 int index = (accessAddr - IntCtlAddr) >> 3;
106 uint64_t data = intCtl[index].mask ? 1 << 2 : 0 |
107 intCtl[index].pend ? 1 << 0 : 0;
108 pkt->setBE(data);
109 return;
110 }
111
112 if (accessAddr == JIntVecAddr) {
113 pkt->setBE(jIntVec);
114 return;
115 }
116
117 panic("Read to unknown IOB offset 0x%x\n", accessAddr);
118}
119
120void
121Iob::readJBus(PacketPtr pkt)
122{
123 Addr accessAddr = pkt->getAddr() - iobJBusAddr;
124 ContextID cpuid = pkt->req->contextId();
125 int index;
126 uint64_t data;
127
128
129
130
131 if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) {
132 index = (accessAddr - JIntData0Addr) >> 3;
133 pkt->setBE(jBusData0[index]);
134 return;
135 }
136
137 if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) {
138 index = (accessAddr - JIntData1Addr) >> 3;
139 pkt->setBE(jBusData1[index]);
140 return;
141 }
142
143 if (accessAddr == JIntDataA0Addr) {
144 pkt->setBE(jBusData0[cpuid]);
145 return;
146 }
147
148 if (accessAddr == JIntDataA1Addr) {
149 pkt->setBE(jBusData1[cpuid]);
150 return;
151 }
152
153 if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
154 index = (accessAddr - JIntBusyAddr) >> 3;
155 data = jIntBusy[index].busy ? 1 << 5 : 0 |
156 jIntBusy[index].source;
157 pkt->setBE(data);
158 return;
159 }
160 if (accessAddr == JIntABusyAddr) {
161 data = jIntBusy[cpuid].busy ? 1 << 5 : 0 |
162 jIntBusy[cpuid].source;
163 pkt->setBE(data);
164 return;
165 };
166
167 panic("Read to unknown JBus offset 0x%x\n", accessAddr);
168}
169
170Tick
171Iob::write(PacketPtr pkt)
172{
173 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
174 writeIob(pkt);
175 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
176 writeJBus(pkt);
177 else
178 panic("Invalid address reached Iob\n");
179
180
181 pkt->makeAtomicResponse();
182 return pioDelay;
183}
184
185void
186Iob::writeIob(PacketPtr pkt)
187{
188 Addr accessAddr = pkt->getAddr() - iobManAddr;
189 int index;
190 uint64_t data;
191
192 assert(IntManAddr == 0);
193 if (accessAddr < IntManAddr + IntManSize) {
194 index = (accessAddr - IntManAddr) >> 3;
195 data = pkt->getBE<uint64_t>();
196 intMan[index].cpu = bits(data,12,8);
197 intMan[index].vector = bits(data,5,0);
198 DPRINTF(Iob, "Wrote IntMan %d cpu %d, vec %d\n", index,
199 intMan[index].cpu, intMan[index].vector);
200 return;
201 }
202
203 if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
204 index = (accessAddr - IntCtlAddr) >> 3;
205 data = pkt->getBE<uint64_t>();
206 intCtl[index].mask = bits(data,2,2);
207 if (bits(data,1,1))
208 intCtl[index].pend = false;
209 DPRINTF(Iob, "Wrote IntCtl %d pend %d cleared %d\n", index,
210 intCtl[index].pend, bits(data,2,2));
211 return;
212 }
213
214 if (accessAddr == JIntVecAddr) {
215 jIntVec = bits(pkt->getBE<uint64_t>(), 5,0);
216 DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec);
217 return;
218 }
219
220 if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) {
221 Type type;
222 int cpu_id;
223 int vector;
224 index = (accessAddr - IntManAddr) >> 3;
225 data = pkt->getBE<uint64_t>();
226 type = (Type)bits(data,17,16);
227 cpu_id = bits(data, 12,8);
228 vector = bits(data,5,0);
229 generateIpi(type,cpu_id, vector);
230 return;
231 }
232
233 panic("Write to unknown IOB offset 0x%x\n", accessAddr);
234}
235
236void
237Iob::writeJBus(PacketPtr pkt)
238{
239 Addr accessAddr = pkt->getAddr() - iobJBusAddr;
240 ContextID cpuid = pkt->req->contextId();
241 int index;
242 uint64_t data;
243
244 if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
245 index = (accessAddr - JIntBusyAddr) >> 3;
246 data = pkt->getBE<uint64_t>();
247 jIntBusy[index].busy = bits(data,5,5);
248 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", index,
249 jIntBusy[index].busy);
250 return;
251 }
252 if (accessAddr == JIntABusyAddr) {
253 data = pkt->getBE<uint64_t>();
254 jIntBusy[cpuid].busy = bits(data,5,5);
255 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", cpuid,
256 jIntBusy[cpuid].busy);
257 return;
258 };
259
260 panic("Write to unknown JBus offset 0x%x\n", accessAddr);
261}
262
263void
264Iob::receiveDeviceInterrupt(DeviceId devid)
265{
266 assert(devid < NumDeviceIds);
267 if (intCtl[devid].mask)
268 return;
269 intCtl[devid].mask = true;
270 intCtl[devid].pend = true;
271 DPRINTF(Iob, "Receiving Device interrupt: %d for cpu %d vec %d\n",
272 devid, intMan[devid].cpu, intMan[devid].vector);
273 ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector);
274}
275
276
277void
278Iob::generateIpi(Type type, int cpu_id, int vector)
279{
280 SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
281 if (cpu_id >= sys->numContexts())
282 return;
283
284 switch (type) {
285 case 0: // interrupt
286 DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n",
287 cpu_id, vector);
288 ic->post(cpu_id, SparcISA::IT_INT_VEC, vector);
289 break;
290 case 1: // reset
291 warn("Sending reset to CPU: %d\n", cpu_id);
292 if (vector != por->trapType())
293 panic("Don't know how to set non-POR reset to cpu\n");
294 por->invoke(sys->threadContexts[cpu_id]);
295 sys->threadContexts[cpu_id]->activate();
296 break;
297 case 2: // idle -- this means stop executing and don't wake on interrupts
298 DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id);
299 sys->threadContexts[cpu_id]->halt();
300 break;
301 case 3: // resume
302 DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id);
303 sys->threadContexts[cpu_id]->activate();
304 break;
305 default:
306 panic("Invalid type to generate ipi\n");
307 }
308}
309
310bool
311Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1)
312{
313 // If we are already dealing with an interrupt for that cpu we can't deal
314 // with another one right now... come back later
315 if (jIntBusy[cpu_id].busy)
316 return false;
317
318 DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n",
319 source, cpu_id, jIntVec);
320
321 jIntBusy[cpu_id].busy = true;
322 jIntBusy[cpu_id].source = source;
323 jBusData0[cpu_id] = d0;
324 jBusData1[cpu_id] = d1;
325
326 ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec);
327 return true;
328}
329
330AddrRangeList
331Iob::getAddrRanges() const
332{
333 AddrRangeList ranges;
334 ranges.push_back(RangeSize(iobManAddr, iobManSize));
335 ranges.push_back(RangeSize(iobJBusAddr, iobJBusSize));
336 return ranges;
337}
338
339
340void
341Iob::serialize(CheckpointOut &cp) const
342{
343
344 SERIALIZE_SCALAR(jIntVec);
345 SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
346 SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
347 for (int x = 0; x < NumDeviceIds; x++) {
348 ScopedCheckpointSection sec(cp, csprintf("Int%d", x));
349 paramOut(cp, "cpu", intMan[x].cpu);
350 paramOut(cp, "vector", intMan[x].vector);
351 paramOut(cp, "mask", intCtl[x].mask);
352 paramOut(cp, "pend", intCtl[x].pend);
353 };
354 for (int x = 0; x < MaxNiagaraProcs; x++) {
355 ScopedCheckpointSection sec(cp, csprintf("jIntBusy%d", x));
356 paramOut(cp, "busy", jIntBusy[x].busy);
357 paramOut(cp, "source", jIntBusy[x].source);
358 };
359}
360
361void
362Iob::unserialize(CheckpointIn &cp)
363{
364 UNSERIALIZE_SCALAR(jIntVec);
365 UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
366 UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
367 for (int x = 0; x < NumDeviceIds; x++) {
368 ScopedCheckpointSection sec(cp, csprintf("Int%d", x));
369 paramIn(cp, "cpu", intMan[x].cpu);
370 paramIn(cp, "vector", intMan[x].vector);
371 paramIn(cp, "mask", intCtl[x].mask);
372 paramIn(cp, "pend", intCtl[x].pend);
373 };
374 for (int x = 0; x < MaxNiagaraProcs; x++) {
375 ScopedCheckpointSection sec(cp, csprintf("jIntBusy%d", x));
376 paramIn(cp, "busy", jIntBusy[x].busy);
377 paramIn(cp, "source", jIntBusy[x].source);
378 };
379}
380
381Iob *
382IobParams::create()
383{
384 return new Iob(this);
385}