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