iob.cc revision 5714
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/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"
50
51Iob::Iob(const Params *p)
52    : PioDevice(p), ic(p->platform->intrctrl)
53{
54    iobManAddr = ULL(0x9800000000);
55    iobManSize = ULL(0x0100000000);
56    iobJBusAddr = ULL(0x9F00000000);
57    iobJBusSize = ULL(0x0100000000);
58    assert (params()->system->threadContexts.size() <= MaxNiagaraProcs);
59
60    pioDelay = p->pio_latency;
61
62    // Get the interrupt controller from the platform
63    ic = platform->intrctrl;
64
65    for (int x = 0; x < NumDeviceIds; ++x) {
66        intMan[x].cpu = 0;
67        intMan[x].vector = 0;
68        intCtl[x].mask = true;
69        intCtl[x].pend = false;
70    }
71
72}
73
74Tick
75Iob::read(PacketPtr pkt)
76{
77
78    if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
79        readIob(pkt);
80    else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
81        readJBus(pkt);
82    else
83        panic("Invalid address reached Iob\n");
84
85    pkt->makeAtomicResponse();
86    return pioDelay;
87}
88
89void
90Iob::readIob(PacketPtr pkt)
91{
92        Addr accessAddr = pkt->getAddr() - iobManAddr;
93        int index;
94        uint64_t data;
95
96        if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
97            index = (accessAddr - IntManAddr) >> 3;
98            data = intMan[index].cpu << 8 | intMan[index].vector << 0;
99            pkt->set(data);
100            return;
101        }
102
103        if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
104            index = (accessAddr - IntManAddr) >> 3;
105            data = intCtl[index].mask  ? 1 << 2 : 0 |
106                   intCtl[index].pend  ? 1 << 0 : 0;
107            pkt->set(data);
108            return;
109        }
110
111        if (accessAddr == JIntVecAddr) {
112            pkt->set(jIntVec);
113            return;
114        }
115
116        panic("Read to unknown IOB offset 0x%x\n", accessAddr);
117}
118
119void
120Iob::readJBus(PacketPtr pkt)
121{
122        Addr accessAddr = pkt->getAddr() - iobJBusAddr;
123        int cpuid = pkt->req->contextId();
124        int index;
125        uint64_t data;
126
127
128
129
130        if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) {
131            index = (accessAddr - JIntData0Addr) >> 3;
132            pkt->set(jBusData0[index]);
133            return;
134        }
135
136        if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) {
137            index = (accessAddr - JIntData1Addr) >> 3;
138            pkt->set(jBusData1[index]);
139            return;
140        }
141
142        if (accessAddr == JIntDataA0Addr) {
143            pkt->set(jBusData0[cpuid]);
144            return;
145        }
146
147        if (accessAddr == JIntDataA1Addr) {
148            pkt->set(jBusData1[cpuid]);
149            return;
150        }
151
152        if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
153            index = (accessAddr - JIntBusyAddr) >> 3;
154            data = jIntBusy[index].busy ? 1 << 5 : 0 |
155                   jIntBusy[index].source;
156            pkt->set(data);
157            return;
158        }
159        if (accessAddr == JIntABusyAddr) {
160            data = jIntBusy[cpuid].busy ? 1 << 5 : 0 |
161                   jIntBusy[cpuid].source;
162            pkt->set(data);
163            return;
164        };
165
166        panic("Read to unknown JBus offset 0x%x\n", accessAddr);
167}
168
169Tick
170Iob::write(PacketPtr pkt)
171{
172    if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
173        writeIob(pkt);
174    else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
175        writeJBus(pkt);
176    else
177        panic("Invalid address reached Iob\n");
178
179
180    pkt->makeAtomicResponse();
181    return pioDelay;
182}
183
184void
185Iob::writeIob(PacketPtr pkt)
186{
187        Addr accessAddr = pkt->getAddr() - iobManAddr;
188        int index;
189        uint64_t data;
190
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);
198            return;
199        }
200
201        if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
202            index = (accessAddr - IntManAddr) >> 3;
203            data = pkt->get<uint64_t>();
204            intCtl[index].mask = bits(data,2,2);
205            if (bits(data,1,1))
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));
209            return;
210        }
211
212        if (accessAddr == JIntVecAddr) {
213            jIntVec = bits(pkt->get<uint64_t>(), 5,0);
214            DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec);
215            return;
216        }
217
218        if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) {
219            Type type;
220            int cpu_id;
221            int vector;
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);
228            return;
229        }
230
231        panic("Write to unknown IOB offset 0x%x\n", accessAddr);
232}
233
234void
235Iob::writeJBus(PacketPtr pkt)
236{
237        Addr accessAddr = pkt->getAddr() - iobJBusAddr;
238        int cpuid = pkt->req->contextId();
239        int index;
240        uint64_t data;
241
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);
248            return;
249        }
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);
255            return;
256        };
257
258        panic("Write to unknown JBus offset 0x%x\n", accessAddr);
259}
260
261void
262Iob::receiveDeviceInterrupt(DeviceId devid)
263{
264    assert(devid < NumDeviceIds);
265    if (intCtl[devid].mask)
266        return;
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);
272}
273
274
275void
276Iob::generateIpi(Type type, int cpu_id, int vector)
277{
278    SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
279    if (cpu_id >= sys->getNumCPUs())
280        return;
281
282    switch (type) {
283      case 0: // interrupt
284        DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n",
285                cpu_id, vector);
286        ic->post(cpu_id, SparcISA::IT_INT_VEC, vector);
287        break;
288      case 1: // reset
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();
294        break;
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();
298        break;
299      case 3: // resume
300        DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id);
301        sys->threadContexts[cpu_id]->activate();
302        break;
303      default:
304        panic("Invalid type to generate ipi\n");
305    }
306}
307
308bool
309Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1)
310{
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)
314        return false;
315
316    DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n",
317            source, cpu_id, jIntVec);
318
319    jIntBusy[cpu_id].busy = true;
320    jIntBusy[cpu_id].source = source;
321    jBusData0[cpu_id] = d0;
322    jBusData1[cpu_id] = d1;
323
324    ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec);
325    return true;
326}
327
328void
329Iob::addressRanges(AddrRangeList &range_list)
330{
331    range_list.clear();
332    range_list.push_back(RangeSize(iobManAddr, iobManSize));
333    range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize));
334}
335
336
337void
338Iob::serialize(std::ostream &os)
339{
340
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);
350    };
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);
355    };
356}
357
358void
359Iob::unserialize(Checkpoint *cp, const std::string &section)
360{
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);
369    };
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);
373    };
374}
375
376Iob *
377IobParams::create()
378{
379    return new Iob(this);
380}
381