tsunami_pchip.cc revision 2107
1/* 2 * Copyright (c) 2004-2005 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 29/** @file 30 * Tsunami PChip (pci) 31 */ 32 33#include <deque> 34#include <string> 35#include <vector> 36 37#include "base/trace.hh" 38#include "dev/tsunami_pchip.hh" 39#include "dev/tsunamireg.h" 40#include "dev/tsunami.hh" 41#include "mem/bus/bus.hh" 42#include "mem/bus/pio_interface.hh" 43#include "mem/bus/pio_interface_impl.hh" 44#include "mem/functional/memory_control.hh" 45#include "mem/functional/physical.hh" 46#include "sim/builder.hh" 47#include "sim/system.hh" 48 49using namespace std; 50//Should this be AlphaISA? 51using namespace TheISA; 52 53TsunamiPChip::TsunamiPChip(const string &name, Tsunami *t, Addr a, 54 MemoryController *mmu, HierParams *hier, 55 Bus *pio_bus, Tick pio_latency) 56 : PioDevice(name, t), addr(a), tsunami(t) 57{ 58 mmu->add_child(this, RangeSize(addr, size)); 59 60 for (int i = 0; i < 4; i++) { 61 wsba[i] = 0; 62 wsm[i] = 0; 63 tba[i] = 0; 64 } 65 66 if (pio_bus) { 67 pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, 68 &TsunamiPChip::cacheAccess); 69 pioInterface->addAddrRange(RangeSize(addr, size)); 70 pioLatency = pio_latency * pio_bus->clockRate; 71 } 72 73 74 // initialize pchip control register 75 pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36); 76 77 //Set back pointer in tsunami 78 tsunami->pchip = this; 79} 80 81Fault * 82TsunamiPChip::read(MemReqPtr &req, uint8_t *data) 83{ 84 DPRINTF(Tsunami, "read va=%#x size=%d\n", 85 req->vaddr, req->size); 86 87 Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; 88 89 switch (req->size) { 90 91 case sizeof(uint64_t): 92 switch(daddr) { 93 case TSDEV_PC_WSBA0: 94 *(uint64_t*)data = wsba[0]; 95 return NoFault; 96 case TSDEV_PC_WSBA1: 97 *(uint64_t*)data = wsba[1]; 98 return NoFault; 99 case TSDEV_PC_WSBA2: 100 *(uint64_t*)data = wsba[2]; 101 return NoFault; 102 case TSDEV_PC_WSBA3: 103 *(uint64_t*)data = wsba[3]; 104 return NoFault; 105 case TSDEV_PC_WSM0: 106 *(uint64_t*)data = wsm[0]; 107 return NoFault; 108 case TSDEV_PC_WSM1: 109 *(uint64_t*)data = wsm[1]; 110 return NoFault; 111 case TSDEV_PC_WSM2: 112 *(uint64_t*)data = wsm[2]; 113 return NoFault; 114 case TSDEV_PC_WSM3: 115 *(uint64_t*)data = wsm[3]; 116 return NoFault; 117 case TSDEV_PC_TBA0: 118 *(uint64_t*)data = tba[0]; 119 return NoFault; 120 case TSDEV_PC_TBA1: 121 *(uint64_t*)data = tba[1]; 122 return NoFault; 123 case TSDEV_PC_TBA2: 124 *(uint64_t*)data = tba[2]; 125 return NoFault; 126 case TSDEV_PC_TBA3: 127 *(uint64_t*)data = tba[3]; 128 return NoFault; 129 case TSDEV_PC_PCTL: 130 *(uint64_t*)data = pctl; 131 return NoFault; 132 case TSDEV_PC_PLAT: 133 panic("PC_PLAT not implemented\n"); 134 case TSDEV_PC_RES: 135 panic("PC_RES not implemented\n"); 136 case TSDEV_PC_PERROR: 137 *(uint64_t*)data = 0x00; 138 return NoFault; 139 case TSDEV_PC_PERRMASK: 140 *(uint64_t*)data = 0x00; 141 return NoFault; 142 case TSDEV_PC_PERRSET: 143 panic("PC_PERRSET not implemented\n"); 144 case TSDEV_PC_TLBIV: 145 panic("PC_TLBIV not implemented\n"); 146 case TSDEV_PC_TLBIA: 147 *(uint64_t*)data = 0x00; // shouldn't be readable, but linux 148 return NoFault; 149 case TSDEV_PC_PMONCTL: 150 panic("PC_PMONCTL not implemented\n"); 151 case TSDEV_PC_PMONCNT: 152 panic("PC_PMONCTN not implemented\n"); 153 default: 154 panic("Default in PChip Read reached reading 0x%x\n", daddr); 155 156 } // uint64_t 157 158 break; 159 case sizeof(uint32_t): 160 case sizeof(uint16_t): 161 case sizeof(uint8_t): 162 default: 163 panic("invalid access size(?) for tsunami register!\n\n"); 164 } 165 DPRINTFN("Tsunami PChip ERROR: read daddr=%#x size=%d\n", daddr, req->size); 166 167 return NoFault; 168} 169 170Fault * 171TsunamiPChip::write(MemReqPtr &req, const uint8_t *data) 172{ 173 DPRINTF(Tsunami, "write - va=%#x size=%d \n", 174 req->vaddr, req->size); 175 176 Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; 177 178 switch (req->size) { 179 180 case sizeof(uint64_t): 181 switch(daddr) { 182 case TSDEV_PC_WSBA0: 183 wsba[0] = *(uint64_t*)data; 184 return NoFault; 185 case TSDEV_PC_WSBA1: 186 wsba[1] = *(uint64_t*)data; 187 return NoFault; 188 case TSDEV_PC_WSBA2: 189 wsba[2] = *(uint64_t*)data; 190 return NoFault; 191 case TSDEV_PC_WSBA3: 192 wsba[3] = *(uint64_t*)data; 193 return NoFault; 194 case TSDEV_PC_WSM0: 195 wsm[0] = *(uint64_t*)data; 196 return NoFault; 197 case TSDEV_PC_WSM1: 198 wsm[1] = *(uint64_t*)data; 199 return NoFault; 200 case TSDEV_PC_WSM2: 201 wsm[2] = *(uint64_t*)data; 202 return NoFault; 203 case TSDEV_PC_WSM3: 204 wsm[3] = *(uint64_t*)data; 205 return NoFault; 206 case TSDEV_PC_TBA0: 207 tba[0] = *(uint64_t*)data; 208 return NoFault; 209 case TSDEV_PC_TBA1: 210 tba[1] = *(uint64_t*)data; 211 return NoFault; 212 case TSDEV_PC_TBA2: 213 tba[2] = *(uint64_t*)data; 214 return NoFault; 215 case TSDEV_PC_TBA3: 216 tba[3] = *(uint64_t*)data; 217 return NoFault; 218 case TSDEV_PC_PCTL: 219 pctl = *(uint64_t*)data; 220 return NoFault; 221 case TSDEV_PC_PLAT: 222 panic("PC_PLAT not implemented\n"); 223 case TSDEV_PC_RES: 224 panic("PC_RES not implemented\n"); 225 case TSDEV_PC_PERROR: 226 return NoFault; 227 case TSDEV_PC_PERRMASK: 228 panic("PC_PERRMASK not implemented\n"); 229 case TSDEV_PC_PERRSET: 230 panic("PC_PERRSET not implemented\n"); 231 case TSDEV_PC_TLBIV: 232 panic("PC_TLBIV not implemented\n"); 233 case TSDEV_PC_TLBIA: 234 return NoFault; // value ignored, supposted to invalidate SG TLB 235 case TSDEV_PC_PMONCTL: 236 panic("PC_PMONCTL not implemented\n"); 237 case TSDEV_PC_PMONCNT: 238 panic("PC_PMONCTN not implemented\n"); 239 default: 240 panic("Default in PChip Read reached reading 0x%x\n", daddr); 241 242 } // uint64_t 243 244 break; 245 case sizeof(uint32_t): 246 case sizeof(uint16_t): 247 case sizeof(uint8_t): 248 default: 249 panic("invalid access size(?) for tsunami register!\n\n"); 250 } 251 252 DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size); 253 254 return NoFault; 255} 256 257#define DMA_ADDR_MASK ULL(0x3ffffffff) 258 259Addr 260TsunamiPChip::translatePciToDma(Addr busAddr) 261{ 262 // compare the address to the window base registers 263 uint64_t tbaMask = 0; 264 uint64_t baMask = 0; 265 266 uint64_t windowMask = 0; 267 uint64_t windowBase = 0; 268 269 uint64_t pteEntry = 0; 270 271 Addr pteAddr; 272 Addr dmaAddr; 273 274#if 0 275 DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr); 276 for (int i = 0; i < 4; i++) { 277 DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n", 278 i, wsba[i], wsm[i]); 279 280 windowBase = wsba[i]; 281 windowMask = ~wsm[i] & (ULL(0xfff) << 20); 282 283 if ((busAddr & windowMask) == (windowBase & windowMask)) { 284 DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n", 285 i, windowBase, windowMask, (busAddr & windowMask), 286 (windowBase & windowMask)); 287 } 288 } 289#endif 290 291 for (int i = 0; i < 4; i++) { 292 293 windowBase = wsba[i]; 294 windowMask = ~wsm[i] & (ULL(0xfff) << 20); 295 296 if ((busAddr & windowMask) == (windowBase & windowMask)) { 297 298 if (wsba[i] & 0x1) { // see if enabled 299 if (wsba[i] & 0x2) { // see if SG bit is set 300 /** @todo 301 This currently is faked by just doing a direct 302 read from memory, however, to be realistic, this 303 needs to actually do a bus transaction. The process 304 is explained in the tsunami documentation on page 305 10-12 and basically munges the address to look up a 306 PTE from a table in memory and then uses that mapping 307 to create an address for the SG page 308 */ 309 310 tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff)); 311 baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13); 312 pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10); 313 314 memcpy((void *)&pteEntry, 315 tsunami->system-> 316 physmem->dma_addr(pteAddr, sizeof(uint64_t)), 317 sizeof(uint64_t)); 318 319 dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff)); 320 321 } else { 322 baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff); 323 tbaMask = ~baMask; 324 dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask); 325 } 326 327 return (dmaAddr & DMA_ADDR_MASK); 328 } 329 } 330 } 331 332 // if no match was found, then return the original address 333 return busAddr; 334} 335 336void 337TsunamiPChip::serialize(std::ostream &os) 338{ 339 SERIALIZE_SCALAR(pctl); 340 SERIALIZE_ARRAY(wsba, 4); 341 SERIALIZE_ARRAY(wsm, 4); 342 SERIALIZE_ARRAY(tba, 4); 343} 344 345void 346TsunamiPChip::unserialize(Checkpoint *cp, const std::string §ion) 347{ 348 UNSERIALIZE_SCALAR(pctl); 349 UNSERIALIZE_ARRAY(wsba, 4); 350 UNSERIALIZE_ARRAY(wsm, 4); 351 UNSERIALIZE_ARRAY(tba, 4); 352} 353 354Tick 355TsunamiPChip::cacheAccess(MemReqPtr &req) 356{ 357 return curTick + pioLatency; 358} 359 360BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip) 361 362 SimObjectParam<Tsunami *> tsunami; 363 SimObjectParam<MemoryController *> mmu; 364 Param<Addr> addr; 365 SimObjectParam<Bus*> pio_bus; 366 Param<Tick> pio_latency; 367 SimObjectParam<HierParams *> hier; 368 369END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip) 370 371BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiPChip) 372 373 INIT_PARAM(tsunami, "Tsunami"), 374 INIT_PARAM(mmu, "Memory Controller"), 375 INIT_PARAM(addr, "Device Address"), 376 INIT_PARAM_DFLT(pio_bus, "The IO Bus to attach to", NULL), 377 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 378 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) 379 380END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip) 381 382CREATE_SIM_OBJECT(TsunamiPChip) 383{ 384 return new TsunamiPChip(getInstanceName(), tsunami, addr, mmu, hier, 385 pio_bus, pio_latency); 386} 387 388REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip) 389