iob.cc revision 4194
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/builder.hh"
49#include "sim/faults.hh"
50#include "sim/system.hh"
51
52Iob::Iob(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    // Get the interrupt controller from the platform
61    ic = platform->intrctrl;
62
63    for (int x = 0; x < NumDeviceIds; ++x) {
64        intMan[x].cpu = 0;
65        intMan[x].vector = 0;
66        intCtl[x].mask = true;
67        intCtl[x].pend = false;
68    }
69
70}
71
72Tick
73Iob::read(PacketPtr pkt)
74{
75    assert(pkt->result == Packet::Unknown);
76
77    if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
78        readIob(pkt);
79    else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
80        readJBus(pkt);
81    else
82        panic("Invalid address reached Iob\n");
83
84    pkt->result = Packet::Success;
85    return pioDelay;
86}
87
88void
89Iob::readIob(PacketPtr pkt)
90{
91        Addr accessAddr = pkt->getAddr() - iobManAddr;
92        int index;
93        uint64_t data;
94
95        if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
96            index = (accessAddr - IntManAddr) >> 3;
97            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            index = (accessAddr - IntManAddr) >> 3;
104            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->getCpuNum();
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->result = Packet::Success;
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            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            return;
205        }
206
207        if (accessAddr == JIntVecAddr) {
208            jIntVec = bits(pkt->get<uint64_t>(), 5,0);
209            return;
210        }
211
212        if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) {
213            Type type;
214            int cpu_id;
215            int vector;
216            index = (accessAddr - IntManAddr) >> 3;
217            data = pkt->get<uint64_t>();
218            type = (Type)bits(data,17,16);
219            cpu_id = bits(data, 12,8);
220            vector = bits(data,5,0);
221            generateIpi(type,cpu_id, vector);
222            return;
223        }
224
225        panic("Write to unknown IOB offset 0x%x\n", accessAddr);
226}
227
228void
229Iob::writeJBus(PacketPtr pkt)
230{
231        Addr accessAddr = pkt->getAddr() - iobJBusAddr;
232        int cpuid = pkt->req->getCpuNum();
233        int index;
234        uint64_t data;
235
236        if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
237            index = (accessAddr - JIntBusyAddr) >> 3;
238            data = pkt->get<uint64_t>();
239            jIntBusy[index].busy = bits(data,5,5);
240            return;
241        }
242        if (accessAddr == JIntABusyAddr) {
243            data = pkt->get<uint64_t>();
244            jIntBusy[cpuid].busy = bits(data,5,5);
245            return;
246        };
247
248        panic("Write to unknown JBus offset 0x%x\n", accessAddr);
249}
250
251void
252Iob::receiveDeviceInterrupt(DeviceId devid)
253{
254    assert(devid < NumDeviceIds);
255    if (intCtl[devid].mask)
256        return;
257    intCtl[devid].mask = true;
258    intCtl[devid].pend = true;
259    ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector);
260}
261
262
263void
264Iob::generateIpi(Type type, int cpu_id, int vector)
265{
266    SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
267    if (cpu_id >= sys->getNumCPUs())
268        return;
269
270    switch (type) {
271      case 0: // interrupt
272        ic->post(cpu_id, SparcISA::IT_INT_VEC, vector);
273        break;
274      case 1: // reset
275        warn("Sending reset to CPU: %d\n", cpu_id);
276        if (vector != por->trapType())
277            panic("Don't know how to set non-POR reset to cpu\n");
278        por->invoke(sys->threadContexts[cpu_id]);
279        sys->threadContexts[cpu_id]->activate();
280        break;
281      case 2: // idle -- this means stop executing and don't wake on interrupts
282        sys->threadContexts[cpu_id]->halt();
283        break;
284      case 3: // resume
285        sys->threadContexts[cpu_id]->activate();
286        break;
287      default:
288        panic("Invalid type to generate ipi\n");
289    }
290}
291
292bool
293Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1)
294{
295    // If we are already dealing with an interrupt for that cpu we can't deal
296    // with another one right now... come back later
297    if (jIntBusy[cpu_id].busy)
298        return false;
299
300    jIntBusy[cpu_id].busy = true;
301    jIntBusy[cpu_id].source = source;
302    jBusData0[cpu_id] = d0;
303    jBusData1[cpu_id] = d1;
304
305    ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec);
306    return true;
307}
308
309void
310Iob::addressRanges(AddrRangeList &range_list)
311{
312    range_list.clear();
313    range_list.push_back(RangeSize(iobManAddr, iobManSize));
314    range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize));
315}
316
317
318void
319Iob::serialize(std::ostream &os)
320{
321
322    SERIALIZE_SCALAR(jIntVec);
323    SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
324    SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
325    for (int x = 0; x < NumDeviceIds; x++) {
326        nameOut(os, csprintf("%s.Int%d", name(), x));
327        paramOut(os, "cpu", intMan[x].cpu);
328        paramOut(os, "vector", intMan[x].vector);
329        paramOut(os, "mask", intCtl[x].mask);
330        paramOut(os, "pend", intCtl[x].pend);
331    };
332    for (int x = 0; x < MaxNiagaraProcs; x++) {
333        nameOut(os, csprintf("%s.jIntBusy%d", name(), x));
334        paramOut(os, "busy", jIntBusy[x].busy);
335        paramOut(os, "source", jIntBusy[x].source);
336    };
337}
338
339void
340Iob::unserialize(Checkpoint *cp, const std::string &section)
341{
342    UNSERIALIZE_SCALAR(jIntVec);
343    UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
344    UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
345    for (int x = 0; x < NumDeviceIds; x++) {
346        paramIn(cp, csprintf("%s.Int%d", name(), x), "cpu", intMan[x].cpu);
347        paramIn(cp, csprintf("%s.Int%d", name(), x), "vector", intMan[x].vector);
348        paramIn(cp, csprintf("%s.Int%d", name(), x), "mask", intCtl[x].mask);
349        paramIn(cp, csprintf("%s.Int%d", name(), x), "pend", intCtl[x].pend);
350    };
351    for (int x = 0; x < MaxNiagaraProcs; x++) {
352        paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "busy", jIntBusy[x].busy);
353        paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "source", jIntBusy[x].source);
354    };
355}
356
357
358
359
360BEGIN_DECLARE_SIM_OBJECT_PARAMS(Iob)
361    Param<Tick> pio_latency;
362    SimObjectParam<Platform *> platform;
363    SimObjectParam<System *> system;
364END_DECLARE_SIM_OBJECT_PARAMS(Iob)
365
366BEGIN_INIT_SIM_OBJECT_PARAMS(Iob)
367
368    INIT_PARAM(pio_latency, "Programmed IO latency"),
369    INIT_PARAM(platform, "platform"),
370    INIT_PARAM(system, "system object")
371
372END_INIT_SIM_OBJECT_PARAMS(Iob)
373
374CREATE_SIM_OBJECT(Iob)
375{
376    Iob::Params *p = new Iob::Params;
377    p->name = getInstanceName();
378    p->pio_delay = pio_latency;
379    p->platform = platform;
380    p->system = system;
381    return new Iob(p);
382}
383
384REGISTER_SIM_OBJECT("Iob", Iob)
385