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 <cstring> 39 40#include "arch/sparc/isa_traits.hh" 41#include "arch/sparc/faults.hh" 42#include "base/trace.hh" 43#include "cpu/intr_control.hh" 44#include "dev/sparc/iob.hh" 45#include "dev/platform.hh" 46#include "mem/port.hh" 47#include "mem/packet_access.hh" 48#include "sim/faults.hh" 49#include "sim/system.hh" 50 51Iob::Iob(const Params *p) 52 : PioDevice(p), ic(p->platform->intrctrl) 53{ 54 iobManAddr = ULL(0x9800000000); 55 iobManSize = ULL(0x0100000000); 56 iobJBusAddr = ULL(0x9F00000000); 57 iobJBusSize = ULL(0x0100000000); 58 assert (params()->system->threadContexts.size() <= MaxNiagaraProcs); 59 60 pioDelay = p->pio_latency; 61 62 // Get the interrupt controller from the platform 63 ic = platform->intrctrl; 64 65 for (int x = 0; x < NumDeviceIds; ++x) { 66 intMan[x].cpu = 0; 67 intMan[x].vector = 0; 68 intCtl[x].mask = true; 69 intCtl[x].pend = false; 70 } 71 72} 73 74Tick 75Iob::read(PacketPtr pkt) 76{ 77 78 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize) 79 readIob(pkt); 80 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize) 81 readJBus(pkt); 82 else 83 panic("Invalid address reached Iob\n"); 84 85 pkt->makeAtomicResponse(); 86 return pioDelay; 87} 88 89void 90Iob::readIob(PacketPtr pkt) 91{ 92 Addr accessAddr = pkt->getAddr() - iobManAddr;
| 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 <cstring> 39 40#include "arch/sparc/isa_traits.hh" 41#include "arch/sparc/faults.hh" 42#include "base/trace.hh" 43#include "cpu/intr_control.hh" 44#include "dev/sparc/iob.hh" 45#include "dev/platform.hh" 46#include "mem/port.hh" 47#include "mem/packet_access.hh" 48#include "sim/faults.hh" 49#include "sim/system.hh" 50 51Iob::Iob(const Params *p) 52 : PioDevice(p), ic(p->platform->intrctrl) 53{ 54 iobManAddr = ULL(0x9800000000); 55 iobManSize = ULL(0x0100000000); 56 iobJBusAddr = ULL(0x9F00000000); 57 iobJBusSize = ULL(0x0100000000); 58 assert (params()->system->threadContexts.size() <= MaxNiagaraProcs); 59 60 pioDelay = p->pio_latency; 61 62 // Get the interrupt controller from the platform 63 ic = platform->intrctrl; 64 65 for (int x = 0; x < NumDeviceIds; ++x) { 66 intMan[x].cpu = 0; 67 intMan[x].vector = 0; 68 intCtl[x].mask = true; 69 intCtl[x].pend = false; 70 } 71 72} 73 74Tick 75Iob::read(PacketPtr pkt) 76{ 77 78 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize) 79 readIob(pkt); 80 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize) 81 readJBus(pkt); 82 else 83 panic("Invalid address reached Iob\n"); 84 85 pkt->makeAtomicResponse(); 86 return pioDelay; 87} 88 89void 90Iob::readIob(PacketPtr pkt) 91{ 92 Addr accessAddr = pkt->getAddr() - iobManAddr;
|
203 data = pkt->get<uint64_t>(); 204 intCtl[index].mask = bits(data,2,2); 205 if (bits(data,1,1)) 206 intCtl[index].pend = false; 207 DPRINTF(Iob, "Wrote IntCtl %d pend %d cleared %d\n", index, 208 intCtl[index].pend, bits(data,2,2)); 209 return; 210 } 211 212 if (accessAddr == JIntVecAddr) { 213 jIntVec = bits(pkt->get<uint64_t>(), 5,0); 214 DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec); 215 return; 216 } 217 218 if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) { 219 Type type; 220 int cpu_id; 221 int vector; 222 index = (accessAddr - IntManAddr) >> 3; 223 data = pkt->get<uint64_t>(); 224 type = (Type)bits(data,17,16); 225 cpu_id = bits(data, 12,8); 226 vector = bits(data,5,0); 227 generateIpi(type,cpu_id, vector); 228 return; 229 } 230 231 panic("Write to unknown IOB offset 0x%x\n", accessAddr); 232} 233 234void 235Iob::writeJBus(PacketPtr pkt) 236{ 237 Addr accessAddr = pkt->getAddr() - iobJBusAddr; 238 int cpuid = pkt->req->contextId(); 239 int index; 240 uint64_t data; 241 242 if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) { 243 index = (accessAddr - JIntBusyAddr) >> 3; 244 data = pkt->get<uint64_t>(); 245 jIntBusy[index].busy = bits(data,5,5); 246 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", index, 247 jIntBusy[index].busy); 248 return; 249 } 250 if (accessAddr == JIntABusyAddr) { 251 data = pkt->get<uint64_t>(); 252 jIntBusy[cpuid].busy = bits(data,5,5); 253 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", cpuid, 254 jIntBusy[cpuid].busy); 255 return; 256 }; 257 258 panic("Write to unknown JBus offset 0x%x\n", accessAddr); 259} 260 261void 262Iob::receiveDeviceInterrupt(DeviceId devid) 263{ 264 assert(devid < NumDeviceIds); 265 if (intCtl[devid].mask) 266 return; 267 intCtl[devid].mask = true; 268 intCtl[devid].pend = true; 269 DPRINTF(Iob, "Receiving Device interrupt: %d for cpu %d vec %d\n", 270 devid, intMan[devid].cpu, intMan[devid].vector); 271 ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector); 272} 273 274 275void 276Iob::generateIpi(Type type, int cpu_id, int vector) 277{ 278 SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset(); 279 if (cpu_id >= sys->numContexts()) 280 return; 281 282 switch (type) { 283 case 0: // interrupt 284 DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n", 285 cpu_id, vector); 286 ic->post(cpu_id, SparcISA::IT_INT_VEC, vector); 287 break; 288 case 1: // reset 289 warn("Sending reset to CPU: %d\n", cpu_id); 290 if (vector != por->trapType()) 291 panic("Don't know how to set non-POR reset to cpu\n"); 292 por->invoke(sys->threadContexts[cpu_id]); 293 sys->threadContexts[cpu_id]->activate(); 294 break; 295 case 2: // idle -- this means stop executing and don't wake on interrupts 296 DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id); 297 sys->threadContexts[cpu_id]->halt(); 298 break; 299 case 3: // resume 300 DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id); 301 sys->threadContexts[cpu_id]->activate(); 302 break; 303 default: 304 panic("Invalid type to generate ipi\n"); 305 } 306} 307 308bool 309Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1) 310{ 311 // If we are already dealing with an interrupt for that cpu we can't deal 312 // with another one right now... come back later 313 if (jIntBusy[cpu_id].busy) 314 return false; 315 316 DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n", 317 source, cpu_id, jIntVec); 318 319 jIntBusy[cpu_id].busy = true; 320 jIntBusy[cpu_id].source = source; 321 jBusData0[cpu_id] = d0; 322 jBusData1[cpu_id] = d1; 323 324 ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec); 325 return true; 326} 327 328void 329Iob::addressRanges(AddrRangeList &range_list) 330{ 331 range_list.clear(); 332 range_list.push_back(RangeSize(iobManAddr, iobManSize)); 333 range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize)); 334} 335 336 337void 338Iob::serialize(std::ostream &os) 339{ 340 341 SERIALIZE_SCALAR(jIntVec); 342 SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs); 343 SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs); 344 for (int x = 0; x < NumDeviceIds; x++) { 345 nameOut(os, csprintf("%s.Int%d", name(), x)); 346 paramOut(os, "cpu", intMan[x].cpu); 347 paramOut(os, "vector", intMan[x].vector); 348 paramOut(os, "mask", intCtl[x].mask); 349 paramOut(os, "pend", intCtl[x].pend); 350 }; 351 for (int x = 0; x < MaxNiagaraProcs; x++) { 352 nameOut(os, csprintf("%s.jIntBusy%d", name(), x)); 353 paramOut(os, "busy", jIntBusy[x].busy); 354 paramOut(os, "source", jIntBusy[x].source); 355 }; 356} 357 358void 359Iob::unserialize(Checkpoint *cp, const std::string §ion) 360{ 361 UNSERIALIZE_SCALAR(jIntVec); 362 UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs); 363 UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs); 364 for (int x = 0; x < NumDeviceIds; x++) { 365 paramIn(cp, csprintf("%s.Int%d", name(), x), "cpu", intMan[x].cpu); 366 paramIn(cp, csprintf("%s.Int%d", name(), x), "vector", intMan[x].vector); 367 paramIn(cp, csprintf("%s.Int%d", name(), x), "mask", intCtl[x].mask); 368 paramIn(cp, csprintf("%s.Int%d", name(), x), "pend", intCtl[x].pend); 369 }; 370 for (int x = 0; x < MaxNiagaraProcs; x++) { 371 paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "busy", jIntBusy[x].busy); 372 paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "source", jIntBusy[x].source); 373 }; 374} 375 376Iob * 377IobParams::create() 378{ 379 return new Iob(this); 380}
| 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->contextId(); 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->numContexts()) 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 §ion) 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 374Iob * 375IobParams::create() 376{ 377 return new Iob(this); 378}
|