device.cc revision 4167
12995Ssaidi@eecs.umich.edu/* 22995Ssaidi@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan 32995Ssaidi@eecs.umich.edu * All rights reserved. 42995Ssaidi@eecs.umich.edu * 52995Ssaidi@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 62995Ssaidi@eecs.umich.edu * modification, are permitted provided that the following conditions are 72995Ssaidi@eecs.umich.edu * met: redistributions of source code must retain the above copyright 82995Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 92995Ssaidi@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 102995Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 112995Ssaidi@eecs.umich.edu * documentation and/or other materials provided with the distribution; 122995Ssaidi@eecs.umich.edu * neither the name of the copyright holders nor the names of its 132995Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from 142995Ssaidi@eecs.umich.edu * this software without specific prior written permission. 152995Ssaidi@eecs.umich.edu * 162995Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172995Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182995Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192995Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202995Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212995Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222995Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232995Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242995Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252995Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262995Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272995Ssaidi@eecs.umich.edu * 282995Ssaidi@eecs.umich.edu * Authors: Ali Saidi 292995Ssaidi@eecs.umich.edu * Andrew Schultz 302995Ssaidi@eecs.umich.edu * Miguel Serrano 312995Ssaidi@eecs.umich.edu */ 322995Ssaidi@eecs.umich.edu 332995Ssaidi@eecs.umich.edu/* @file 342995Ssaidi@eecs.umich.edu * A single PCI device configuration space entry. 352995Ssaidi@eecs.umich.edu */ 362995Ssaidi@eecs.umich.edu 372995Ssaidi@eecs.umich.edu#include <list> 382995Ssaidi@eecs.umich.edu#include <string> 392995Ssaidi@eecs.umich.edu#include <vector> 402995Ssaidi@eecs.umich.edu 412995Ssaidi@eecs.umich.edu#include "base/inifile.hh" 422995Ssaidi@eecs.umich.edu#include "base/intmath.hh" // for isPowerOf2( 432995Ssaidi@eecs.umich.edu#include "base/misc.hh" 442995Ssaidi@eecs.umich.edu#include "base/str.hh" // for to_number 452995Ssaidi@eecs.umich.edu#include "base/trace.hh" 462995Ssaidi@eecs.umich.edu#include "dev/pciconfigall.hh" 472995Ssaidi@eecs.umich.edu#include "dev/pcidev.hh" 482995Ssaidi@eecs.umich.edu#include "dev/alpha/tsunamireg.h" 492995Ssaidi@eecs.umich.edu#include "mem/packet.hh" 502995Ssaidi@eecs.umich.edu#include "mem/packet_access.hh" 512995Ssaidi@eecs.umich.edu#include "sim/builder.hh" 522995Ssaidi@eecs.umich.edu#include "sim/byteswap.hh" 532995Ssaidi@eecs.umich.edu#include "sim/param.hh" 542995Ssaidi@eecs.umich.edu#include "sim/core.hh" 552995Ssaidi@eecs.umich.edu 562995Ssaidi@eecs.umich.eduusing namespace std; 572995Ssaidi@eecs.umich.edu 582995Ssaidi@eecs.umich.edu 592995Ssaidi@eecs.umich.eduPciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid, 602995Ssaidi@eecs.umich.edu int funcid, Platform *p) 612995Ssaidi@eecs.umich.edu : SimpleTimingPort(dev->name() + "-pciconf"), device(dev), platform(p), 622995Ssaidi@eecs.umich.edu busId(busid), deviceId(devid), functionId(funcid) 632995Ssaidi@eecs.umich.edu{ 642995Ssaidi@eecs.umich.edu configAddr = platform->calcConfigAddr(busId, deviceId, functionId); 652995Ssaidi@eecs.umich.edu} 662995Ssaidi@eecs.umich.edu 672995Ssaidi@eecs.umich.edu 682995Ssaidi@eecs.umich.eduTick 692995Ssaidi@eecs.umich.eduPciDev::PciConfigPort::recvAtomic(PacketPtr pkt) 702995Ssaidi@eecs.umich.edu{ 712995Ssaidi@eecs.umich.edu assert(pkt->result == Packet::Unknown); 722995Ssaidi@eecs.umich.edu assert(pkt->getAddr() >= configAddr && 732995Ssaidi@eecs.umich.edu pkt->getAddr() < configAddr + PCI_CONFIG_SIZE); 742995Ssaidi@eecs.umich.edu return pkt->isRead() ? device->readConfig(pkt) : device->writeConfig(pkt); 752995Ssaidi@eecs.umich.edu} 762995Ssaidi@eecs.umich.edu 772995Ssaidi@eecs.umich.eduvoid 782995Ssaidi@eecs.umich.eduPciDev::PciConfigPort::getDeviceAddressRanges(AddrRangeList &resp, 792995Ssaidi@eecs.umich.edu AddrRangeList &snoop) 802995Ssaidi@eecs.umich.edu{ 812995Ssaidi@eecs.umich.edu snoop.clear(); 822995Ssaidi@eecs.umich.edu resp.push_back(RangeSize(configAddr, PCI_CONFIG_SIZE+1)); 832995Ssaidi@eecs.umich.edu} 842995Ssaidi@eecs.umich.edu 852995Ssaidi@eecs.umich.edu 862995Ssaidi@eecs.umich.eduPciDev::PciDev(Params *p) 872995Ssaidi@eecs.umich.edu : DmaDevice(p), plat(p->platform), configData(p->configData), 882995Ssaidi@eecs.umich.edu pioDelay(p->pio_delay), configDelay(p->config_delay), 892995Ssaidi@eecs.umich.edu configPort(NULL) 902995Ssaidi@eecs.umich.edu{ 912995Ssaidi@eecs.umich.edu // copy the config data from the PciConfigData object 922995Ssaidi@eecs.umich.edu if (configData) { 932995Ssaidi@eecs.umich.edu memcpy(config.data, configData->config.data, sizeof(config.data)); 942995Ssaidi@eecs.umich.edu memcpy(BARSize, configData->BARSize, sizeof(BARSize)); 952995Ssaidi@eecs.umich.edu } else 962995Ssaidi@eecs.umich.edu panic("NULL pointer to configuration data"); 972995Ssaidi@eecs.umich.edu 982995Ssaidi@eecs.umich.edu memset(BARAddrs, 0, sizeof(BARAddrs)); 992995Ssaidi@eecs.umich.edu 1002995Ssaidi@eecs.umich.edu plat->registerPciDevice(0, p->deviceNum, p->functionNum, 1013089Ssaidi@eecs.umich.edu letoh(configData->config.interruptLine)); 1023089Ssaidi@eecs.umich.edu} 1033089Ssaidi@eecs.umich.edu 1042995Ssaidi@eecs.umich.eduvoid 1052995Ssaidi@eecs.umich.eduPciDev::init() 1062995Ssaidi@eecs.umich.edu{ 107 if (!configPort) 108 panic("pci config port not connected to anything!"); 109 configPort->sendStatusChange(Port::RangeChange); 110 PioDevice::init(); 111} 112 113unsigned int 114PciDev::drain(Event *de) 115{ 116 unsigned int count; 117 count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de); 118 if (count) 119 changeState(Draining); 120 else 121 changeState(Drained); 122 return count; 123} 124 125Tick 126PciDev::readConfig(PacketPtr pkt) 127{ 128 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 129 if (offset >= PCI_DEVICE_SPECIFIC) 130 panic("Device specific PCI config space not implemented!\n"); 131 132 pkt->allocate(); 133 134 switch (pkt->getSize()) { 135 case sizeof(uint8_t): 136 pkt->set<uint8_t>(config.data[offset]); 137 DPRINTF(PCIDEV, 138 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 139 params()->deviceNum, params()->functionNum, offset, 140 (uint32_t)pkt->get<uint8_t>()); 141 break; 142 case sizeof(uint16_t): 143 pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]); 144 DPRINTF(PCIDEV, 145 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 146 params()->deviceNum, params()->functionNum, offset, 147 (uint32_t)pkt->get<uint16_t>()); 148 break; 149 case sizeof(uint32_t): 150 pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]); 151 DPRINTF(PCIDEV, 152 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 153 params()->deviceNum, params()->functionNum, offset, 154 (uint32_t)pkt->get<uint32_t>()); 155 break; 156 default: 157 panic("invalid access size(?) for PCI configspace!\n"); 158 } 159 pkt->result = Packet::Success; 160 return configDelay; 161 162} 163 164void 165PciDev::addressRanges(AddrRangeList &range_list) 166{ 167 int x = 0; 168 range_list.clear(); 169 for (x = 0; x < 6; x++) 170 if (BARAddrs[x] != 0) 171 range_list.push_back(RangeSize(BARAddrs[x],BARSize[x])); 172} 173 174Tick 175PciDev::writeConfig(PacketPtr pkt) 176{ 177 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 178 if (offset >= PCI_DEVICE_SPECIFIC) 179 panic("Device specific PCI config space not implemented!\n"); 180 181 switch (pkt->getSize()) { 182 case sizeof(uint8_t): 183 switch (offset) { 184 case PCI0_INTERRUPT_LINE: 185 config.interruptLine = pkt->get<uint8_t>(); 186 case PCI_CACHE_LINE_SIZE: 187 config.cacheLineSize = pkt->get<uint8_t>(); 188 case PCI_LATENCY_TIMER: 189 config.latencyTimer = pkt->get<uint8_t>(); 190 break; 191 /* Do nothing for these read-only registers */ 192 case PCI0_INTERRUPT_PIN: 193 case PCI0_MINIMUM_GRANT: 194 case PCI0_MAXIMUM_LATENCY: 195 case PCI_CLASS_CODE: 196 case PCI_REVISION_ID: 197 break; 198 default: 199 panic("writing to a read only register"); 200 } 201 DPRINTF(PCIDEV, 202 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 203 params()->deviceNum, params()->functionNum, offset, 204 (uint32_t)pkt->get<uint8_t>()); 205 break; 206 case sizeof(uint16_t): 207 switch (offset) { 208 case PCI_COMMAND: 209 config.command = pkt->get<uint8_t>(); 210 case PCI_STATUS: 211 config.status = pkt->get<uint8_t>(); 212 case PCI_CACHE_LINE_SIZE: 213 config.cacheLineSize = pkt->get<uint8_t>(); 214 break; 215 default: 216 panic("writing to a read only register"); 217 } 218 DPRINTF(PCIDEV, 219 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 220 params()->deviceNum, params()->functionNum, offset, 221 (uint32_t)pkt->get<uint16_t>()); 222 break; 223 case sizeof(uint32_t): 224 switch (offset) { 225 case PCI0_BASE_ADDR0: 226 case PCI0_BASE_ADDR1: 227 case PCI0_BASE_ADDR2: 228 case PCI0_BASE_ADDR3: 229 case PCI0_BASE_ADDR4: 230 case PCI0_BASE_ADDR5: 231 { 232 int barnum = BAR_NUMBER(offset); 233 234 // convert BAR values to host endianness 235 uint32_t he_old_bar = letoh(config.baseAddr[barnum]); 236 uint32_t he_new_bar = letoh(pkt->get<uint32_t>()); 237 238 uint32_t bar_mask = 239 BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK; 240 241 // Writing 0xffffffff to a BAR tells the card to set the 242 // value of the bar to a bitmask indicating the size of 243 // memory it needs 244 if (he_new_bar == 0xffffffff) { 245 he_new_bar = ~(BARSize[barnum] - 1); 246 } else { 247 // does it mean something special to write 0 to a BAR? 248 he_new_bar &= ~bar_mask; 249 if (he_new_bar) { 250 Addr space_base = BAR_IO_SPACE(he_old_bar) ? 251 TSUNAMI_PCI0_IO : TSUNAMI_PCI0_MEMORY; 252 BARAddrs[barnum] = he_new_bar + space_base; 253 pioPort->sendStatusChange(Port::RangeChange); 254 } 255 } 256 config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) | 257 (he_old_bar & bar_mask)); 258 } 259 break; 260 261 case PCI0_ROM_BASE_ADDR: 262 if (letoh(pkt->get<uint32_t>()) == 0xfffffffe) 263 config.expansionROM = htole((uint32_t)0xffffffff); 264 else 265 config.expansionROM = pkt->get<uint32_t>(); 266 break; 267 268 case PCI_COMMAND: 269 // This could also clear some of the error bits in the Status 270 // register. However they should never get set, so lets ignore 271 // it for now 272 config.command = pkt->get<uint32_t>(); 273 break; 274 275 default: 276 DPRINTF(PCIDEV, "Writing to a read only register"); 277 } 278 DPRINTF(PCIDEV, 279 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 280 params()->deviceNum, params()->functionNum, offset, 281 (uint32_t)pkt->get<uint32_t>()); 282 break; 283 default: 284 panic("invalid access size(?) for PCI configspace!\n"); 285 } 286 pkt->result = Packet::Success; 287 return configDelay; 288 289} 290 291void 292PciDev::serialize(ostream &os) 293{ 294 SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 295 SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 296 SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); 297} 298 299void 300PciDev::unserialize(Checkpoint *cp, const std::string §ion) 301{ 302 UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 303 UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 304 UNSERIALIZE_ARRAY(config.data, 305 sizeof(config.data) / sizeof(config.data[0])); 306 pioPort->sendStatusChange(Port::RangeChange); 307 308} 309 310#ifndef DOXYGEN_SHOULD_SKIP_THIS 311 312BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) 313 314 Param<uint16_t> VendorID; 315 Param<uint16_t> DeviceID; 316 Param<uint16_t> Command; 317 Param<uint16_t> Status; 318 Param<uint8_t> Revision; 319 Param<uint8_t> ProgIF; 320 Param<uint8_t> SubClassCode; 321 Param<uint8_t> ClassCode; 322 Param<uint8_t> CacheLineSize; 323 Param<uint8_t> LatencyTimer; 324 Param<uint8_t> HeaderType; 325 Param<uint8_t> BIST; 326 Param<uint32_t> BAR0; 327 Param<uint32_t> BAR1; 328 Param<uint32_t> BAR2; 329 Param<uint32_t> BAR3; 330 Param<uint32_t> BAR4; 331 Param<uint32_t> BAR5; 332 Param<uint32_t> CardbusCIS; 333 Param<uint16_t> SubsystemVendorID; 334 Param<uint16_t> SubsystemID; 335 Param<uint32_t> ExpansionROM; 336 Param<uint8_t> InterruptLine; 337 Param<uint8_t> InterruptPin; 338 Param<uint8_t> MinimumGrant; 339 Param<uint8_t> MaximumLatency; 340 Param<uint32_t> BAR0Size; 341 Param<uint32_t> BAR1Size; 342 Param<uint32_t> BAR2Size; 343 Param<uint32_t> BAR3Size; 344 Param<uint32_t> BAR4Size; 345 Param<uint32_t> BAR5Size; 346 347END_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) 348 349BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigData) 350 351 INIT_PARAM(VendorID, "Vendor ID"), 352 INIT_PARAM(DeviceID, "Device ID"), 353 INIT_PARAM_DFLT(Command, "Command Register", 0x00), 354 INIT_PARAM_DFLT(Status, "Status Register", 0x00), 355 INIT_PARAM_DFLT(Revision, "Device Revision", 0x00), 356 INIT_PARAM_DFLT(ProgIF, "Programming Interface", 0x00), 357 INIT_PARAM(SubClassCode, "Sub-Class Code"), 358 INIT_PARAM(ClassCode, "Class Code"), 359 INIT_PARAM_DFLT(CacheLineSize, "System Cacheline Size", 0x00), 360 INIT_PARAM_DFLT(LatencyTimer, "PCI Latency Timer", 0x00), 361 INIT_PARAM_DFLT(HeaderType, "PCI Header Type", 0x00), 362 INIT_PARAM_DFLT(BIST, "Built In Self Test", 0x00), 363 INIT_PARAM_DFLT(BAR0, "Base Address Register 0", 0x00), 364 INIT_PARAM_DFLT(BAR1, "Base Address Register 1", 0x00), 365 INIT_PARAM_DFLT(BAR2, "Base Address Register 2", 0x00), 366 INIT_PARAM_DFLT(BAR3, "Base Address Register 3", 0x00), 367 INIT_PARAM_DFLT(BAR4, "Base Address Register 4", 0x00), 368 INIT_PARAM_DFLT(BAR5, "Base Address Register 5", 0x00), 369 INIT_PARAM_DFLT(CardbusCIS, "Cardbus Card Information Structure", 0x00), 370 INIT_PARAM_DFLT(SubsystemVendorID, "Subsystem Vendor ID", 0x00), 371 INIT_PARAM_DFLT(SubsystemID, "Subsystem ID", 0x00), 372 INIT_PARAM_DFLT(ExpansionROM, "Expansion ROM Base Address Register", 0x00), 373 INIT_PARAM(InterruptLine, "Interrupt Line Register"), 374 INIT_PARAM(InterruptPin, "Interrupt Pin Register"), 375 INIT_PARAM_DFLT(MinimumGrant, "Minimum Grant", 0x00), 376 INIT_PARAM_DFLT(MaximumLatency, "Maximum Latency", 0x00), 377 INIT_PARAM_DFLT(BAR0Size, "Base Address Register 0 Size", 0x00), 378 INIT_PARAM_DFLT(BAR1Size, "Base Address Register 1 Size", 0x00), 379 INIT_PARAM_DFLT(BAR2Size, "Base Address Register 2 Size", 0x00), 380 INIT_PARAM_DFLT(BAR3Size, "Base Address Register 3 Size", 0x00), 381 INIT_PARAM_DFLT(BAR4Size, "Base Address Register 4 Size", 0x00), 382 INIT_PARAM_DFLT(BAR5Size, "Base Address Register 5 Size", 0x00) 383 384END_INIT_SIM_OBJECT_PARAMS(PciConfigData) 385 386CREATE_SIM_OBJECT(PciConfigData) 387{ 388 PciConfigData *data = new PciConfigData(getInstanceName()); 389 390 data->config.vendor = htole(VendorID.returnValue()); 391 data->config.device = htole(DeviceID.returnValue()); 392 data->config.command = htole(Command.returnValue()); 393 data->config.status = htole(Status.returnValue()); 394 data->config.revision = htole(Revision.returnValue()); 395 data->config.progIF = htole(ProgIF.returnValue()); 396 data->config.subClassCode = htole(SubClassCode.returnValue()); 397 data->config.classCode = htole(ClassCode.returnValue()); 398 data->config.cacheLineSize = htole(CacheLineSize.returnValue()); 399 data->config.latencyTimer = htole(LatencyTimer.returnValue()); 400 data->config.headerType = htole(HeaderType.returnValue()); 401 data->config.bist = htole(BIST.returnValue()); 402 403 data->config.baseAddr[0] = htole(BAR0.returnValue()); 404 data->config.baseAddr[1] = htole(BAR1.returnValue()); 405 data->config.baseAddr[2] = htole(BAR2.returnValue()); 406 data->config.baseAddr[3] = htole(BAR3.returnValue()); 407 data->config.baseAddr[4] = htole(BAR4.returnValue()); 408 data->config.baseAddr[5] = htole(BAR5.returnValue()); 409 data->config.cardbusCIS = htole(CardbusCIS.returnValue()); 410 data->config.subsystemVendorID = htole(SubsystemVendorID.returnValue()); 411 data->config.subsystemID = htole(SubsystemID.returnValue()); 412 data->config.expansionROM = htole(ExpansionROM.returnValue()); 413 data->config.interruptLine = htole(InterruptLine.returnValue()); 414 data->config.interruptPin = htole(InterruptPin.returnValue()); 415 data->config.minimumGrant = htole(MinimumGrant.returnValue()); 416 data->config.maximumLatency = htole(MaximumLatency.returnValue()); 417 418 data->BARSize[0] = BAR0Size; 419 data->BARSize[1] = BAR1Size; 420 data->BARSize[2] = BAR2Size; 421 data->BARSize[3] = BAR3Size; 422 data->BARSize[4] = BAR4Size; 423 data->BARSize[5] = BAR5Size; 424 425 for (int i = 0; i < 6; ++i) { 426 uint32_t barsize = data->BARSize[i]; 427 if (barsize != 0 && !isPowerOf2(barsize)) { 428 fatal("%s: BAR %d size %d is not a power of 2\n", 429 getInstanceName(), i, data->BARSize[i]); 430 } 431 } 432 433 return data; 434} 435 436REGISTER_SIM_OBJECT("PciConfigData", PciConfigData) 437 438#endif // DOXYGEN_SHOULD_SKIP_THIS 439