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/faults.hh"
41 #include "arch/sparc/isa_traits.hh"
42 #include "base/bitfield.hh"
43 #include "base/trace.hh"
44 #include "cpu/intr_control.hh"
45 #include "debug/Iob.hh"
46 #include "dev/sparc/iob.hh"
47 #include "dev/platform.hh"
48 #include "mem/packet_access.hh"
49 #include "mem/port.hh"
50 #include "sim/faults.hh"
51 #include "sim/system.hh"
53 Iob::Iob(const Params
*p
)
54 : PioDevice(p
), ic(p
->platform
->intrctrl
)
56 iobManAddr
= ULL(0x9800000000);
57 iobManSize
= ULL(0x0100000000);
58 iobJBusAddr
= ULL(0x9F00000000);
59 iobJBusSize
= ULL(0x0100000000);
60 assert (params()->system
->threadContexts
.size() <= MaxNiagaraProcs
);
62 pioDelay
= p
->pio_latency
;
64 // Get the interrupt controller from the platform
65 ic
= platform
->intrctrl
;
67 for (int x
= 0; x
< NumDeviceIds
; ++x
) {
70 intCtl
[x
].mask
= true;
71 intCtl
[x
].pend
= false;
77 Iob::read(PacketPtr pkt
)
80 if (pkt
->getAddr() >= iobManAddr
&& pkt
->getAddr() < iobManAddr
+ iobManSize
)
82 else if (pkt
->getAddr() >= iobJBusAddr
&& pkt
->getAddr() < iobJBusAddr
+iobJBusSize
)
85 panic("Invalid address reached Iob\n");
87 pkt
->makeAtomicResponse();
92 Iob::readIob(PacketPtr pkt
)
94 Addr accessAddr
= pkt
->getAddr() - iobManAddr
;
96 if (accessAddr
>= IntManAddr
&& accessAddr
< IntManAddr
+ IntManSize
) {
97 int index
= (accessAddr
- IntManAddr
) >> 3;
98 uint64_t data
= intMan
[index
].cpu
<< 8 | intMan
[index
].vector
<< 0;
103 if (accessAddr
>= IntCtlAddr
&& accessAddr
< IntCtlAddr
+ IntCtlSize
) {
104 int index
= (accessAddr
- IntCtlAddr
) >> 3;
105 uint64_t data
= intCtl
[index
].mask
? 1 << 2 : 0 |
106 intCtl
[index
].pend
? 1 << 0 : 0;
111 if (accessAddr
== JIntVecAddr
) {
116 panic("Read to unknown IOB offset 0x%x\n", accessAddr
);
120 Iob::readJBus(PacketPtr pkt
)
122 Addr accessAddr
= pkt
->getAddr() - iobJBusAddr
;
123 int cpuid
= pkt
->req
->contextId();
130 if (accessAddr
>= JIntData0Addr
&& accessAddr
< JIntData1Addr
) {
131 index
= (accessAddr
- JIntData0Addr
) >> 3;
132 pkt
->set(jBusData0
[index
]);
136 if (accessAddr
>= JIntData1Addr
&& accessAddr
< JIntDataA0Addr
) {
137 index
= (accessAddr
- JIntData1Addr
) >> 3;
138 pkt
->set(jBusData1
[index
]);
142 if (accessAddr
== JIntDataA0Addr
) {
143 pkt
->set(jBusData0
[cpuid
]);
147 if (accessAddr
== JIntDataA1Addr
) {
148 pkt
->set(jBusData1
[cpuid
]);
152 if (accessAddr
>= JIntBusyAddr
&& accessAddr
< JIntBusyAddr
+ JIntBusySize
) {
153 index
= (accessAddr
- JIntBusyAddr
) >> 3;
154 data
= jIntBusy
[index
].busy
? 1 << 5 : 0 |
155 jIntBusy
[index
].source
;
159 if (accessAddr
== JIntABusyAddr
) {
160 data
= jIntBusy
[cpuid
].busy
? 1 << 5 : 0 |
161 jIntBusy
[cpuid
].source
;
166 panic("Read to unknown JBus offset 0x%x\n", accessAddr
);
170 Iob::write(PacketPtr pkt
)
172 if (pkt
->getAddr() >= iobManAddr
&& pkt
->getAddr() < iobManAddr
+ iobManSize
)
174 else if (pkt
->getAddr() >= iobJBusAddr
&& pkt
->getAddr() < iobJBusAddr
+iobJBusSize
)
177 panic("Invalid address reached Iob\n");
180 pkt
->makeAtomicResponse();
185 Iob::writeIob(PacketPtr pkt
)
187 Addr accessAddr
= pkt
->getAddr() - iobManAddr
;
191 if (accessAddr
>= IntManAddr
&& accessAddr
< IntManAddr
+ IntManSize
) {
192 index
= (accessAddr
- IntManAddr
) >> 3;
193 data
= pkt
->get
<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
->get
<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
->get
<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
->get
<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 int cpuid
= pkt
->req
->contextId();
242 if (accessAddr
>= JIntBusyAddr
&& accessAddr
< JIntBusyAddr
+ JIntBusySize
) {
243 index
= (accessAddr
- JIntBusyAddr
) >> 3;
244 data
= pkt
->get
<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
->get
<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
->numContexts())
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
->threadContexts
[cpu_id
]);
293 sys
->threadContexts
[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
->threadContexts
[cpu_id
]->halt();
300 DPRINTF(Iob
, "Resuming CPU because of I/O write cpu: %d\n", cpu_id
);
301 sys
->threadContexts
[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::addressRanges(AddrRangeList
&range_list
)
332 range_list
.push_back(RangeSize(iobManAddr
, iobManSize
));
333 range_list
.push_back(RangeSize(iobJBusAddr
, iobJBusSize
));
338 Iob::serialize(std::ostream
&os
)
341 SERIALIZE_SCALAR(jIntVec
);
342 SERIALIZE_ARRAY(jBusData0
, MaxNiagaraProcs
);
343 SERIALIZE_ARRAY(jBusData1
, MaxNiagaraProcs
);
344 for (int x
= 0; x
< NumDeviceIds
; x
++) {
345 nameOut(os
, csprintf("%s.Int%d", name(), x
));
346 paramOut(os
, "cpu", intMan
[x
].cpu
);
347 paramOut(os
, "vector", intMan
[x
].vector
);
348 paramOut(os
, "mask", intCtl
[x
].mask
);
349 paramOut(os
, "pend", intCtl
[x
].pend
);
351 for (int x
= 0; x
< MaxNiagaraProcs
; x
++) {
352 nameOut(os
, csprintf("%s.jIntBusy%d", name(), x
));
353 paramOut(os
, "busy", jIntBusy
[x
].busy
);
354 paramOut(os
, "source", jIntBusy
[x
].source
);
359 Iob::unserialize(Checkpoint
*cp
, const std::string
§ion
)
361 UNSERIALIZE_SCALAR(jIntVec
);
362 UNSERIALIZE_ARRAY(jBusData0
, MaxNiagaraProcs
);
363 UNSERIALIZE_ARRAY(jBusData1
, MaxNiagaraProcs
);
364 for (int x
= 0; x
< NumDeviceIds
; x
++) {
365 paramIn(cp
, csprintf("%s.Int%d", name(), x
), "cpu", intMan
[x
].cpu
);
366 paramIn(cp
, csprintf("%s.Int%d", name(), x
), "vector", intMan
[x
].vector
);
367 paramIn(cp
, csprintf("%s.Int%d", name(), x
), "mask", intCtl
[x
].mask
);
368 paramIn(cp
, csprintf("%s.Int%d", name(), x
), "pend", intCtl
[x
].pend
);
370 for (int x
= 0; x
< MaxNiagaraProcs
; x
++) {
371 paramIn(cp
, csprintf("%s.jIntBusy%d", name(), x
), "busy", jIntBusy
[x
].busy
);
372 paramIn(cp
, csprintf("%s.jIntBusy%d", name(), x
), "source", jIntBusy
[x
].source
);
379 return new Iob(this);