iob.cc revision 13231
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 "dev/sparc/iob.hh" 39 40#include <cstring> 41 42#include "arch/sparc/faults.hh" 43#include "arch/sparc/isa_traits.hh" 44#include "base/bitfield.hh" 45#include "base/trace.hh" 46#include "cpu/intr_control.hh" 47#include "cpu/thread_context.hh" 48#include "debug/Iob.hh" 49#include "dev/platform.hh" 50#include "mem/packet_access.hh" 51#include "mem/port.hh" 52#include "sim/faults.hh" 53#include "sim/system.hh" 54 55Iob::Iob(const Params *p) 56 : PioDevice(p), ic(p->platform->intrctrl) 57{ 58 iobManAddr = ULL(0x9800000000); 59 iobManSize = ULL(0x0100000000); 60 iobJBusAddr = ULL(0x9F00000000); 61 iobJBusSize = ULL(0x0100000000); 62 assert (params()->system->threadContexts.size() <= MaxNiagaraProcs); 63 64 pioDelay = p->pio_latency; 65 66 for (int x = 0; x < NumDeviceIds; ++x) { 67 intMan[x].cpu = 0; 68 intMan[x].vector = 0; 69 intCtl[x].mask = true; 70 intCtl[x].pend = false; 71 } 72 73} 74 75Tick 76Iob::read(PacketPtr pkt) 77{ 78 79 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize) 80 readIob(pkt); 81 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize) 82 readJBus(pkt); 83 else 84 panic("Invalid address reached Iob\n"); 85 86 pkt->makeAtomicResponse(); 87 return pioDelay; 88} 89 90void 91Iob::readIob(PacketPtr pkt) 92{ 93 Addr accessAddr = pkt->getAddr() - iobManAddr; 94 95 assert(IntManAddr == 0); 96 if (accessAddr < IntManAddr + IntManSize) { 97 int index = (accessAddr - IntManAddr) >> 3; 98 uint64_t data = intMan[index].cpu << 8 | intMan[index].vector << 0; 99 pkt->setBE(data); 100 return; 101 } 102 103 if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) { 104 int index = (accessAddr - IntCtlAddr) >> 3; 105 uint64_t data = intCtl[index].mask ? 1 << 2 : 0 | 106 intCtl[index].pend ? 1 << 0 : 0; 107 pkt->setBE(data); 108 return; 109 } 110 111 if (accessAddr == JIntVecAddr) { 112 pkt->setBE(jIntVec); 113 return; 114 } 115 116 panic("Read to unknown IOB offset 0x%x\n", accessAddr); 117} 118 119void 120Iob::readJBus(PacketPtr pkt) 121{ 122 Addr accessAddr = pkt->getAddr() - iobJBusAddr; 123 ContextID cpuid = pkt->req->contextId(); 124 int index; 125 uint64_t data; 126 127 128 129 130 if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) { 131 index = (accessAddr - JIntData0Addr) >> 3; 132 pkt->setBE(jBusData0[index]); 133 return; 134 } 135 136 if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) { 137 index = (accessAddr - JIntData1Addr) >> 3; 138 pkt->setBE(jBusData1[index]); 139 return; 140 } 141 142 if (accessAddr == JIntDataA0Addr) { 143 pkt->setBE(jBusData0[cpuid]); 144 return; 145 } 146 147 if (accessAddr == JIntDataA1Addr) { 148 pkt->setBE(jBusData1[cpuid]); 149 return; 150 } 151 152 if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) { 153 index = (accessAddr - JIntBusyAddr) >> 3; 154 data = jIntBusy[index].busy ? 1 << 5 : 0 | 155 jIntBusy[index].source; 156 pkt->setBE(data); 157 return; 158 } 159 if (accessAddr == JIntABusyAddr) { 160 data = jIntBusy[cpuid].busy ? 1 << 5 : 0 | 161 jIntBusy[cpuid].source; 162 pkt->setBE(data); 163 return; 164 }; 165 166 panic("Read to unknown JBus offset 0x%x\n", accessAddr); 167} 168 169Tick 170Iob::write(PacketPtr pkt) 171{ 172 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize) 173 writeIob(pkt); 174 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize) 175 writeJBus(pkt); 176 else 177 panic("Invalid address reached Iob\n"); 178 179 180 pkt->makeAtomicResponse(); 181 return pioDelay; 182} 183 184void 185Iob::writeIob(PacketPtr pkt) 186{ 187 Addr accessAddr = pkt->getAddr() - iobManAddr; 188 int index; 189 uint64_t data; 190 191 assert(IntManAddr == 0); 192 if (accessAddr < IntManAddr + IntManSize) { 193 index = (accessAddr - IntManAddr) >> 3; 194 data = pkt->getBE<uint64_t>(); 195 intMan[index].cpu = bits(data,12,8); 196 intMan[index].vector = bits(data,5,0); 197 DPRINTF(Iob, "Wrote IntMan %d cpu %d, vec %d\n", index, 198 intMan[index].cpu, intMan[index].vector); 199 return; 200 } 201 202 if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) { 203 index = (accessAddr - IntCtlAddr) >> 3; 204 data = pkt->getBE<uint64_t>(); 205 intCtl[index].mask = bits(data,2,2); 206 if (bits(data,1,1)) 207 intCtl[index].pend = false; 208 DPRINTF(Iob, "Wrote IntCtl %d pend %d cleared %d\n", index, 209 intCtl[index].pend, bits(data,2,2)); 210 return; 211 } 212 213 if (accessAddr == JIntVecAddr) { 214 jIntVec = bits(pkt->getBE<uint64_t>(), 5,0); 215 DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec); 216 return; 217 } 218 219 if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) { 220 Type type; 221 int cpu_id; 222 int vector; 223 index = (accessAddr - IntManAddr) >> 3; 224 data = pkt->getBE<uint64_t>(); 225 type = (Type)bits(data,17,16); 226 cpu_id = bits(data, 12,8); 227 vector = bits(data,5,0); 228 generateIpi(type,cpu_id, vector); 229 return; 230 } 231 232 panic("Write to unknown IOB offset 0x%x\n", accessAddr); 233} 234 235void 236Iob::writeJBus(PacketPtr pkt) 237{ 238 Addr accessAddr = pkt->getAddr() - iobJBusAddr; 239 ContextID cpuid = pkt->req->contextId(); 240 int index; 241 uint64_t data; 242 243 if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) { 244 index = (accessAddr - JIntBusyAddr) >> 3; 245 data = pkt->getBE<uint64_t>(); 246 jIntBusy[index].busy = bits(data,5,5); 247 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", index, 248 jIntBusy[index].busy); 249 return; 250 } 251 if (accessAddr == JIntABusyAddr) { 252 data = pkt->getBE<uint64_t>(); 253 jIntBusy[cpuid].busy = bits(data,5,5); 254 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", cpuid, 255 jIntBusy[cpuid].busy); 256 return; 257 }; 258 259 panic("Write to unknown JBus offset 0x%x\n", accessAddr); 260} 261 262void 263Iob::receiveDeviceInterrupt(DeviceId devid) 264{ 265 assert(devid < NumDeviceIds); 266 if (intCtl[devid].mask) 267 return; 268 intCtl[devid].mask = true; 269 intCtl[devid].pend = true; 270 DPRINTF(Iob, "Receiving Device interrupt: %d for cpu %d vec %d\n", 271 devid, intMan[devid].cpu, intMan[devid].vector); 272 ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector); 273} 274 275 276void 277Iob::generateIpi(Type type, int cpu_id, int vector) 278{ 279 SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset(); 280 if (cpu_id >= sys->numContexts()) 281 return; 282 283 switch (type) { 284 case 0: // interrupt 285 DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n", 286 cpu_id, vector); 287 ic->post(cpu_id, SparcISA::IT_INT_VEC, vector); 288 break; 289 case 1: // reset 290 warn("Sending reset to CPU: %d\n", cpu_id); 291 if (vector != por->trapType()) 292 panic("Don't know how to set non-POR reset to cpu\n"); 293 por->invoke(sys->threadContexts[cpu_id]); 294 sys->threadContexts[cpu_id]->activate(); 295 break; 296 case 2: // idle -- this means stop executing and don't wake on interrupts 297 DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id); 298 sys->threadContexts[cpu_id]->halt(); 299 break; 300 case 3: // resume 301 DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id); 302 sys->threadContexts[cpu_id]->activate(); 303 break; 304 default: 305 panic("Invalid type to generate ipi\n"); 306 } 307} 308 309bool 310Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1) 311{ 312 // If we are already dealing with an interrupt for that cpu we can't deal 313 // with another one right now... come back later 314 if (jIntBusy[cpu_id].busy) 315 return false; 316 317 DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n", 318 source, cpu_id, jIntVec); 319 320 jIntBusy[cpu_id].busy = true; 321 jIntBusy[cpu_id].source = source; 322 jBusData0[cpu_id] = d0; 323 jBusData1[cpu_id] = d1; 324 325 ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec); 326 return true; 327} 328 329AddrRangeList 330Iob::getAddrRanges() const 331{ 332 AddrRangeList ranges; 333 ranges.push_back(RangeSize(iobManAddr, iobManSize)); 334 ranges.push_back(RangeSize(iobJBusAddr, iobJBusSize)); 335 return ranges; 336} 337 338 339void 340Iob::serialize(CheckpointOut &cp) const 341{ 342 343 SERIALIZE_SCALAR(jIntVec); 344 SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs); 345 SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs); 346 for (int x = 0; x < NumDeviceIds; x++) { 347 ScopedCheckpointSection sec(cp, csprintf("Int%d", x)); 348 paramOut(cp, "cpu", intMan[x].cpu); 349 paramOut(cp, "vector", intMan[x].vector); 350 paramOut(cp, "mask", intCtl[x].mask); 351 paramOut(cp, "pend", intCtl[x].pend); 352 }; 353 for (int x = 0; x < MaxNiagaraProcs; x++) { 354 ScopedCheckpointSection sec(cp, csprintf("jIntBusy%d", x)); 355 paramOut(cp, "busy", jIntBusy[x].busy); 356 paramOut(cp, "source", jIntBusy[x].source); 357 }; 358} 359 360void 361Iob::unserialize(CheckpointIn &cp) 362{ 363 UNSERIALIZE_SCALAR(jIntVec); 364 UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs); 365 UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs); 366 for (int x = 0; x < NumDeviceIds; x++) { 367 ScopedCheckpointSection sec(cp, csprintf("Int%d", x)); 368 paramIn(cp, "cpu", intMan[x].cpu); 369 paramIn(cp, "vector", intMan[x].vector); 370 paramIn(cp, "mask", intCtl[x].mask); 371 paramIn(cp, "pend", intCtl[x].pend); 372 }; 373 for (int x = 0; x < MaxNiagaraProcs; x++) { 374 ScopedCheckpointSection sec(cp, csprintf("jIntBusy%d", x)); 375 paramIn(cp, "busy", jIntBusy[x].busy); 376 paramIn(cp, "source", jIntBusy[x].source); 377 }; 378} 379 380Iob * 381IobParams::create() 382{ 383 return new Iob(this); 384} 385