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