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