iob.cc revision 11294:a368064a2ab5
18968SN/A/*
28968SN/A * Copyright (c) 2006 The Regents of The University of Michigan
38968SN/A * All rights reserved.
410013Snilay@cs.wisc.edu *
58968SN/A * Redistribution and use in source and binary forms, with or without
610013Snilay@cs.wisc.edu * modification, are permitted provided that the following conditions are
78968SN/A * met: redistributions of source code must retain the above copyright
88968SN/A * notice, this list of conditions and the following disclaimer;
98968SN/A * redistributions in binary form must reproduce the above copyright
108968SN/A * notice, this list of conditions and the following disclaimer in the
118968SN/A * documentation and/or other materials provided with the distribution;
128968SN/A * neither the name of the copyright holders nor the names of its
1310526Snilay@cs.wisc.edu * contributors may be used to endorse or promote products derived from
148968SN/A * this software without specific prior written permission.
158968SN/A *
169842SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
179842SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
188968SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1910013Snilay@cs.wisc.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2011281Sstever@gmail.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
218968SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
228968SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238968SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2411374Ssteve.reinhardt@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2510315Snilay@cs.wisc.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
268968SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2710091Snilay@cs.wisc.edu *
288968SN/A * Authors: Ali Saidi
299469SN/A */
3010526Snilay@cs.wisc.edu
3110900Snilay@cs.wisc.edu/** @file
3211281Sstever@gmail.com * This device implemetns the niagara I/O bridge chip. It manages incomming
338968SN/A * interrupts and posts them to the CPU when needed. It holds mask registers and
3411374Ssteve.reinhardt@amd.com * various status registers for CPUs to check what interrupts are pending as
358968SN/A * well as facilities to send IPIs to other cpus.
368968SN/A */
378968SN/A
388968SN/A#include <cstring>
398968SN/A
408968SN/A#include "arch/sparc/faults.hh"
418968SN/A#include "arch/sparc/isa_traits.hh"
428968SN/A#include "base/bitfield.hh"
438968SN/A#include "base/trace.hh"
448968SN/A#include "cpu/intr_control.hh"
458968SN/A#include "cpu/thread_context.hh"
468968SN/A#include "debug/Iob.hh"
478968SN/A#include "dev/sparc/iob.hh"
488968SN/A#include "dev/platform.hh"
4910013Snilay@cs.wisc.edu#include "mem/packet_access.hh"
508968SN/A#include "mem/port.hh"
518968SN/A#include "sim/faults.hh"
528968SN/A#include "sim/system.hh"
538968SN/A
548968SN/AIob::Iob(const Params *p)
558968SN/A    : PioDevice(p), ic(p->platform->intrctrl)
568968SN/A{
578968SN/A    iobManAddr = ULL(0x9800000000);
588968SN/A    iobManSize = ULL(0x0100000000);
598968SN/A    iobJBusAddr = ULL(0x9F00000000);
6010013Snilay@cs.wisc.edu    iobJBusSize = ULL(0x0100000000);
618968SN/A    assert (params()->system->threadContexts.size() <= MaxNiagaraProcs);
628968SN/A
638968SN/A    pioDelay = p->pio_latency;
648968SN/A
659842SN/A    for (int x = 0; x < NumDeviceIds; ++x) {
669842SN/A        intMan[x].cpu = 0;
679842SN/A        intMan[x].vector = 0;
6810315Snilay@cs.wisc.edu        intCtl[x].mask = true;
6910013Snilay@cs.wisc.edu        intCtl[x].pend = false;
7010315Snilay@cs.wisc.edu    }
719842SN/A
729842SN/A}
738968SN/A
748968SN/ATick
759842SN/AIob::read(PacketPtr pkt)
7610091Snilay@cs.wisc.edu{
778968SN/A
789842SN/A    if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
798968SN/A        readIob(pkt);
808968SN/A    else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
818968SN/A        readJBus(pkt);
828968SN/A    else
838968SN/A        panic("Invalid address reached Iob\n");
8410013Snilay@cs.wisc.edu
858968SN/A    pkt->makeAtomicResponse();
868968SN/A    return pioDelay;
878968SN/A}
889469SN/A
898968SN/Avoid
908968SN/AIob::readIob(PacketPtr pkt)
918968SN/A{
928968SN/A        Addr accessAddr = pkt->getAddr() - iobManAddr;
938968SN/A
948968SN/A        assert(IntManAddr == 0);
958968SN/A        if (accessAddr < IntManAddr + IntManSize) {
968968SN/A            int index = (accessAddr - IntManAddr) >> 3;
979698SN/A            uint64_t data = intMan[index].cpu << 8 | intMan[index].vector << 0;
9810315Snilay@cs.wisc.edu            pkt->set(data);
999469SN/A            return;
1008968SN/A        }
1018968SN/A
1028968SN/A        if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
1039469SN/A            int index = (accessAddr - IntCtlAddr) >> 3;
1049469SN/A            uint64_t data = intCtl[index].mask  ? 1 << 2 : 0 |
1058968SN/A                intCtl[index].pend  ? 1 << 0 : 0;
1069842SN/A            pkt->set(data);
1079842SN/A            return;
1089842SN/A        }
1099842SN/A
11010013Snilay@cs.wisc.edu        if (accessAddr == JIntVecAddr) {
1119842SN/A            pkt->set(jIntVec);
1128968SN/A            return;
1138968SN/A        }
1148968SN/A
11510013Snilay@cs.wisc.edu        panic("Read to unknown IOB offset 0x%x\n", accessAddr);
1168968SN/A}
1178968SN/A
1188968SN/Avoid
1198968SN/AIob::readJBus(PacketPtr pkt)
1208968SN/A{
1219842SN/A        Addr accessAddr = pkt->getAddr() - iobJBusAddr;
12210013Snilay@cs.wisc.edu        ContextID cpuid = pkt->req->contextId();
1239842SN/A        int index;
1248968SN/A        uint64_t data;
1259469SN/A
1268968SN/A
1278968SN/A
1288968SN/A
1299842SN/A        if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) {
13010013Snilay@cs.wisc.edu            index = (accessAddr - JIntData0Addr) >> 3;
1318968SN/A            pkt->set(jBusData0[index]);
1328968SN/A            return;
1339207SN/A        }
1348968SN/A
13510091Snilay@cs.wisc.edu        if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) {
13610091Snilay@cs.wisc.edu            index = (accessAddr - JIntData1Addr) >> 3;
13710091Snilay@cs.wisc.edu            pkt->set(jBusData1[index]);
1388968SN/A            return;
1399469SN/A        }
1409469SN/A
14110013Snilay@cs.wisc.edu        if (accessAddr == JIntDataA0Addr) {
1429469SN/A            pkt->set(jBusData0[cpuid]);
1438968SN/A            return;
1448968SN/A        }
1458968SN/A
14610013Snilay@cs.wisc.edu        if (accessAddr == JIntDataA1Addr) {
1478968SN/A            pkt->set(jBusData1[cpuid]);
1488968SN/A            return;
1498968SN/A        }
1508968SN/A
1518968SN/A        if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
1529842SN/A            index = (accessAddr - JIntBusyAddr) >> 3;
15310013Snilay@cs.wisc.edu            data = jIntBusy[index].busy ? 1 << 5 : 0 |
1549842SN/A                   jIntBusy[index].source;
1558968SN/A            pkt->set(data);
1569469SN/A            return;
1578968SN/A        }
1588968SN/A        if (accessAddr == JIntABusyAddr) {
1598968SN/A            data = jIntBusy[cpuid].busy ? 1 << 5 : 0 |
16010013Snilay@cs.wisc.edu                   jIntBusy[cpuid].source;
1618968SN/A            pkt->set(data);
1628968SN/A            return;
1638968SN/A        };
1649842SN/A
16510091Snilay@cs.wisc.edu        panic("Read to unknown JBus offset 0x%x\n", accessAddr);
1668968SN/A}
1679842SN/A
1688968SN/ATick
1698968SN/AIob::write(PacketPtr pkt)
1708968SN/A{
1718968SN/A    if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
1728968SN/A        writeIob(pkt);
17310013Snilay@cs.wisc.edu    else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
1748968SN/A        writeJBus(pkt);
1758968SN/A    else
1768968SN/A        panic("Invalid address reached Iob\n");
1779469SN/A
1788968SN/A
1798968SN/A    pkt->makeAtomicResponse();
1808968SN/A    return pioDelay;
1818968SN/A}
1828968SN/A
1838968SN/Avoid
1848968SN/AIob::writeIob(PacketPtr pkt)
1858968SN/A{
1869698SN/A        Addr accessAddr = pkt->getAddr() - iobManAddr;
18710315Snilay@cs.wisc.edu        int index;
1889469SN/A        uint64_t data;
1898968SN/A
1908968SN/A        assert(IntManAddr == 0);
1918968SN/A        if (accessAddr < IntManAddr + IntManSize) {
1929469SN/A            index = (accessAddr - IntManAddr) >> 3;
1939469SN/A            data = pkt->get<uint64_t>();
1948968SN/A            intMan[index].cpu = bits(data,12,8);
1959842SN/A            intMan[index].vector = bits(data,5,0);
1969842SN/A            DPRINTF(Iob, "Wrote IntMan %d cpu %d, vec %d\n", index,
1979842SN/A                    intMan[index].cpu, intMan[index].vector);
1989842SN/A            return;
19910013Snilay@cs.wisc.edu        }
2009842SN/A
2018968SN/A        if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
2028968SN/A            index = (accessAddr - IntCtlAddr) >> 3;
2038968SN/A            data = pkt->get<uint64_t>();
20410013Snilay@cs.wisc.edu            intCtl[index].mask = bits(data,2,2);
2058968SN/A            if (bits(data,1,1))
2068968SN/A                intCtl[index].pend = false;
2078968SN/A            DPRINTF(Iob, "Wrote IntCtl %d pend %d cleared %d\n", index,
2088968SN/A                    intCtl[index].pend, bits(data,2,2));
2098968SN/A            return;
2109842SN/A        }
21110013Snilay@cs.wisc.edu
2129842SN/A        if (accessAddr == JIntVecAddr) {
2138968SN/A            jIntVec = bits(pkt->get<uint64_t>(), 5,0);
2149469SN/A            DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec);
2158968SN/A            return;
2168968SN/A        }
2178968SN/A
2189842SN/A        if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) {
21910013Snilay@cs.wisc.edu            Type type;
2208968SN/A            int cpu_id;
2218968SN/A            int vector;
2229207SN/A            index = (accessAddr - IntManAddr) >> 3;
2238968SN/A            data = pkt->get<uint64_t>();
22410091Snilay@cs.wisc.edu            type = (Type)bits(data,17,16);
22510091Snilay@cs.wisc.edu            cpu_id = bits(data, 12,8);
22610091Snilay@cs.wisc.edu            vector = bits(data,5,0);
2278968SN/A            generateIpi(type,cpu_id, vector);
2289469SN/A            return;
2299469SN/A        }
23010013Snilay@cs.wisc.edu
2319469SN/A        panic("Write to unknown IOB offset 0x%x\n", accessAddr);
2328968SN/A}
2338968SN/A
2348968SN/Avoid
23510013Snilay@cs.wisc.eduIob::writeJBus(PacketPtr pkt)
2368968SN/A{
2378968SN/A        Addr accessAddr = pkt->getAddr() - iobJBusAddr;
2388968SN/A        ContextID cpuid = pkt->req->contextId();
2398968SN/A        int index;
2408968SN/A        uint64_t data;
2419842SN/A
24210013Snilay@cs.wisc.edu        if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
2439842SN/A            index = (accessAddr - JIntBusyAddr) >> 3;
2448968SN/A            data = pkt->get<uint64_t>();
2459469SN/A            jIntBusy[index].busy = bits(data,5,5);
2468968SN/A            DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", index,
2478968SN/A                    jIntBusy[index].busy);
2488968SN/A            return;
24910013Snilay@cs.wisc.edu        }
2508968SN/A        if (accessAddr == JIntABusyAddr) {
2519842SN/A            data = pkt->get<uint64_t>();
2529842SN/A            jIntBusy[cpuid].busy = bits(data,5,5);
2539842SN/A            DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", cpuid,
25410315Snilay@cs.wisc.edu                    jIntBusy[cpuid].busy);
25510013Snilay@cs.wisc.edu            return;
25610315Snilay@cs.wisc.edu        };
2579842SN/A
2589842SN/A        panic("Write to unknown JBus offset 0x%x\n", accessAddr);
25910315Snilay@cs.wisc.edu}
26010315Snilay@cs.wisc.edu
26110315Snilay@cs.wisc.eduvoid
26210315Snilay@cs.wisc.eduIob::receiveDeviceInterrupt(DeviceId devid)
26310315Snilay@cs.wisc.edu{
26410315Snilay@cs.wisc.edu    assert(devid < NumDeviceIds);
26510315Snilay@cs.wisc.edu    if (intCtl[devid].mask)
26610315Snilay@cs.wisc.edu        return;
2678968SN/A    intCtl[devid].mask = true;
2688968SN/A    intCtl[devid].pend = true;
26910451Snilay@cs.wisc.edu    DPRINTF(Iob, "Receiving Device interrupt: %d for cpu %d vec %d\n",
27010451Snilay@cs.wisc.edu            devid, intMan[devid].cpu, intMan[devid].vector);
27110013Snilay@cs.wisc.edu    ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector);
2728968SN/A}
2738968SN/A
2748968SN/A
2758968SN/Avoid
27610013Snilay@cs.wisc.eduIob::generateIpi(Type type, int cpu_id, int vector)
2779625SN/A{
2789625SN/A    SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
2798968SN/A    if (cpu_id >= sys->numContexts())
2808968SN/A        return;
2818968SN/A
2829625SN/A    switch (type) {
28310013Snilay@cs.wisc.edu      case 0: // interrupt
2849625SN/A        DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n",
2859625SN/A                cpu_id, vector);
2869625SN/A        ic->post(cpu_id, SparcISA::IT_INT_VEC, vector);
2879625SN/A        break;
2889625SN/A      case 1: // reset
2898968SN/A        warn("Sending reset to CPU: %d\n", cpu_id);
29010013Snilay@cs.wisc.edu        if (vector != por->trapType())
2918968SN/A            panic("Don't know how to set non-POR reset to cpu\n");
2928968SN/A        por->invoke(sys->threadContexts[cpu_id]);
2938968SN/A        sys->threadContexts[cpu_id]->activate();
2949924SN/A        break;
2959924SN/A      case 2: // idle -- this means stop executing and don't wake on interrupts
29610451Snilay@cs.wisc.edu        DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id);
29710451Snilay@cs.wisc.edu        sys->threadContexts[cpu_id]->halt();
29810451Snilay@cs.wisc.edu        break;
29910451Snilay@cs.wisc.edu      case 3: // resume
30010451Snilay@cs.wisc.edu        DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id);
30110451Snilay@cs.wisc.edu        sys->threadContexts[cpu_id]->activate();
30210451Snilay@cs.wisc.edu        break;
3039924SN/A      default:
30410013Snilay@cs.wisc.edu        panic("Invalid type to generate ipi\n");
3059924SN/A    }
3069924SN/A}
3079924SN/A
3088968SN/Abool
3098968SN/AIob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1)
3108968SN/A{
31110013Snilay@cs.wisc.edu    // If we are already dealing with an interrupt for that cpu we can't deal
3128968SN/A    // with another one right now... come back later
3138968SN/A    if (jIntBusy[cpu_id].busy)
3148968SN/A        return false;
3158968SN/A
3168968SN/A    DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n",
3178968SN/A            source, cpu_id, jIntVec);
3188968SN/A
31910013Snilay@cs.wisc.edu    jIntBusy[cpu_id].busy = true;
3208968SN/A    jIntBusy[cpu_id].source = source;
3218968SN/A    jBusData0[cpu_id] = d0;
3228968SN/A    jBusData1[cpu_id] = d1;
3238968SN/A
3248968SN/A    ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec);
3258968SN/A    return true;
3268968SN/A}
3278968SN/A
3288968SN/AAddrRangeList
3298968SN/AIob::getAddrRanges() const
3308968SN/A{
3318968SN/A    AddrRangeList ranges;
33210013Snilay@cs.wisc.edu    ranges.push_back(RangeSize(iobManAddr, iobManSize));
3338968SN/A    ranges.push_back(RangeSize(iobJBusAddr, iobJBusSize));
3348968SN/A    return ranges;
3358968SN/A}
3368968SN/A
3378968SN/A
3388968SN/Avoid
3398968SN/AIob::serialize(CheckpointOut &cp) const
3408968SN/A{
3418968SN/A
3428968SN/A    SERIALIZE_SCALAR(jIntVec);
3438968SN/A    SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
34410013Snilay@cs.wisc.edu    SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
3458968SN/A    for (int x = 0; x < NumDeviceIds; x++) {
3468968SN/A        ScopedCheckpointSection sec(cp, csprintf("Int%d", x));
3478968SN/A        paramOut(cp, "cpu", intMan[x].cpu);
3488968SN/A        paramOut(cp, "vector", intMan[x].vector);
3498968SN/A        paramOut(cp, "mask", intCtl[x].mask);
3508968SN/A        paramOut(cp, "pend", intCtl[x].pend);
3518968SN/A    };
3528968SN/A    for (int x = 0; x < MaxNiagaraProcs; x++) {
3538968SN/A        ScopedCheckpointSection sec(cp, csprintf("jIntBusy%d", x));
3548968SN/A        paramOut(cp, "busy", jIntBusy[x].busy);
3558968SN/A        paramOut(cp, "source", jIntBusy[x].source);
35610013Snilay@cs.wisc.edu    };
3578968SN/A}
3588968SN/A
3598968SN/Avoid
3608968SN/AIob::unserialize(CheckpointIn &cp)
3618968SN/A{
3628968SN/A    UNSERIALIZE_SCALAR(jIntVec);
36310451Snilay@cs.wisc.edu    UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
36410013Snilay@cs.wisc.edu    UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
3658968SN/A    for (int x = 0; x < NumDeviceIds; x++) {
3668968SN/A        ScopedCheckpointSection sec(cp, csprintf("Int%d", x));
3678968SN/A        paramIn(cp, "cpu", intMan[x].cpu);
3688968SN/A        paramIn(cp, "vector", intMan[x].vector);
36910451Snilay@cs.wisc.edu        paramIn(cp, "mask", intCtl[x].mask);
37010013Snilay@cs.wisc.edu        paramIn(cp, "pend", intCtl[x].pend);
3718968SN/A    };
3728968SN/A    for (int x = 0; x < MaxNiagaraProcs; x++) {
3738968SN/A        ScopedCheckpointSection sec(cp, csprintf("jIntBusy%d", x));
3748968SN/A        paramIn(cp, "busy", jIntBusy[x].busy);
3758968SN/A        paramIn(cp, "source", jIntBusy[x].source);
37610013Snilay@cs.wisc.edu    };
3778968SN/A}
3788968SN/A
37910451Snilay@cs.wisc.eduIob *
3808968SN/AIobParams::create()
3818968SN/A{
3828968SN/A    return new Iob(this);
3838968SN/A}
3848968SN/A