device.cc revision 3086
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 } else 120 panic("NULL pointer to configuration data"); 121 122 memset(BARAddrs, 0, sizeof(BARAddrs)); 123 124 plat->registerPciDevice(0, p->deviceNum, p->functionNum, 125 letoh(configData->config.interruptLine)); 126} 127 128void 129PciDev::init() 130{ 131 if (!configPort) 132 panic("pci config port not connected to anything!"); 133 configPort->sendStatusChange(Port::RangeChange); 134 PioDevice::init(); 135} 136 137unsigned int 138PciDev::drain(Event *de) 139{ 140 unsigned int count; 141 count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de); 142 if (count) 143 changeState(Draining); 144 else 145 changeState(Drained); 146 return count; 147} 148 149Tick 150PciDev::readConfig(Packet *pkt) 151{ 152 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 153 if (offset >= PCI_DEVICE_SPECIFIC) 154 panic("Device specific PCI config space not implemented!\n"); 155 156 pkt->allocate(); 157 158 switch (pkt->getSize()) { 159 case sizeof(uint8_t): 160 pkt->set<uint8_t>(config.data[offset]); 161 DPRINTF(PCIDEV, 162 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 163 params()->deviceNum, params()->functionNum, offset, 164 (uint32_t)pkt->get<uint8_t>()); 165 break; 166 case sizeof(uint16_t): 167 pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]); 168 DPRINTF(PCIDEV, 169 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 170 params()->deviceNum, params()->functionNum, offset, 171 (uint32_t)pkt->get<uint16_t>()); 172 break; 173 case sizeof(uint32_t): 174 pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]); 175 DPRINTF(PCIDEV, 176 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 177 params()->deviceNum, params()->functionNum, offset, 178 (uint32_t)pkt->get<uint32_t>()); 179 break; 180 default: 181 panic("invalid access size(?) for PCI configspace!\n"); 182 } 183 pkt->result = Packet::Success; 184 return configDelay; 185 186} 187 188void 189PciDev::addressRanges(AddrRangeList &range_list) 190{ 191 int x = 0; 192 range_list.clear(); 193 for (x = 0; x < 6; x++) 194 if (BARAddrs[x] != 0) 195 range_list.push_back(RangeSize(BARAddrs[x],BARSize[x])); 196} 197 198Tick 199PciDev::writeConfig(Packet *pkt) 200{ 201 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 202 if (offset >= PCI_DEVICE_SPECIFIC) 203 panic("Device specific PCI config space not implemented!\n"); 204 205 switch (pkt->getSize()) { 206 case sizeof(uint8_t): 207 switch (offset) { 208 case PCI0_INTERRUPT_LINE: 209 config.interruptLine = pkt->get<uint8_t>(); 210 case PCI_CACHE_LINE_SIZE: 211 config.cacheLineSize = pkt->get<uint8_t>(); 212 case PCI_LATENCY_TIMER: 213 config.latencyTimer = pkt->get<uint8_t>(); 214 break; 215 /* Do nothing for these read-only registers */ 216 case PCI0_INTERRUPT_PIN: 217 case PCI0_MINIMUM_GRANT: 218 case PCI0_MAXIMUM_LATENCY: 219 case PCI_CLASS_CODE: 220 case PCI_REVISION_ID: 221 break; 222 default: 223 panic("writing to a read only register"); 224 } 225 DPRINTF(PCIDEV, 226 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 227 params()->deviceNum, params()->functionNum, offset, 228 (uint32_t)pkt->get<uint8_t>()); 229 break; 230 case sizeof(uint16_t): 231 switch (offset) { 232 case PCI_COMMAND: 233 config.command = pkt->get<uint8_t>(); 234 case PCI_STATUS: 235 config.status = pkt->get<uint8_t>(); 236 case PCI_CACHE_LINE_SIZE: 237 config.cacheLineSize = pkt->get<uint8_t>(); 238 break; 239 default: 240 panic("writing to a read only register"); 241 } 242 DPRINTF(PCIDEV, 243 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 244 params()->deviceNum, params()->functionNum, offset, 245 (uint32_t)pkt->get<uint16_t>()); 246 break; 247 case sizeof(uint32_t): 248 switch (offset) { 249 case PCI0_BASE_ADDR0: 250 case PCI0_BASE_ADDR1: 251 case PCI0_BASE_ADDR2: 252 case PCI0_BASE_ADDR3: 253 case PCI0_BASE_ADDR4: 254 case PCI0_BASE_ADDR5: 255 { 256 int barnum = BAR_NUMBER(offset); 257 258 // convert BAR values to host endianness 259 uint32_t he_old_bar = letoh(config.baseAddr[barnum]); 260 uint32_t he_new_bar = letoh(pkt->get<uint32_t>()); 261 262 uint32_t bar_mask = 263 BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK; 264 265 // Writing 0xffffffff to a BAR tells the card to set the 266 // value of the bar to a bitmask indicating the size of 267 // memory it needs 268 if (he_new_bar == 0xffffffff) { 269 he_new_bar = ~(BARSize[barnum] - 1); 270 } else { 271 // does it mean something special to write 0 to a BAR? 272 he_new_bar &= ~bar_mask; 273 if (he_new_bar) { 274 Addr space_base = BAR_IO_SPACE(he_old_bar) ? 275 TSUNAMI_PCI0_IO : TSUNAMI_PCI0_MEMORY; 276 BARAddrs[barnum] = he_new_bar + space_base; 277 pioPort->sendStatusChange(Port::RangeChange); 278 } 279 } 280 config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) | 281 (he_old_bar & bar_mask)); 282 } 283 break; 284 285 case PCI0_ROM_BASE_ADDR: 286 if (letoh(pkt->get<uint32_t>()) == 0xfffffffe) 287 config.expansionROM = htole((uint32_t)0xffffffff); 288 else 289 config.expansionROM = pkt->get<uint32_t>(); 290 break; 291 292 case PCI_COMMAND: 293 // This could also clear some of the error bits in the Status 294 // register. However they should never get set, so lets ignore 295 // it for now 296 config.command = pkt->get<uint32_t>(); 297 break; 298 299 default: 300 DPRINTF(PCIDEV, "Writing to a read only register"); 301 } 302 DPRINTF(PCIDEV, 303 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 304 params()->deviceNum, params()->functionNum, offset, 305 (uint32_t)pkt->get<uint32_t>()); 306 break; 307 default: 308 panic("invalid access size(?) for PCI configspace!\n"); 309 } 310 pkt->result = Packet::Success; 311 return configDelay; 312 313} 314 315void 316PciDev::serialize(ostream &os) 317{ 318 SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 319 SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 320 SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); 321} 322 323void 324PciDev::unserialize(Checkpoint *cp, const std::string §ion) 325{ 326 UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 327 UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 328 UNSERIALIZE_ARRAY(config.data, 329 sizeof(config.data) / sizeof(config.data[0])); 330} 331 332#ifndef DOXYGEN_SHOULD_SKIP_THIS 333 334BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) 335 336 Param<uint16_t> VendorID; 337 Param<uint16_t> DeviceID; 338 Param<uint16_t> Command; 339 Param<uint16_t> Status; 340 Param<uint8_t> Revision; 341 Param<uint8_t> ProgIF; 342 Param<uint8_t> SubClassCode; 343 Param<uint8_t> ClassCode; 344 Param<uint8_t> CacheLineSize; 345 Param<uint8_t> LatencyTimer; 346 Param<uint8_t> HeaderType; 347 Param<uint8_t> BIST; 348 Param<uint32_t> BAR0; 349 Param<uint32_t> BAR1; 350 Param<uint32_t> BAR2; 351 Param<uint32_t> BAR3; 352 Param<uint32_t> BAR4; 353 Param<uint32_t> BAR5; 354 Param<uint32_t> CardbusCIS; 355 Param<uint16_t> SubsystemVendorID; 356 Param<uint16_t> SubsystemID; 357 Param<uint32_t> ExpansionROM; 358 Param<uint8_t> InterruptLine; 359 Param<uint8_t> InterruptPin; 360 Param<uint8_t> MinimumGrant; 361 Param<uint8_t> MaximumLatency; 362 Param<uint32_t> BAR0Size; 363 Param<uint32_t> BAR1Size; 364 Param<uint32_t> BAR2Size; 365 Param<uint32_t> BAR3Size; 366 Param<uint32_t> BAR4Size; 367 Param<uint32_t> BAR5Size; 368 369END_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) 370 371BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigData) 372 373 INIT_PARAM(VendorID, "Vendor ID"), 374 INIT_PARAM(DeviceID, "Device ID"), 375 INIT_PARAM_DFLT(Command, "Command Register", 0x00), 376 INIT_PARAM_DFLT(Status, "Status Register", 0x00), 377 INIT_PARAM_DFLT(Revision, "Device Revision", 0x00), 378 INIT_PARAM_DFLT(ProgIF, "Programming Interface", 0x00), 379 INIT_PARAM(SubClassCode, "Sub-Class Code"), 380 INIT_PARAM(ClassCode, "Class Code"), 381 INIT_PARAM_DFLT(CacheLineSize, "System Cacheline Size", 0x00), 382 INIT_PARAM_DFLT(LatencyTimer, "PCI Latency Timer", 0x00), 383 INIT_PARAM_DFLT(HeaderType, "PCI Header Type", 0x00), 384 INIT_PARAM_DFLT(BIST, "Built In Self Test", 0x00), 385 INIT_PARAM_DFLT(BAR0, "Base Address Register 0", 0x00), 386 INIT_PARAM_DFLT(BAR1, "Base Address Register 1", 0x00), 387 INIT_PARAM_DFLT(BAR2, "Base Address Register 2", 0x00), 388 INIT_PARAM_DFLT(BAR3, "Base Address Register 3", 0x00), 389 INIT_PARAM_DFLT(BAR4, "Base Address Register 4", 0x00), 390 INIT_PARAM_DFLT(BAR5, "Base Address Register 5", 0x00), 391 INIT_PARAM_DFLT(CardbusCIS, "Cardbus Card Information Structure", 0x00), 392 INIT_PARAM_DFLT(SubsystemVendorID, "Subsystem Vendor ID", 0x00), 393 INIT_PARAM_DFLT(SubsystemID, "Subsystem ID", 0x00), 394 INIT_PARAM_DFLT(ExpansionROM, "Expansion ROM Base Address Register", 0x00), 395 INIT_PARAM(InterruptLine, "Interrupt Line Register"), 396 INIT_PARAM(InterruptPin, "Interrupt Pin Register"), 397 INIT_PARAM_DFLT(MinimumGrant, "Minimum Grant", 0x00), 398 INIT_PARAM_DFLT(MaximumLatency, "Maximum Latency", 0x00), 399 INIT_PARAM_DFLT(BAR0Size, "Base Address Register 0 Size", 0x00), 400 INIT_PARAM_DFLT(BAR1Size, "Base Address Register 1 Size", 0x00), 401 INIT_PARAM_DFLT(BAR2Size, "Base Address Register 2 Size", 0x00), 402 INIT_PARAM_DFLT(BAR3Size, "Base Address Register 3 Size", 0x00), 403 INIT_PARAM_DFLT(BAR4Size, "Base Address Register 4 Size", 0x00), 404 INIT_PARAM_DFLT(BAR5Size, "Base Address Register 5 Size", 0x00) 405 406END_INIT_SIM_OBJECT_PARAMS(PciConfigData) 407 408CREATE_SIM_OBJECT(PciConfigData) 409{ 410 PciConfigData *data = new PciConfigData(getInstanceName()); 411 412 data->config.vendor = htole(VendorID); 413 data->config.device = htole(DeviceID); 414 data->config.command = htole(Command); 415 data->config.status = htole(Status); 416 data->config.revision = htole(Revision); 417 data->config.progIF = htole(ProgIF); 418 data->config.subClassCode = htole(SubClassCode); 419 data->config.classCode = htole(ClassCode); 420 data->config.cacheLineSize = htole(CacheLineSize); 421 data->config.latencyTimer = htole(LatencyTimer); 422 data->config.headerType = htole(HeaderType); 423 data->config.bist = htole(BIST); 424 425 data->config.baseAddr[0] = htole(BAR0); 426 data->config.baseAddr[1] = htole(BAR1); 427 data->config.baseAddr[2] = htole(BAR2); 428 data->config.baseAddr[3] = htole(BAR3); 429 data->config.baseAddr[4] = htole(BAR4); 430 data->config.baseAddr[5] = htole(BAR5); 431 data->config.cardbusCIS = htole(CardbusCIS); 432 data->config.subsystemVendorID = htole(SubsystemVendorID); 433 data->config.subsystemID = htole(SubsystemVendorID); 434 data->config.expansionROM = htole(ExpansionROM); 435 data->config.interruptLine = htole(InterruptLine); 436 data->config.interruptPin = htole(InterruptPin); 437 data->config.minimumGrant = htole(MinimumGrant); 438 data->config.maximumLatency = htole(MaximumLatency); 439 440 data->BARSize[0] = BAR0Size; 441 data->BARSize[1] = BAR1Size; 442 data->BARSize[2] = BAR2Size; 443 data->BARSize[3] = BAR3Size; 444 data->BARSize[4] = BAR4Size; 445 data->BARSize[5] = BAR5Size; 446 447 for (int i = 0; i < 6; ++i) { 448 uint32_t barsize = data->BARSize[i]; 449 if (barsize != 0 && !isPowerOf2(barsize)) { 450 fatal("%s: BAR %d size %d is not a power of 2\n", 451 getInstanceName(), i, data->BARSize[i]); 452 } 453 } 454 455 return data; 456} 457 458REGISTER_SIM_OBJECT("PciConfigData", PciConfigData) 459 460#endif // DOXYGEN_SHOULD_SKIP_THIS 461