device.cc revision 3083
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 * Authors: Ali Saidi 29 * Andrew Schultz 30 * Miguel Serrano 31 */ 32 33/* @file 34 * A single PCI device configuration space entry. 35 */ 36 37#include <list> 38#include <string> 39#include <vector> 40 41#include "base/inifile.hh" 42#include "base/misc.hh" 43#include "base/str.hh" // for to_number 44#include "base/trace.hh" 45#include "dev/pciconfigall.hh" 46#include "dev/pcidev.hh" 47#include "dev/tsunamireg.h" 48#include "mem/packet.hh" 49#include "sim/builder.hh" 50#include "sim/byteswap.hh" 51#include "sim/param.hh" 52#include "sim/root.hh" 53 54using namespace std; 55 56 57PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid, 58 int funcid, Platform *p) 59 : PioPort(dev,p->system,"-pciconf"), device(dev), platform(p), 60 busId(busid), deviceId(devid), functionId(funcid) 61{ 62 configAddr = platform->calcConfigAddr(busId, deviceId, functionId); 63} 64 65 66Tick 67PciDev::PciConfigPort::recvAtomic(Packet *pkt) 68{ 69 assert(pkt->result == Packet::Unknown); 70 assert(pkt->getAddr() >= configAddr && pkt->getAddr() < configAddr + 71 PCI_CONFIG_SIZE); 72 return device->recvConfig(pkt); 73} 74 75void 76PciDev::PciConfigPort::recvFunctional(Packet *pkt) 77{ 78 assert(pkt->result == Packet::Unknown); 79 assert(pkt->getAddr() >= configAddr && pkt->getAddr() < configAddr + 80 PCI_CONFIG_SIZE); 81 device->recvConfig(pkt); 82} 83 84void 85PciDev::PciConfigPort::getDeviceAddressRanges(AddrRangeList &resp, 86 AddrRangeList &snoop) 87{ 88 snoop.clear(); 89 resp.push_back(RangeSize(configAddr, PCI_CONFIG_SIZE+1)); 90} 91 92 93bool 94PciDev::PciConfigPort::recvTiming(Packet *pkt) 95{ 96 if (pkt->result == Packet::Nacked) { 97 resendNacked(pkt); 98 } else { 99 assert(pkt->result == Packet::Unknown); 100 assert(pkt->getAddr() >= configAddr && pkt->getAddr() < configAddr + 101 PCI_CONFIG_SIZE); 102 Tick latency = device->recvConfig(pkt); 103 // turn packet around to go back to requester 104 pkt->makeTimingResponse(); 105 sendTiming(pkt, latency); 106 } 107 return true; 108} 109 110PciDev::PciDev(Params *p) 111 : DmaDevice(p), plat(p->platform), configData(p->configData), 112 pioDelay(p->pio_delay), configDelay(p->config_delay), 113 configPort(NULL) 114{ 115 // copy the config data from the PciConfigData object 116 if (configData) { 117 memcpy(config.data, configData->config.data, sizeof(config.data)); 118 memcpy(BARSize, configData->BARSize, sizeof(BARSize)); 119 memcpy(BARAddrs, configData->BARAddrs, sizeof(BARAddrs)); 120 } else 121 panic("NULL pointer to configuration data"); 122 123 plat->registerPciDevice(0, p->deviceNum, p->functionNum, 124 letoh(configData->config.interruptLine)); 125} 126 127void 128PciDev::init() 129{ 130 if (!configPort) 131 panic("pci config port not connected to anything!"); 132 configPort->sendStatusChange(Port::RangeChange); 133 PioDevice::init(); 134} 135 136unsigned int 137PciDev::drain(Event *de) 138{ 139 unsigned int count; 140 count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de); 141 if (count) 142 changeState(Draining); 143 else 144 changeState(Drained); 145 return count; 146} 147 148Tick 149PciDev::readConfig(Packet *pkt) 150{ 151 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 152 if (offset >= PCI_DEVICE_SPECIFIC) 153 panic("Device specific PCI config space not implemented!\n"); 154 155 pkt->allocate(); 156 157 switch (pkt->getSize()) { 158 case sizeof(uint8_t): 159 pkt->set<uint8_t>(config.data[offset]); 160 DPRINTF(PCIDEV, 161 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 162 params()->deviceNum, params()->functionNum, offset, 163 (uint32_t)pkt->get<uint8_t>()); 164 break; 165 case sizeof(uint16_t): 166 pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]); 167 DPRINTF(PCIDEV, 168 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 169 params()->deviceNum, params()->functionNum, offset, 170 (uint32_t)pkt->get<uint16_t>()); 171 break; 172 case sizeof(uint32_t): 173 pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]); 174 DPRINTF(PCIDEV, 175 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 176 params()->deviceNum, params()->functionNum, offset, 177 (uint32_t)pkt->get<uint32_t>()); 178 break; 179 default: 180 panic("invalid access size(?) for PCI configspace!\n"); 181 } 182 pkt->result = Packet::Success; 183 return configDelay; 184 185} 186 187void 188PciDev::addressRanges(AddrRangeList &range_list) 189{ 190 int x = 0; 191 range_list.clear(); 192 for (x = 0; x < 6; x++) 193 if (BARAddrs[x] != 0) 194 range_list.push_back(RangeSize(BARAddrs[x],BARSize[x])); 195} 196 197Tick 198PciDev::writeConfig(Packet *pkt) 199{ 200 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 201 if (offset >= PCI_DEVICE_SPECIFIC) 202 panic("Device specific PCI config space not implemented!\n"); 203 204 switch (pkt->getSize()) { 205 case sizeof(uint8_t): 206 switch (offset) { 207 case PCI0_INTERRUPT_LINE: 208 config.interruptLine = pkt->get<uint8_t>(); 209 case PCI_CACHE_LINE_SIZE: 210 config.cacheLineSize = pkt->get<uint8_t>(); 211 case PCI_LATENCY_TIMER: 212 config.latencyTimer = pkt->get<uint8_t>(); 213 break; 214 /* Do nothing for these read-only registers */ 215 case PCI0_INTERRUPT_PIN: 216 case PCI0_MINIMUM_GRANT: 217 case PCI0_MAXIMUM_LATENCY: 218 case PCI_CLASS_CODE: 219 case PCI_REVISION_ID: 220 break; 221 default: 222 panic("writing to a read only register"); 223 } 224 DPRINTF(PCIDEV, 225 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 226 params()->deviceNum, params()->functionNum, offset, 227 (uint32_t)pkt->get<uint8_t>()); 228 break; 229 case sizeof(uint16_t): 230 switch (offset) { 231 case PCI_COMMAND: 232 config.command = pkt->get<uint8_t>(); 233 case PCI_STATUS: 234 config.status = pkt->get<uint8_t>(); 235 case PCI_CACHE_LINE_SIZE: 236 config.cacheLineSize = pkt->get<uint8_t>(); 237 break; 238 default: 239 panic("writing to a read only register"); 240 } 241 DPRINTF(PCIDEV, 242 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 243 params()->deviceNum, params()->functionNum, offset, 244 (uint32_t)pkt->get<uint16_t>()); 245 break; 246 case sizeof(uint32_t): 247 switch (offset) { 248 case PCI0_BASE_ADDR0: 249 case PCI0_BASE_ADDR1: 250 case PCI0_BASE_ADDR2: 251 case PCI0_BASE_ADDR3: 252 case PCI0_BASE_ADDR4: 253 case PCI0_BASE_ADDR5: 254 255 uint32_t barnum, bar_mask; 256 Addr base_addr, base_size, space_base; 257 258 barnum = BAR_NUMBER(offset); 259 260 if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) { 261 bar_mask = BAR_IO_MASK; 262 space_base = TSUNAMI_PCI0_IO; 263 } else { 264 bar_mask = BAR_MEM_MASK; 265 space_base = TSUNAMI_PCI0_MEMORY; 266 } 267 268 // Writing 0xffffffff to a BAR tells the card to set the 269 // value of the bar to size of memory it needs 270 if (letoh(pkt->get<uint32_t>()) == 0xffffffff) { 271 // This is I/O Space, bottom two bits are read only 272 273 config.baseAddr[barnum] = letoh( 274 (~(BARSize[barnum] - 1) & ~bar_mask) | 275 (letoh(config.baseAddr[barnum]) & bar_mask)); 276 } else { 277 config.baseAddr[barnum] = letoh( 278 (letoh(pkt->get<uint32_t>()) & ~bar_mask) | 279 (letoh(config.baseAddr[barnum]) & bar_mask)); 280 281 if (letoh(config.baseAddr[barnum]) & ~bar_mask) { 282 base_addr = (letoh(pkt->get<uint32_t>()) & ~bar_mask) + space_base; 283 base_size = BARSize[barnum]; 284 BARAddrs[barnum] = base_addr; 285 286 pioPort->sendStatusChange(Port::RangeChange); 287 } 288 } 289 break; 290 291 case PCI0_ROM_BASE_ADDR: 292 if (letoh(pkt->get<uint32_t>()) == 0xfffffffe) 293 config.expansionROM = htole((uint32_t)0xffffffff); 294 else 295 config.expansionROM = pkt->get<uint32_t>(); 296 break; 297 298 case PCI_COMMAND: 299 // This could also clear some of the error bits in the Status 300 // register. However they should never get set, so lets ignore 301 // it for now 302 config.command = pkt->get<uint32_t>(); 303 break; 304 305 default: 306 DPRINTF(PCIDEV, "Writing to a read only register"); 307 } 308 DPRINTF(PCIDEV, 309 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 310 params()->deviceNum, params()->functionNum, offset, 311 (uint32_t)pkt->get<uint32_t>()); 312 break; 313 default: 314 panic("invalid access size(?) for PCI configspace!\n"); 315 } 316 pkt->result = Packet::Success; 317 return configDelay; 318 319} 320 321void 322PciDev::serialize(ostream &os) 323{ 324 SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 325 SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 326 SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); 327} 328 329void 330PciDev::unserialize(Checkpoint *cp, const std::string §ion) 331{ 332 UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 333 UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 334 UNSERIALIZE_ARRAY(config.data, 335 sizeof(config.data) / sizeof(config.data[0])); 336} 337 338#ifndef DOXYGEN_SHOULD_SKIP_THIS 339 340BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) 341 342 Param<uint16_t> VendorID; 343 Param<uint16_t> DeviceID; 344 Param<uint16_t> Command; 345 Param<uint16_t> Status; 346 Param<uint8_t> Revision; 347 Param<uint8_t> ProgIF; 348 Param<uint8_t> SubClassCode; 349 Param<uint8_t> ClassCode; 350 Param<uint8_t> CacheLineSize; 351 Param<uint8_t> LatencyTimer; 352 Param<uint8_t> HeaderType; 353 Param<uint8_t> BIST; 354 Param<uint32_t> BAR0; 355 Param<uint32_t> BAR1; 356 Param<uint32_t> BAR2; 357 Param<uint32_t> BAR3; 358 Param<uint32_t> BAR4; 359 Param<uint32_t> BAR5; 360 Param<uint32_t> CardbusCIS; 361 Param<uint16_t> SubsystemVendorID; 362 Param<uint16_t> SubsystemID; 363 Param<uint32_t> ExpansionROM; 364 Param<uint8_t> InterruptLine; 365 Param<uint8_t> InterruptPin; 366 Param<uint8_t> MinimumGrant; 367 Param<uint8_t> MaximumLatency; 368 Param<uint32_t> BAR0Size; 369 Param<uint32_t> BAR1Size; 370 Param<uint32_t> BAR2Size; 371 Param<uint32_t> BAR3Size; 372 Param<uint32_t> BAR4Size; 373 Param<uint32_t> BAR5Size; 374 375END_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) 376 377BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigData) 378 379 INIT_PARAM(VendorID, "Vendor ID"), 380 INIT_PARAM(DeviceID, "Device ID"), 381 INIT_PARAM_DFLT(Command, "Command Register", 0x00), 382 INIT_PARAM_DFLT(Status, "Status Register", 0x00), 383 INIT_PARAM_DFLT(Revision, "Device Revision", 0x00), 384 INIT_PARAM_DFLT(ProgIF, "Programming Interface", 0x00), 385 INIT_PARAM(SubClassCode, "Sub-Class Code"), 386 INIT_PARAM(ClassCode, "Class Code"), 387 INIT_PARAM_DFLT(CacheLineSize, "System Cacheline Size", 0x00), 388 INIT_PARAM_DFLT(LatencyTimer, "PCI Latency Timer", 0x00), 389 INIT_PARAM_DFLT(HeaderType, "PCI Header Type", 0x00), 390 INIT_PARAM_DFLT(BIST, "Built In Self Test", 0x00), 391 INIT_PARAM_DFLT(BAR0, "Base Address Register 0", 0x00), 392 INIT_PARAM_DFLT(BAR1, "Base Address Register 1", 0x00), 393 INIT_PARAM_DFLT(BAR2, "Base Address Register 2", 0x00), 394 INIT_PARAM_DFLT(BAR3, "Base Address Register 3", 0x00), 395 INIT_PARAM_DFLT(BAR4, "Base Address Register 4", 0x00), 396 INIT_PARAM_DFLT(BAR5, "Base Address Register 5", 0x00), 397 INIT_PARAM_DFLT(CardbusCIS, "Cardbus Card Information Structure", 0x00), 398 INIT_PARAM_DFLT(SubsystemVendorID, "Subsystem Vendor ID", 0x00), 399 INIT_PARAM_DFLT(SubsystemID, "Subsystem ID", 0x00), 400 INIT_PARAM_DFLT(ExpansionROM, "Expansion ROM Base Address Register", 0x00), 401 INIT_PARAM(InterruptLine, "Interrupt Line Register"), 402 INIT_PARAM(InterruptPin, "Interrupt Pin Register"), 403 INIT_PARAM_DFLT(MinimumGrant, "Minimum Grant", 0x00), 404 INIT_PARAM_DFLT(MaximumLatency, "Maximum Latency", 0x00), 405 INIT_PARAM_DFLT(BAR0Size, "Base Address Register 0 Size", 0x00), 406 INIT_PARAM_DFLT(BAR1Size, "Base Address Register 1 Size", 0x00), 407 INIT_PARAM_DFLT(BAR2Size, "Base Address Register 2 Size", 0x00), 408 INIT_PARAM_DFLT(BAR3Size, "Base Address Register 3 Size", 0x00), 409 INIT_PARAM_DFLT(BAR4Size, "Base Address Register 4 Size", 0x00), 410 INIT_PARAM_DFLT(BAR5Size, "Base Address Register 5 Size", 0x00) 411 412END_INIT_SIM_OBJECT_PARAMS(PciConfigData) 413 414CREATE_SIM_OBJECT(PciConfigData) 415{ 416 PciConfigData *data = new PciConfigData(getInstanceName()); 417 418 data->config.vendor = htole(VendorID); 419 data->config.device = htole(DeviceID); 420 data->config.command = htole(Command); 421 data->config.status = htole(Status); 422 data->config.revision = htole(Revision); 423 data->config.progIF = htole(ProgIF); 424 data->config.subClassCode = htole(SubClassCode); 425 data->config.classCode = htole(ClassCode); 426 data->config.cacheLineSize = htole(CacheLineSize); 427 data->config.latencyTimer = htole(LatencyTimer); 428 data->config.headerType = htole(HeaderType); 429 data->config.bist = htole(BIST); 430 431 data->config.baseAddr0 = htole(BAR0); 432 data->config.baseAddr1 = htole(BAR1); 433 data->config.baseAddr2 = htole(BAR2); 434 data->config.baseAddr3 = htole(BAR3); 435 data->config.baseAddr4 = htole(BAR4); 436 data->config.baseAddr5 = htole(BAR5); 437 data->config.cardbusCIS = htole(CardbusCIS); 438 data->config.subsystemVendorID = htole(SubsystemVendorID); 439 data->config.subsystemID = htole(SubsystemVendorID); 440 data->config.expansionROM = htole(ExpansionROM); 441 data->config.interruptLine = htole(InterruptLine); 442 data->config.interruptPin = htole(InterruptPin); 443 data->config.minimumGrant = htole(MinimumGrant); 444 data->config.maximumLatency = htole(MaximumLatency); 445 446 data->BARSize[0] = BAR0Size; 447 data->BARSize[1] = BAR1Size; 448 data->BARSize[2] = BAR2Size; 449 data->BARSize[3] = BAR3Size; 450 data->BARSize[4] = BAR4Size; 451 data->BARSize[5] = BAR5Size; 452 453 return data; 454} 455 456REGISTER_SIM_OBJECT("PciConfigData", PciConfigData) 457 458#endif // DOXYGEN_SHOULD_SKIP_THIS 459