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