iob.cc revision 4216
112855Sgabeblack@google.com/*
212855Sgabeblack@google.com * Copyright (c) 2006 The Regents of The University of Michigan
312855Sgabeblack@google.com * All rights reserved.
412855Sgabeblack@google.com *
512855Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
612855Sgabeblack@google.com * modification, are permitted provided that the following conditions are
712855Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
812855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
912855Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1012855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1112855Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1212855Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1312855Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1412855Sgabeblack@google.com * this software without specific prior written permission.
1512855Sgabeblack@google.com *
1612855Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712855Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812855Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912855Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012855Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112855Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212855Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312855Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412855Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512855Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612855Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712855Sgabeblack@google.com *
2812855Sgabeblack@google.com * Authors: Ali Saidi
2912855Sgabeblack@google.com */
3012855Sgabeblack@google.com
3112855Sgabeblack@google.com/** @file
3212855Sgabeblack@google.com * This device implemetns the niagara I/O bridge chip. It manages incomming
3312855Sgabeblack@google.com * interrupts and posts them to the CPU when needed. It holds mask registers and
3412855Sgabeblack@google.com * various status registers for CPUs to check what interrupts are pending as
3512855Sgabeblack@google.com * well as facilities to send IPIs to other cpus.
3612855Sgabeblack@google.com */
3712855Sgabeblack@google.com
3812855Sgabeblack@google.com#include <cstring>
3912855Sgabeblack@google.com
4012855Sgabeblack@google.com#include "arch/sparc/isa_traits.hh"
4112855Sgabeblack@google.com#include "arch/sparc/faults.hh"
4212855Sgabeblack@google.com#include "base/trace.hh"
4312855Sgabeblack@google.com#include "cpu/intr_control.hh"
4412855Sgabeblack@google.com#include "dev/sparc/iob.hh"
4512855Sgabeblack@google.com#include "dev/platform.hh"
4612855Sgabeblack@google.com#include "mem/port.hh"
4712855Sgabeblack@google.com#include "mem/packet_access.hh"
4812855Sgabeblack@google.com#include "sim/builder.hh"
4912855Sgabeblack@google.com#include "sim/faults.hh"
5012855Sgabeblack@google.com#include "sim/system.hh"
5112855Sgabeblack@google.com
5212855Sgabeblack@google.comIob::Iob(Params *p)
5312855Sgabeblack@google.com    : PioDevice(p), ic(p->platform->intrctrl)
5412855Sgabeblack@google.com{
5512855Sgabeblack@google.com    iobManAddr = ULL(0x9800000000);
5612855Sgabeblack@google.com    iobManSize = ULL(0x0100000000);
5712855Sgabeblack@google.com    iobJBusAddr = ULL(0x9F00000000);
5812855Sgabeblack@google.com    iobJBusSize = ULL(0x0100000000);
5912855Sgabeblack@google.com    assert (params()->system->threadContexts.size() <= MaxNiagaraProcs);
6012855Sgabeblack@google.com    // Get the interrupt controller from the platform
6112855Sgabeblack@google.com    ic = platform->intrctrl;
6212855Sgabeblack@google.com
6312855Sgabeblack@google.com    for (int x = 0; x < NumDeviceIds; ++x) {
6412855Sgabeblack@google.com        intMan[x].cpu = 0;
6512855Sgabeblack@google.com        intMan[x].vector = 0;
6612855Sgabeblack@google.com        intCtl[x].mask = true;
6712855Sgabeblack@google.com        intCtl[x].pend = false;
6812855Sgabeblack@google.com    }
6912855Sgabeblack@google.com
7012855Sgabeblack@google.com}
7112855Sgabeblack@google.com
7212855Sgabeblack@google.comTick
7312855Sgabeblack@google.comIob::read(PacketPtr pkt)
7412855Sgabeblack@google.com{
7512855Sgabeblack@google.com    assert(pkt->result == Packet::Unknown);
7612855Sgabeblack@google.com
7712855Sgabeblack@google.com    if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
7812855Sgabeblack@google.com        readIob(pkt);
7912855Sgabeblack@google.com    else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
8012855Sgabeblack@google.com        readJBus(pkt);
8112855Sgabeblack@google.com    else
8212855Sgabeblack@google.com        panic("Invalid address reached Iob\n");
8312855Sgabeblack@google.com
8412855Sgabeblack@google.com    pkt->result = Packet::Success;
8512855Sgabeblack@google.com    return pioDelay;
8612855Sgabeblack@google.com}
8712855Sgabeblack@google.com
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            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 - IntManAddr) >> 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->getCpuNum();
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->getNumCPUs())
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
375
376
377
378BEGIN_DECLARE_SIM_OBJECT_PARAMS(Iob)
379    Param<Tick> pio_latency;
380    SimObjectParam<Platform *> platform;
381    SimObjectParam<System *> system;
382END_DECLARE_SIM_OBJECT_PARAMS(Iob)
383
384BEGIN_INIT_SIM_OBJECT_PARAMS(Iob)
385
386    INIT_PARAM(pio_latency, "Programmed IO latency"),
387    INIT_PARAM(platform, "platform"),
388    INIT_PARAM(system, "system object")
389
390END_INIT_SIM_OBJECT_PARAMS(Iob)
391
392CREATE_SIM_OBJECT(Iob)
393{
394    Iob::Params *p = new Iob::Params;
395    p->name = getInstanceName();
396    p->pio_delay = pio_latency;
397    p->platform = platform;
398    p->system = system;
399    return new Iob(p);
400}
401
402REGISTER_SIM_OBJECT("Iob", Iob)
403