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.
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.
40 #include "arch/sparc/isa_traits.hh"
41 #include "arch/sparc/faults.hh"
42 #include "base/trace.hh"
43 #include "cpu/intr_control.hh"
44 #include "dev/sparc/iob.hh"
45 #include "dev/platform.hh"
46 #include "mem/port.hh"
47 #include "mem/packet_access.hh"
48 #include "sim/faults.hh"
49 #include "sim/system.hh"
51 Iob::Iob(const Params
*p
)
52 : PioDevice(p
), ic(p
->platform
->intrctrl
)
54 iobManAddr
= ULL(0x9800000000);
55 iobManSize
= ULL(0x0100000000);
56 iobJBusAddr
= ULL(0x9F00000000);
57 iobJBusSize
= ULL(0x0100000000);
58 assert (params()->system
->threadContexts
.size() <= MaxNiagaraProcs
);
59 // Get the interrupt controller from the platform
60 ic
= platform
->intrctrl
;
62 for (int x
= 0; x
< NumDeviceIds
; ++x
) {
65 intCtl
[x
].mask
= true;
66 intCtl
[x
].pend
= false;
72 Iob::read(PacketPtr pkt
)
74 assert(pkt
->result
== Packet::Unknown
);
76 if (pkt
->getAddr() >= iobManAddr
&& pkt
->getAddr() < iobManAddr
+ iobManSize
)
78 else if (pkt
->getAddr() >= iobJBusAddr
&& pkt
->getAddr() < iobJBusAddr
+iobJBusSize
)
81 panic("Invalid address reached Iob\n");
83 pkt
->result
= Packet::Success
;
88 Iob::readIob(PacketPtr pkt
)
90 Addr accessAddr
= pkt
->getAddr() - iobManAddr
;
94 if (accessAddr
>= IntManAddr
&& accessAddr
< IntManAddr
+ IntManSize
) {
95 index
= (accessAddr
- IntManAddr
) >> 3;
96 data
= intMan
[index
].cpu
<< 8 | intMan
[index
].vector
<< 0;
101 if (accessAddr
>= IntCtlAddr
&& accessAddr
< IntCtlAddr
+ IntCtlSize
) {
102 index
= (accessAddr
- IntManAddr
) >> 3;
103 data
= intCtl
[index
].mask
? 1 << 2 : 0 |
104 intCtl
[index
].pend
? 1 << 0 : 0;
109 if (accessAddr
== JIntVecAddr
) {
114 panic("Read to unknown IOB offset 0x%x\n", accessAddr
);
118 Iob::readJBus(PacketPtr pkt
)
120 Addr accessAddr
= pkt
->getAddr() - iobJBusAddr
;
121 int cpuid
= pkt
->req
->getCpuNum();
128 if (accessAddr
>= JIntData0Addr
&& accessAddr
< JIntData1Addr
) {
129 index
= (accessAddr
- JIntData0Addr
) >> 3;
130 pkt
->set(jBusData0
[index
]);
134 if (accessAddr
>= JIntData1Addr
&& accessAddr
< JIntDataA0Addr
) {
135 index
= (accessAddr
- JIntData1Addr
) >> 3;
136 pkt
->set(jBusData1
[index
]);
140 if (accessAddr
== JIntDataA0Addr
) {
141 pkt
->set(jBusData0
[cpuid
]);
145 if (accessAddr
== JIntDataA1Addr
) {
146 pkt
->set(jBusData1
[cpuid
]);
150 if (accessAddr
>= JIntBusyAddr
&& accessAddr
< JIntBusyAddr
+ JIntBusySize
) {
151 index
= (accessAddr
- JIntBusyAddr
) >> 3;
152 data
= jIntBusy
[index
].busy
? 1 << 5 : 0 |
153 jIntBusy
[index
].source
;
157 if (accessAddr
== JIntABusyAddr
) {
158 data
= jIntBusy
[cpuid
].busy
? 1 << 5 : 0 |
159 jIntBusy
[cpuid
].source
;
164 panic("Read to unknown JBus offset 0x%x\n", accessAddr
);
168 Iob::write(PacketPtr pkt
)
170 if (pkt
->getAddr() >= iobManAddr
&& pkt
->getAddr() < iobManAddr
+ iobManSize
)
172 else if (pkt
->getAddr() >= iobJBusAddr
&& pkt
->getAddr() < iobJBusAddr
+iobJBusSize
)
175 panic("Invalid address reached Iob\n");
178 pkt
->result
= Packet::Success
;
183 Iob::writeIob(PacketPtr pkt
)
185 Addr accessAddr
= pkt
->getAddr() - iobManAddr
;
189 if (accessAddr
>= IntManAddr
&& accessAddr
< IntManAddr
+ IntManSize
) {
190 index
= (accessAddr
- IntManAddr
) >> 3;
191 data
= pkt
->get
<uint64_t>();
192 intMan
[index
].cpu
= bits(data
,12,8);
193 intMan
[index
].vector
= bits(data
,5,0);
194 DPRINTF(Iob
, "Wrote IntMan %d cpu %d, vec %d\n", index
,
195 intMan
[index
].cpu
, intMan
[index
].vector
);
199 if (accessAddr
>= IntCtlAddr
&& accessAddr
< IntCtlAddr
+ IntCtlSize
) {
200 index
= (accessAddr
- IntManAddr
) >> 3;
201 data
= pkt
->get
<uint64_t>();
202 intCtl
[index
].mask
= bits(data
,2,2);
204 intCtl
[index
].pend
= false;
205 DPRINTF(Iob
, "Wrote IntCtl %d pend %d cleared %d\n", index
,
206 intCtl
[index
].pend
, bits(data
,2,2));
210 if (accessAddr
== JIntVecAddr
) {
211 jIntVec
= bits(pkt
->get
<uint64_t>(), 5,0);
212 DPRINTF(Iob
, "Wrote jIntVec %d\n", jIntVec
);
216 if (accessAddr
>= IntVecDisAddr
&& accessAddr
< IntVecDisAddr
+ IntVecDisSize
) {
220 index
= (accessAddr
- IntManAddr
) >> 3;
221 data
= pkt
->get
<uint64_t>();
222 type
= (Type
)bits(data
,17,16);
223 cpu_id
= bits(data
, 12,8);
224 vector
= bits(data
,5,0);
225 generateIpi(type
,cpu_id
, vector
);
229 panic("Write to unknown IOB offset 0x%x\n", accessAddr
);
233 Iob::writeJBus(PacketPtr pkt
)
235 Addr accessAddr
= pkt
->getAddr() - iobJBusAddr
;
236 int cpuid
= pkt
->req
->getCpuNum();
240 if (accessAddr
>= JIntBusyAddr
&& accessAddr
< JIntBusyAddr
+ JIntBusySize
) {
241 index
= (accessAddr
- JIntBusyAddr
) >> 3;
242 data
= pkt
->get
<uint64_t>();
243 jIntBusy
[index
].busy
= bits(data
,5,5);
244 DPRINTF(Iob
, "Wrote jIntBusy index %d busy: %d\n", index
,
245 jIntBusy
[index
].busy
);
248 if (accessAddr
== JIntABusyAddr
) {
249 data
= pkt
->get
<uint64_t>();
250 jIntBusy
[cpuid
].busy
= bits(data
,5,5);
251 DPRINTF(Iob
, "Wrote jIntBusy index %d busy: %d\n", cpuid
,
252 jIntBusy
[cpuid
].busy
);
256 panic("Write to unknown JBus offset 0x%x\n", accessAddr
);
260 Iob::receiveDeviceInterrupt(DeviceId devid
)
262 assert(devid
< NumDeviceIds
);
263 if (intCtl
[devid
].mask
)
265 intCtl
[devid
].mask
= true;
266 intCtl
[devid
].pend
= true;
267 DPRINTF(Iob
, "Receiving Device interrupt: %d for cpu %d vec %d\n",
268 devid
, intMan
[devid
].cpu
, intMan
[devid
].vector
);
269 ic
->post(intMan
[devid
].cpu
, SparcISA::IT_INT_VEC
, intMan
[devid
].vector
);
274 Iob::generateIpi(Type type
, int cpu_id
, int vector
)
276 SparcISA::SparcFault
<SparcISA::PowerOnReset
> *por
= new SparcISA::PowerOnReset();
277 if (cpu_id
>= sys
->getNumCPUs())
282 DPRINTF(Iob
, "Generating interrupt because of I/O write to cpu: %d vec %d\n",
284 ic
->post(cpu_id
, SparcISA::IT_INT_VEC
, vector
);
287 warn("Sending reset to CPU: %d\n", cpu_id
);
288 if (vector
!= por
->trapType())
289 panic("Don't know how to set non-POR reset to cpu\n");
290 por
->invoke(sys
->threadContexts
[cpu_id
]);
291 sys
->threadContexts
[cpu_id
]->activate();
293 case 2: // idle -- this means stop executing and don't wake on interrupts
294 DPRINTF(Iob
, "Idling CPU because of I/O write cpu: %d\n", cpu_id
);
295 sys
->threadContexts
[cpu_id
]->halt();
298 DPRINTF(Iob
, "Resuming CPU because of I/O write cpu: %d\n", cpu_id
);
299 sys
->threadContexts
[cpu_id
]->activate();
302 panic("Invalid type to generate ipi\n");
307 Iob::receiveJBusInterrupt(int cpu_id
, int source
, uint64_t d0
, uint64_t d1
)
309 // If we are already dealing with an interrupt for that cpu we can't deal
310 // with another one right now... come back later
311 if (jIntBusy
[cpu_id
].busy
)
314 DPRINTF(Iob
, "Receiving jBus interrupt: %d for cpu %d vec %d\n",
315 source
, cpu_id
, jIntVec
);
317 jIntBusy
[cpu_id
].busy
= true;
318 jIntBusy
[cpu_id
].source
= source
;
319 jBusData0
[cpu_id
] = d0
;
320 jBusData1
[cpu_id
] = d1
;
322 ic
->post(cpu_id
, SparcISA::IT_INT_VEC
, jIntVec
);
327 Iob::addressRanges(AddrRangeList
&range_list
)
330 range_list
.push_back(RangeSize(iobManAddr
, iobManSize
));
331 range_list
.push_back(RangeSize(iobJBusAddr
, iobJBusSize
));
336 Iob::serialize(std::ostream
&os
)
339 SERIALIZE_SCALAR(jIntVec
);
340 SERIALIZE_ARRAY(jBusData0
, MaxNiagaraProcs
);
341 SERIALIZE_ARRAY(jBusData1
, MaxNiagaraProcs
);
342 for (int x
= 0; x
< NumDeviceIds
; x
++) {
343 nameOut(os
, csprintf("%s.Int%d", name(), x
));
344 paramOut(os
, "cpu", intMan
[x
].cpu
);
345 paramOut(os
, "vector", intMan
[x
].vector
);
346 paramOut(os
, "mask", intCtl
[x
].mask
);
347 paramOut(os
, "pend", intCtl
[x
].pend
);
349 for (int x
= 0; x
< MaxNiagaraProcs
; x
++) {
350 nameOut(os
, csprintf("%s.jIntBusy%d", name(), x
));
351 paramOut(os
, "busy", jIntBusy
[x
].busy
);
352 paramOut(os
, "source", jIntBusy
[x
].source
);
357 Iob::unserialize(Checkpoint
*cp
, const std::string
§ion
)
359 UNSERIALIZE_SCALAR(jIntVec
);
360 UNSERIALIZE_ARRAY(jBusData0
, MaxNiagaraProcs
);
361 UNSERIALIZE_ARRAY(jBusData1
, MaxNiagaraProcs
);
362 for (int x
= 0; x
< NumDeviceIds
; x
++) {
363 paramIn(cp
, csprintf("%s.Int%d", name(), x
), "cpu", intMan
[x
].cpu
);
364 paramIn(cp
, csprintf("%s.Int%d", name(), x
), "vector", intMan
[x
].vector
);
365 paramIn(cp
, csprintf("%s.Int%d", name(), x
), "mask", intCtl
[x
].mask
);
366 paramIn(cp
, csprintf("%s.Int%d", name(), x
), "pend", intCtl
[x
].pend
);
368 for (int x
= 0; x
< MaxNiagaraProcs
; x
++) {
369 paramIn(cp
, csprintf("%s.jIntBusy%d", name(), x
), "busy", jIntBusy
[x
].busy
);
370 paramIn(cp
, csprintf("%s.jIntBusy%d", name(), x
), "source", jIntBusy
[x
].source
);
377 return new Iob(this);