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