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