iob.cc revision 8739
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 <cstring>
39
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 "cpu/thread_context.hh"
46#include "debug/Iob.hh"
47#include "dev/sparc/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
54Iob::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->threadContexts.size() <= MaxNiagaraProcs);
62
63    pioDelay = p->pio_latency;
64
65    // Get the interrupt controller from the platform
66    ic = platform->intrctrl;
67
68    for (int x = 0; x < NumDeviceIds; ++x) {
69        intMan[x].cpu = 0;
70        intMan[x].vector = 0;
71        intCtl[x].mask = true;
72        intCtl[x].pend = false;
73    }
74
75}
76
77Tick
78Iob::read(PacketPtr pkt)
79{
80
81    if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
82        readIob(pkt);
83    else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
84        readJBus(pkt);
85    else
86        panic("Invalid address reached Iob\n");
87
88    pkt->makeAtomicResponse();
89    return pioDelay;
90}
91
92void
93Iob::readIob(PacketPtr pkt)
94{
95        Addr accessAddr = pkt->getAddr() - iobManAddr;
96
97        if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
98            int index = (accessAddr - IntManAddr) >> 3;
99            uint64_t data = intMan[index].cpu << 8 | intMan[index].vector << 0;
100            pkt->set(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->set(data);
109            return;
110        }
111
112        if (accessAddr == JIntVecAddr) {
113            pkt->set(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        int 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->set(jBusData0[index]);
134            return;
135        }
136
137        if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) {
138            index = (accessAddr - JIntData1Addr) >> 3;
139            pkt->set(jBusData1[index]);
140            return;
141        }
142
143        if (accessAddr == JIntDataA0Addr) {
144            pkt->set(jBusData0[cpuid]);
145            return;
146        }
147
148        if (accessAddr == JIntDataA1Addr) {
149            pkt->set(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->set(data);
158            return;
159        }
160        if (accessAddr == JIntABusyAddr) {
161            data = jIntBusy[cpuid].busy ? 1 << 5 : 0 |
162                   jIntBusy[cpuid].source;
163            pkt->set(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        if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
193            index = (accessAddr - IntManAddr) >> 3;
194            data = pkt->get<uint64_t>();
195            intMan[index].cpu = bits(data,12,8);
196            intMan[index].vector = bits(data,5,0);
197            DPRINTF(Iob, "Wrote IntMan %d cpu %d, vec %d\n", index,
198                    intMan[index].cpu, intMan[index].vector);
199            return;
200        }
201
202        if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
203            index = (accessAddr - IntCtlAddr) >> 3;
204            data = pkt->get<uint64_t>();
205            intCtl[index].mask = bits(data,2,2);
206            if (bits(data,1,1))
207                intCtl[index].pend = false;
208            DPRINTF(Iob, "Wrote IntCtl %d pend %d cleared %d\n", index,
209                    intCtl[index].pend, bits(data,2,2));
210            return;
211        }
212
213        if (accessAddr == JIntVecAddr) {
214            jIntVec = bits(pkt->get<uint64_t>(), 5,0);
215            DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec);
216            return;
217        }
218
219        if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) {
220            Type type;
221            int cpu_id;
222            int vector;
223            index = (accessAddr - IntManAddr) >> 3;
224            data = pkt->get<uint64_t>();
225            type = (Type)bits(data,17,16);
226            cpu_id = bits(data, 12,8);
227            vector = bits(data,5,0);
228            generateIpi(type,cpu_id, vector);
229            return;
230        }
231
232        panic("Write to unknown IOB offset 0x%x\n", accessAddr);
233}
234
235void
236Iob::writeJBus(PacketPtr pkt)
237{
238        Addr accessAddr = pkt->getAddr() - iobJBusAddr;
239        int cpuid = pkt->req->contextId();
240        int index;
241        uint64_t data;
242
243        if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
244            index = (accessAddr - JIntBusyAddr) >> 3;
245            data = pkt->get<uint64_t>();
246            jIntBusy[index].busy = bits(data,5,5);
247            DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", index,
248                    jIntBusy[index].busy);
249            return;
250        }
251        if (accessAddr == JIntABusyAddr) {
252            data = pkt->get<uint64_t>();
253            jIntBusy[cpuid].busy = bits(data,5,5);
254            DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", cpuid,
255                    jIntBusy[cpuid].busy);
256            return;
257        };
258
259        panic("Write to unknown JBus offset 0x%x\n", accessAddr);
260}
261
262void
263Iob::receiveDeviceInterrupt(DeviceId devid)
264{
265    assert(devid < NumDeviceIds);
266    if (intCtl[devid].mask)
267        return;
268    intCtl[devid].mask = true;
269    intCtl[devid].pend = true;
270    DPRINTF(Iob, "Receiving Device interrupt: %d for cpu %d vec %d\n",
271            devid, intMan[devid].cpu, intMan[devid].vector);
272    ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector);
273}
274
275
276void
277Iob::generateIpi(Type type, int cpu_id, int vector)
278{
279    SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
280    if (cpu_id >= sys->numContexts())
281        return;
282
283    switch (type) {
284      case 0: // interrupt
285        DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n",
286                cpu_id, vector);
287        ic->post(cpu_id, SparcISA::IT_INT_VEC, vector);
288        break;
289      case 1: // reset
290        warn("Sending reset to CPU: %d\n", cpu_id);
291        if (vector != por->trapType())
292            panic("Don't know how to set non-POR reset to cpu\n");
293        por->invoke(sys->threadContexts[cpu_id]);
294        sys->threadContexts[cpu_id]->activate();
295        break;
296      case 2: // idle -- this means stop executing and don't wake on interrupts
297        DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id);
298        sys->threadContexts[cpu_id]->halt();
299        break;
300      case 3: // resume
301        DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id);
302        sys->threadContexts[cpu_id]->activate();
303        break;
304      default:
305        panic("Invalid type to generate ipi\n");
306    }
307}
308
309bool
310Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1)
311{
312    // If we are already dealing with an interrupt for that cpu we can't deal
313    // with another one right now... come back later
314    if (jIntBusy[cpu_id].busy)
315        return false;
316
317    DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n",
318            source, cpu_id, jIntVec);
319
320    jIntBusy[cpu_id].busy = true;
321    jIntBusy[cpu_id].source = source;
322    jBusData0[cpu_id] = d0;
323    jBusData1[cpu_id] = d1;
324
325    ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec);
326    return true;
327}
328
329void
330Iob::addressRanges(AddrRangeList &range_list)
331{
332    range_list.clear();
333    range_list.push_back(RangeSize(iobManAddr, iobManSize));
334    range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize));
335}
336
337
338void
339Iob::serialize(std::ostream &os)
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        nameOut(os, csprintf("%s.Int%d", name(), x));
347        paramOut(os, "cpu", intMan[x].cpu);
348        paramOut(os, "vector", intMan[x].vector);
349        paramOut(os, "mask", intCtl[x].mask);
350        paramOut(os, "pend", intCtl[x].pend);
351    };
352    for (int x = 0; x < MaxNiagaraProcs; x++) {
353        nameOut(os, csprintf("%s.jIntBusy%d", name(), x));
354        paramOut(os, "busy", jIntBusy[x].busy);
355        paramOut(os, "source", jIntBusy[x].source);
356    };
357}
358
359void
360Iob::unserialize(Checkpoint *cp, const std::string &section)
361{
362    UNSERIALIZE_SCALAR(jIntVec);
363    UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
364    UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
365    for (int x = 0; x < NumDeviceIds; x++) {
366        paramIn(cp, csprintf("%s.Int%d", name(), x), "cpu", intMan[x].cpu);
367        paramIn(cp, csprintf("%s.Int%d", name(), x), "vector", intMan[x].vector);
368        paramIn(cp, csprintf("%s.Int%d", name(), x), "mask", intCtl[x].mask);
369        paramIn(cp, csprintf("%s.Int%d", name(), x), "pend", intCtl[x].pend);
370    };
371    for (int x = 0; x < MaxNiagaraProcs; x++) {
372        paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "busy", jIntBusy[x].busy);
373        paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "source", jIntBusy[x].source);
374    };
375}
376
377Iob *
378IobParams::create()
379{
380    return new Iob(this);
381}
382