2 * Copyright (c) 2006 The Regents of The University of Michigan
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.
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.
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.
36 #include "dev/sparc/iob.hh"
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"
54 Iob::Iob(const Params
&p
)
55 : PioDevice(p
), ic(p
.platform
->intrctrl
)
57 iobManAddr
= ULL(0x9800000000);
58 iobManSize
= ULL(0x0100000000);
59 iobJBusAddr
= ULL(0x9F00000000);
60 iobJBusSize
= ULL(0x0100000000);
61 assert(params().system
->threads
.size() <= MaxNiagaraProcs
);
63 pioDelay
= p
.pio_latency
;
65 for (int x
= 0; x
< NumDeviceIds
; ++x
) {
68 intCtl
[x
].mask
= true;
69 intCtl
[x
].pend
= false;
75 Iob::read(PacketPtr pkt
)
78 if (pkt
->getAddr() >= iobManAddr
&& pkt
->getAddr() < iobManAddr
+ iobManSize
)
80 else if (pkt
->getAddr() >= iobJBusAddr
&& pkt
->getAddr() < iobJBusAddr
+iobJBusSize
)
83 panic("Invalid address reached Iob\n");
85 pkt
->makeAtomicResponse();
90 Iob::readIob(PacketPtr pkt
)
92 Addr accessAddr
= pkt
->getAddr() - iobManAddr
;
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;
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;
110 if (accessAddr
== JIntVecAddr
) {
115 panic("Read to unknown IOB offset 0x%x\n", accessAddr
);
119 Iob::readJBus(PacketPtr pkt
)
121 Addr accessAddr
= pkt
->getAddr() - iobJBusAddr
;
122 ContextID cpuid
= pkt
->req
->contextId();
129 if (accessAddr
>= JIntData0Addr
&& accessAddr
< JIntData1Addr
) {
130 index
= (accessAddr
- JIntData0Addr
) >> 3;
131 pkt
->setBE(jBusData0
[index
]);
135 if (accessAddr
>= JIntData1Addr
&& accessAddr
< JIntDataA0Addr
) {
136 index
= (accessAddr
- JIntData1Addr
) >> 3;
137 pkt
->setBE(jBusData1
[index
]);
141 if (accessAddr
== JIntDataA0Addr
) {
142 pkt
->setBE(jBusData0
[cpuid
]);
146 if (accessAddr
== JIntDataA1Addr
) {
147 pkt
->setBE(jBusData1
[cpuid
]);
151 if (accessAddr
>= JIntBusyAddr
&& accessAddr
< JIntBusyAddr
+ JIntBusySize
) {
152 index
= (accessAddr
- JIntBusyAddr
) >> 3;
153 data
= jIntBusy
[index
].busy
? 1 << 5 : 0 |
154 jIntBusy
[index
].source
;
158 if (accessAddr
== JIntABusyAddr
) {
159 data
= jIntBusy
[cpuid
].busy
? 1 << 5 : 0 |
160 jIntBusy
[cpuid
].source
;
165 panic("Read to unknown JBus offset 0x%x\n", accessAddr
);
169 Iob::write(PacketPtr pkt
)
171 if (pkt
->getAddr() >= iobManAddr
&& pkt
->getAddr() < iobManAddr
+ iobManSize
)
173 else if (pkt
->getAddr() >= iobJBusAddr
&& pkt
->getAddr() < iobJBusAddr
+iobJBusSize
)
176 panic("Invalid address reached Iob\n");
179 pkt
->makeAtomicResponse();
184 Iob::writeIob(PacketPtr pkt
)
186 Addr accessAddr
= pkt
->getAddr() - iobManAddr
;
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
);
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);
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));
212 if (accessAddr
== JIntVecAddr
) {
213 jIntVec
= bits(pkt
->getBE
<uint64_t>(), 5,0);
214 DPRINTF(Iob
, "Wrote jIntVec %d\n", jIntVec
);
218 if (accessAddr
>= IntVecDisAddr
&& accessAddr
< IntVecDisAddr
+ IntVecDisSize
) {
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
);
231 panic("Write to unknown IOB offset 0x%x\n", accessAddr
);
235 Iob::writeJBus(PacketPtr pkt
)
237 Addr accessAddr
= pkt
->getAddr() - iobJBusAddr
;
238 ContextID cpuid
= pkt
->req
->contextId();
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
);
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
);
258 panic("Write to unknown JBus offset 0x%x\n", accessAddr
);
262 Iob::receiveDeviceInterrupt(DeviceId devid
)
264 assert(devid
< NumDeviceIds
);
265 if (intCtl
[devid
].mask
)
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
);
276 Iob::generateIpi(Type type
, int cpu_id
, int vector
)
278 SparcISA::SparcFault
<SparcISA::PowerOnReset
> *por
= new SparcISA::PowerOnReset();
279 if (cpu_id
>= sys
->threads
.size())
284 DPRINTF(Iob
, "Generating interrupt because of I/O write to cpu: %d vec %d\n",
286 ic
->post(cpu_id
, SparcISA::IT_INT_VEC
, vector
);
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();
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();
300 DPRINTF(Iob
, "Resuming CPU because of I/O write cpu: %d\n", cpu_id
);
301 sys
->threads
[cpu_id
]->activate();
304 panic("Invalid type to generate ipi\n");
309 Iob::receiveJBusInterrupt(int cpu_id
, int source
, uint64_t d0
, uint64_t d1
)
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
)
316 DPRINTF(Iob
, "Receiving jBus interrupt: %d for cpu %d vec %d\n",
317 source
, cpu_id
, jIntVec
);
319 jIntBusy
[cpu_id
].busy
= true;
320 jIntBusy
[cpu_id
].source
= source
;
321 jBusData0
[cpu_id
] = d0
;
322 jBusData1
[cpu_id
] = d1
;
324 ic
->post(cpu_id
, SparcISA::IT_INT_VEC
, jIntVec
);
329 Iob::getAddrRanges() const
331 AddrRangeList ranges
;
332 ranges
.push_back(RangeSize(iobManAddr
, iobManSize
));
333 ranges
.push_back(RangeSize(iobJBusAddr
, iobJBusSize
));
339 Iob::serialize(CheckpointOut
&cp
) const
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
);
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
);
360 Iob::unserialize(CheckpointIn
&cp
)
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
);
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
);