iob.cc revision 4870
15081Sgblack@eecs.umich.edu/*
25081Sgblack@eecs.umich.edu * Copyright (c) 2006 The Regents of The University of Michigan
35081Sgblack@eecs.umich.edu * All rights reserved.
47087Snate@binkert.org *
57087Snate@binkert.org * Redistribution and use in source and binary forms, with or without
67087Snate@binkert.org * modification, are permitted provided that the following conditions are
77087Snate@binkert.org * met: redistributions of source code must retain the above copyright
87087Snate@binkert.org * notice, this list of conditions and the following disclaimer;
97087Snate@binkert.org * redistributions in binary form must reproduce the above copyright
107087Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
117087Snate@binkert.org * documentation and/or other materials provided with the distribution;
125081Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137087Snate@binkert.org * contributors may be used to endorse or promote products derived from
147087Snate@binkert.org * this software without specific prior written permission.
157087Snate@binkert.org *
167087Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177087Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187087Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197087Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207087Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215081Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227087Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235081Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245081Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255081Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265081Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275081Sgblack@eecs.umich.edu *
285081Sgblack@eecs.umich.edu * Authors: Ali Saidi
295081Sgblack@eecs.umich.edu */
305081Sgblack@eecs.umich.edu
315081Sgblack@eecs.umich.edu/** @file
325081Sgblack@eecs.umich.edu * This device implemetns the niagara I/O bridge chip. It manages incomming
335081Sgblack@eecs.umich.edu * interrupts and posts them to the CPU when needed. It holds mask registers and
345081Sgblack@eecs.umich.edu * various status registers for CPUs to check what interrupts are pending as
355081Sgblack@eecs.umich.edu * well as facilities to send IPIs to other cpus.
365081Sgblack@eecs.umich.edu */
375081Sgblack@eecs.umich.edu
385081Sgblack@eecs.umich.edu#include <cstring>
395081Sgblack@eecs.umich.edu
405081Sgblack@eecs.umich.edu#include "arch/sparc/isa_traits.hh"
415081Sgblack@eecs.umich.edu#include "arch/sparc/faults.hh"
425081Sgblack@eecs.umich.edu#include "base/trace.hh"
435081Sgblack@eecs.umich.edu#include "cpu/intr_control.hh"
445081Sgblack@eecs.umich.edu#include "dev/sparc/iob.hh"
455081Sgblack@eecs.umich.edu#include "dev/platform.hh"
465081Sgblack@eecs.umich.edu#include "mem/port.hh"
475081Sgblack@eecs.umich.edu#include "mem/packet_access.hh"
485081Sgblack@eecs.umich.edu#include "sim/builder.hh"
495081Sgblack@eecs.umich.edu#include "sim/faults.hh"
505081Sgblack@eecs.umich.edu#include "sim/system.hh"
515081Sgblack@eecs.umich.edu
525081Sgblack@eecs.umich.eduIob::Iob(Params *p)
537501STushar.Krishna@amd.com    : PioDevice(p), ic(p->platform->intrctrl)
547501STushar.Krishna@amd.com{
555081Sgblack@eecs.umich.edu    iobManAddr = ULL(0x9800000000);
565081Sgblack@eecs.umich.edu    iobManSize = ULL(0x0100000000);
575081Sgblack@eecs.umich.edu    iobJBusAddr = ULL(0x9F00000000);
585081Sgblack@eecs.umich.edu    iobJBusSize = ULL(0x0100000000);
595081Sgblack@eecs.umich.edu    assert (params()->system->threadContexts.size() <= MaxNiagaraProcs);
605081Sgblack@eecs.umich.edu    // Get the interrupt controller from the platform
617501STushar.Krishna@amd.com    ic = platform->intrctrl;
627501STushar.Krishna@amd.com
635081Sgblack@eecs.umich.edu    for (int x = 0; x < NumDeviceIds; ++x) {
645081Sgblack@eecs.umich.edu        intMan[x].cpu = 0;
655081Sgblack@eecs.umich.edu        intMan[x].vector = 0;
665081Sgblack@eecs.umich.edu        intCtl[x].mask = true;
675081Sgblack@eecs.umich.edu        intCtl[x].pend = false;
687501STushar.Krishna@amd.com    }
697501STushar.Krishna@amd.com
705081Sgblack@eecs.umich.edu}
715081Sgblack@eecs.umich.edu
725081Sgblack@eecs.umich.eduTick
735081Sgblack@eecs.umich.eduIob::read(PacketPtr pkt)
745081Sgblack@eecs.umich.edu{
755081Sgblack@eecs.umich.edu
767501STushar.Krishna@amd.com    if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
777501STushar.Krishna@amd.com        readIob(pkt);
785081Sgblack@eecs.umich.edu    else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
795081Sgblack@eecs.umich.edu        readJBus(pkt);
806088Sgblack@eecs.umich.edu    else
816088Sgblack@eecs.umich.edu        panic("Invalid address reached Iob\n");
826088Sgblack@eecs.umich.edu
836088Sgblack@eecs.umich.edu    pkt->makeAtomicResponse();
846088Sgblack@eecs.umich.edu    return pioDelay;
856088Sgblack@eecs.umich.edu}
866088Sgblack@eecs.umich.edu
876088Sgblack@eecs.umich.eduvoid
886088Sgblack@eecs.umich.eduIob::readIob(PacketPtr pkt)
896088Sgblack@eecs.umich.edu{
906088Sgblack@eecs.umich.edu        Addr accessAddr = pkt->getAddr() - iobManAddr;
916088Sgblack@eecs.umich.edu        int index;
926088Sgblack@eecs.umich.edu        uint64_t data;
936088Sgblack@eecs.umich.edu
946088Sgblack@eecs.umich.edu        if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
955081Sgblack@eecs.umich.edu            index = (accessAddr - IntManAddr) >> 3;
96            data = intMan[index].cpu << 8 | intMan[index].vector << 0;
97            pkt->set(data);
98            return;
99        }
100
101        if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
102            index = (accessAddr - IntManAddr) >> 3;
103            data = intCtl[index].mask  ? 1 << 2 : 0 |
104                   intCtl[index].pend  ? 1 << 0 : 0;
105            pkt->set(data);
106            return;
107        }
108
109        if (accessAddr == JIntVecAddr) {
110            pkt->set(jIntVec);
111            return;
112        }
113
114        panic("Read to unknown IOB offset 0x%x\n", accessAddr);
115}
116
117void
118Iob::readJBus(PacketPtr pkt)
119{
120        Addr accessAddr = pkt->getAddr() - iobJBusAddr;
121        int cpuid = pkt->req->getCpuNum();
122        int index;
123        uint64_t data;
124
125
126
127
128        if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) {
129            index = (accessAddr - JIntData0Addr) >> 3;
130            pkt->set(jBusData0[index]);
131            return;
132        }
133
134        if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) {
135            index = (accessAddr - JIntData1Addr) >> 3;
136            pkt->set(jBusData1[index]);
137            return;
138        }
139
140        if (accessAddr == JIntDataA0Addr) {
141            pkt->set(jBusData0[cpuid]);
142            return;
143        }
144
145        if (accessAddr == JIntDataA1Addr) {
146            pkt->set(jBusData1[cpuid]);
147            return;
148        }
149
150        if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
151            index = (accessAddr - JIntBusyAddr) >> 3;
152            data = jIntBusy[index].busy ? 1 << 5 : 0 |
153                   jIntBusy[index].source;
154            pkt->set(data);
155            return;
156        }
157        if (accessAddr == JIntABusyAddr) {
158            data = jIntBusy[cpuid].busy ? 1 << 5 : 0 |
159                   jIntBusy[cpuid].source;
160            pkt->set(data);
161            return;
162        };
163
164        panic("Read to unknown JBus offset 0x%x\n", accessAddr);
165}
166
167Tick
168Iob::write(PacketPtr pkt)
169{
170    if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
171        writeIob(pkt);
172    else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
173        writeJBus(pkt);
174    else
175        panic("Invalid address reached Iob\n");
176
177
178    pkt->makeAtomicResponse();
179    return pioDelay;
180}
181
182void
183Iob::writeIob(PacketPtr pkt)
184{
185        Addr accessAddr = pkt->getAddr() - iobManAddr;
186        int index;
187        uint64_t data;
188
189        if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
190            index = (accessAddr - IntManAddr) >> 3;
191            data = pkt->get<uint64_t>();
192            intMan[index].cpu = bits(data,12,8);
193            intMan[index].vector = bits(data,5,0);
194            DPRINTF(Iob, "Wrote IntMan %d cpu %d, vec %d\n", index,
195                    intMan[index].cpu, intMan[index].vector);
196            return;
197        }
198
199        if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
200            index = (accessAddr - IntManAddr) >> 3;
201            data = pkt->get<uint64_t>();
202            intCtl[index].mask = bits(data,2,2);
203            if (bits(data,1,1))
204                intCtl[index].pend = false;
205            DPRINTF(Iob, "Wrote IntCtl %d pend %d cleared %d\n", index,
206                    intCtl[index].pend, bits(data,2,2));
207            return;
208        }
209
210        if (accessAddr == JIntVecAddr) {
211            jIntVec = bits(pkt->get<uint64_t>(), 5,0);
212            DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec);
213            return;
214        }
215
216        if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) {
217            Type type;
218            int cpu_id;
219            int vector;
220            index = (accessAddr - IntManAddr) >> 3;
221            data = pkt->get<uint64_t>();
222            type = (Type)bits(data,17,16);
223            cpu_id = bits(data, 12,8);
224            vector = bits(data,5,0);
225            generateIpi(type,cpu_id, vector);
226            return;
227        }
228
229        panic("Write to unknown IOB offset 0x%x\n", accessAddr);
230}
231
232void
233Iob::writeJBus(PacketPtr pkt)
234{
235        Addr accessAddr = pkt->getAddr() - iobJBusAddr;
236        int cpuid = pkt->req->getCpuNum();
237        int index;
238        uint64_t data;
239
240        if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
241            index = (accessAddr - JIntBusyAddr) >> 3;
242            data = pkt->get<uint64_t>();
243            jIntBusy[index].busy = bits(data,5,5);
244            DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", index,
245                    jIntBusy[index].busy);
246            return;
247        }
248        if (accessAddr == JIntABusyAddr) {
249            data = pkt->get<uint64_t>();
250            jIntBusy[cpuid].busy = bits(data,5,5);
251            DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", cpuid,
252                    jIntBusy[cpuid].busy);
253            return;
254        };
255
256        panic("Write to unknown JBus offset 0x%x\n", accessAddr);
257}
258
259void
260Iob::receiveDeviceInterrupt(DeviceId devid)
261{
262    assert(devid < NumDeviceIds);
263    if (intCtl[devid].mask)
264        return;
265    intCtl[devid].mask = true;
266    intCtl[devid].pend = true;
267    DPRINTF(Iob, "Receiving Device interrupt: %d for cpu %d vec %d\n",
268            devid, intMan[devid].cpu, intMan[devid].vector);
269    ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector);
270}
271
272
273void
274Iob::generateIpi(Type type, int cpu_id, int vector)
275{
276    SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
277    if (cpu_id >= sys->getNumCPUs())
278        return;
279
280    switch (type) {
281      case 0: // interrupt
282        DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n",
283                cpu_id, vector);
284        ic->post(cpu_id, SparcISA::IT_INT_VEC, vector);
285        break;
286      case 1: // reset
287        warn("Sending reset to CPU: %d\n", cpu_id);
288        if (vector != por->trapType())
289            panic("Don't know how to set non-POR reset to cpu\n");
290        por->invoke(sys->threadContexts[cpu_id]);
291        sys->threadContexts[cpu_id]->activate();
292        break;
293      case 2: // idle -- this means stop executing and don't wake on interrupts
294        DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id);
295        sys->threadContexts[cpu_id]->halt();
296        break;
297      case 3: // resume
298        DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id);
299        sys->threadContexts[cpu_id]->activate();
300        break;
301      default:
302        panic("Invalid type to generate ipi\n");
303    }
304}
305
306bool
307Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1)
308{
309    // If we are already dealing with an interrupt for that cpu we can't deal
310    // with another one right now... come back later
311    if (jIntBusy[cpu_id].busy)
312        return false;
313
314    DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n",
315            source, cpu_id, jIntVec);
316
317    jIntBusy[cpu_id].busy = true;
318    jIntBusy[cpu_id].source = source;
319    jBusData0[cpu_id] = d0;
320    jBusData1[cpu_id] = d1;
321
322    ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec);
323    return true;
324}
325
326void
327Iob::addressRanges(AddrRangeList &range_list)
328{
329    range_list.clear();
330    range_list.push_back(RangeSize(iobManAddr, iobManSize));
331    range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize));
332}
333
334
335void
336Iob::serialize(std::ostream &os)
337{
338
339    SERIALIZE_SCALAR(jIntVec);
340    SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
341    SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
342    for (int x = 0; x < NumDeviceIds; x++) {
343        nameOut(os, csprintf("%s.Int%d", name(), x));
344        paramOut(os, "cpu", intMan[x].cpu);
345        paramOut(os, "vector", intMan[x].vector);
346        paramOut(os, "mask", intCtl[x].mask);
347        paramOut(os, "pend", intCtl[x].pend);
348    };
349    for (int x = 0; x < MaxNiagaraProcs; x++) {
350        nameOut(os, csprintf("%s.jIntBusy%d", name(), x));
351        paramOut(os, "busy", jIntBusy[x].busy);
352        paramOut(os, "source", jIntBusy[x].source);
353    };
354}
355
356void
357Iob::unserialize(Checkpoint *cp, const std::string &section)
358{
359    UNSERIALIZE_SCALAR(jIntVec);
360    UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
361    UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
362    for (int x = 0; x < NumDeviceIds; x++) {
363        paramIn(cp, csprintf("%s.Int%d", name(), x), "cpu", intMan[x].cpu);
364        paramIn(cp, csprintf("%s.Int%d", name(), x), "vector", intMan[x].vector);
365        paramIn(cp, csprintf("%s.Int%d", name(), x), "mask", intCtl[x].mask);
366        paramIn(cp, csprintf("%s.Int%d", name(), x), "pend", intCtl[x].pend);
367    };
368    for (int x = 0; x < MaxNiagaraProcs; x++) {
369        paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "busy", jIntBusy[x].busy);
370        paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "source", jIntBusy[x].source);
371    };
372}
373
374
375
376
377BEGIN_DECLARE_SIM_OBJECT_PARAMS(Iob)
378    Param<Tick> pio_latency;
379    SimObjectParam<Platform *> platform;
380    SimObjectParam<System *> system;
381END_DECLARE_SIM_OBJECT_PARAMS(Iob)
382
383BEGIN_INIT_SIM_OBJECT_PARAMS(Iob)
384
385    INIT_PARAM(pio_latency, "Programmed IO latency"),
386    INIT_PARAM(platform, "platform"),
387    INIT_PARAM(system, "system object")
388
389END_INIT_SIM_OBJECT_PARAMS(Iob)
390
391CREATE_SIM_OBJECT(Iob)
392{
393    Iob::Params *p = new Iob::Params;
394    p->name = getInstanceName();
395    p->pio_delay = pio_latency;
396    p->platform = platform;
397    p->system = system;
398    return new Iob(p);
399}
400
401REGISTER_SIM_OBJECT("Iob", Iob)
402