device.cc revision 4167
13691SN/A/* 23691SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 33691SN/A * All rights reserved. 43691SN/A * 53691SN/A * Redistribution and use in source and binary forms, with or without 63691SN/A * modification, are permitted provided that the following conditions are 79885Sstever@gmail.com * met: redistributions of source code must retain the above copyright 83691SN/A * notice, this list of conditions and the following disclaimer; 93691SN/A * redistributions in binary form must reproduce the above copyright 103691SN/A * notice, this list of conditions and the following disclaimer in the 113691SN/A * documentation and/or other materials provided with the distribution; 123691SN/A * neither the name of the copyright holders nor the names of its 133691SN/A * contributors may be used to endorse or promote products derived from 143691SN/A * this software without specific prior written permission. 153691SN/A * 163691SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173691SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183691SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193691SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203691SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213691SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223691SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233691SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243691SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253691SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263691SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273691SN/A * 283691SN/A * Authors: Ali Saidi 293691SN/A * Andrew Schultz 303691SN/A * Miguel Serrano 313691SN/A */ 323691SN/A 333691SN/A/* @file 343691SN/A * A single PCI device configuration space entry. 353691SN/A */ 363691SN/A 373691SN/A#include <list> 383691SN/A#include <string> 399885Sstever@gmail.com#include <vector> 403691SN/A 413691SN/A#include "base/inifile.hh" 423691SN/A#include "base/intmath.hh" // for isPowerOf2( 433691SN/A#include "base/misc.hh" 443691SN/A#include "base/str.hh" // for to_number 453691SN/A#include "base/trace.hh" 463691SN/A#include "dev/pciconfigall.hh" 473691SN/A#include "dev/pcidev.hh" 483691SN/A#include "dev/alpha/tsunamireg.h" 493691SN/A#include "mem/packet.hh" 503691SN/A#include "mem/packet_access.hh" 513691SN/A#include "sim/builder.hh" 523691SN/A#include "sim/byteswap.hh" 533691SN/A#include "sim/param.hh" 543691SN/A#include "sim/core.hh" 553691SN/A 563691SN/Ausing namespace std; 573691SN/A 585778SN/A 593691SN/APciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid, 603691SN/A int funcid, Platform *p) 613691SN/A : SimpleTimingPort(dev->name() + "-pciconf"), device(dev), platform(p), 6211219Snilay@cs.wisc.edu busId(busid), deviceId(devid), functionId(funcid) 633691SN/A{ 643691SN/A configAddr = platform->calcConfigAddr(busId, deviceId, functionId); 653691SN/A} 663691SN/A 673691SN/A 683691SN/ATick 693691SN/APciDev::PciConfigPort::recvAtomic(PacketPtr pkt) 705778SN/A{ 713691SN/A assert(pkt->result == Packet::Unknown); 723691SN/A assert(pkt->getAddr() >= configAddr && 733691SN/A pkt->getAddr() < configAddr + PCI_CONFIG_SIZE); 743691SN/A return pkt->isRead() ? device->readConfig(pkt) : device->writeConfig(pkt); 753691SN/A} 763691SN/A 774966SN/Avoid 783691SN/APciDev::PciConfigPort::getDeviceAddressRanges(AddrRangeList &resp, 793691SN/A AddrRangeList &snoop) 803691SN/A{ 813691SN/A snoop.clear(); 823691SN/A resp.push_back(RangeSize(configAddr, PCI_CONFIG_SIZE+1)); 833691SN/A} 843691SN/A 853691SN/A 863691SN/APciDev::PciDev(Params *p) 873691SN/A : DmaDevice(p), plat(p->platform), configData(p->configData), 883691SN/A pioDelay(p->pio_delay), configDelay(p->config_delay), 893691SN/A configPort(NULL) 903691SN/A{ 913691SN/A // copy the config data from the PciConfigData object 923691SN/A if (configData) { 933691SN/A memcpy(config.data, configData->config.data, sizeof(config.data)); 943691SN/A memcpy(BARSize, configData->BARSize, sizeof(BARSize)); 953691SN/A } else 963691SN/A panic("NULL pointer to configuration data"); 973691SN/A 983691SN/A memset(BARAddrs, 0, sizeof(BARAddrs)); 993691SN/A 1003691SN/A plat->registerPciDevice(0, p->deviceNum, p->functionNum, 1013691SN/A letoh(configData->config.interruptLine)); 1023691SN/A} 1033691SN/A 1044966SN/Avoid 1054966SN/APciDev::init() 1064966SN/A{ 1074966SN/A if (!configPort) 1084966SN/A panic("pci config port not connected to anything!"); 1093691SN/A configPort->sendStatusChange(Port::RangeChange); 1104966SN/A PioDevice::init(); 1114966SN/A} 1124966SN/A 1134966SN/Aunsigned int 1144966SN/APciDev::drain(Event *de) 1154966SN/A{ 1164966SN/A unsigned int count; 1174966SN/A count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de); 1184966SN/A if (count) 1194966SN/A changeState(Draining); 1209885Sstever@gmail.com else 1214966SN/A changeState(Drained); 1224966SN/A return count; 1234966SN/A} 12411219Snilay@cs.wisc.edu 12511219Snilay@cs.wisc.eduTick 12611219Snilay@cs.wisc.eduPciDev::readConfig(PacketPtr pkt) 12711219Snilay@cs.wisc.edu{ 12811219Snilay@cs.wisc.edu int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 12911219Snilay@cs.wisc.edu if (offset >= PCI_DEVICE_SPECIFIC) 13011219Snilay@cs.wisc.edu panic("Device specific PCI config space not implemented!\n"); 13111219Snilay@cs.wisc.edu 13211219Snilay@cs.wisc.edu pkt->allocate(); 13311219Snilay@cs.wisc.edu 13411219Snilay@cs.wisc.edu switch (pkt->getSize()) { 13511219Snilay@cs.wisc.edu case sizeof(uint8_t): 13611219Snilay@cs.wisc.edu pkt->set<uint8_t>(config.data[offset]); 13711219Snilay@cs.wisc.edu DPRINTF(PCIDEV, 13811219Snilay@cs.wisc.edu "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 13911219Snilay@cs.wisc.edu params()->deviceNum, params()->functionNum, offset, 14011219Snilay@cs.wisc.edu (uint32_t)pkt->get<uint8_t>()); 14111219Snilay@cs.wisc.edu break; 14211219Snilay@cs.wisc.edu case sizeof(uint16_t): 14311219Snilay@cs.wisc.edu pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]); 14411219Snilay@cs.wisc.edu DPRINTF(PCIDEV, 14511219Snilay@cs.wisc.edu "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 14611219Snilay@cs.wisc.edu params()->deviceNum, params()->functionNum, offset, 14711219Snilay@cs.wisc.edu (uint32_t)pkt->get<uint16_t>()); 14811219Snilay@cs.wisc.edu break; 14911219Snilay@cs.wisc.edu case sizeof(uint32_t): 15011219Snilay@cs.wisc.edu pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]); 15111219Snilay@cs.wisc.edu DPRINTF(PCIDEV, 15211219Snilay@cs.wisc.edu "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 15311219Snilay@cs.wisc.edu params()->deviceNum, params()->functionNum, offset, 15411219Snilay@cs.wisc.edu (uint32_t)pkt->get<uint32_t>()); 15511219Snilay@cs.wisc.edu break; 15611219Snilay@cs.wisc.edu default: 15711219Snilay@cs.wisc.edu panic("invalid access size(?) for PCI configspace!\n"); 15811219Snilay@cs.wisc.edu } 15911219Snilay@cs.wisc.edu pkt->result = Packet::Success; 16011219Snilay@cs.wisc.edu return configDelay; 16111219Snilay@cs.wisc.edu 16211219Snilay@cs.wisc.edu} 16311219Snilay@cs.wisc.edu 16411219Snilay@cs.wisc.eduvoid 16511219Snilay@cs.wisc.eduPciDev::addressRanges(AddrRangeList &range_list) 16611219Snilay@cs.wisc.edu{ 16711219Snilay@cs.wisc.edu int x = 0; 16811219Snilay@cs.wisc.edu range_list.clear(); 16911219Snilay@cs.wisc.edu for (x = 0; x < 6; x++) 17011219Snilay@cs.wisc.edu if (BARAddrs[x] != 0) 17111219Snilay@cs.wisc.edu range_list.push_back(RangeSize(BARAddrs[x],BARSize[x])); 17211219Snilay@cs.wisc.edu} 17311219Snilay@cs.wisc.edu 17411219Snilay@cs.wisc.eduTick 17511219Snilay@cs.wisc.eduPciDev::writeConfig(PacketPtr pkt) 17611219Snilay@cs.wisc.edu{ 17711219Snilay@cs.wisc.edu int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 17811219Snilay@cs.wisc.edu if (offset >= PCI_DEVICE_SPECIFIC) 17911219Snilay@cs.wisc.edu panic("Device specific PCI config space not implemented!\n"); 18011219Snilay@cs.wisc.edu 18111219Snilay@cs.wisc.edu switch (pkt->getSize()) { 18211219Snilay@cs.wisc.edu case sizeof(uint8_t): 18311219Snilay@cs.wisc.edu switch (offset) { 18411219Snilay@cs.wisc.edu case PCI0_INTERRUPT_LINE: 18511219Snilay@cs.wisc.edu config.interruptLine = pkt->get<uint8_t>(); 18611219Snilay@cs.wisc.edu case PCI_CACHE_LINE_SIZE: 18711219Snilay@cs.wisc.edu config.cacheLineSize = pkt->get<uint8_t>(); 18811219Snilay@cs.wisc.edu case PCI_LATENCY_TIMER: 18911219Snilay@cs.wisc.edu config.latencyTimer = pkt->get<uint8_t>(); 19011219Snilay@cs.wisc.edu break; 19111219Snilay@cs.wisc.edu /* Do nothing for these read-only registers */ 19211219Snilay@cs.wisc.edu case PCI0_INTERRUPT_PIN: 19311219Snilay@cs.wisc.edu case PCI0_MINIMUM_GRANT: 19411219Snilay@cs.wisc.edu case PCI0_MAXIMUM_LATENCY: 19511219Snilay@cs.wisc.edu case PCI_CLASS_CODE: 19611219Snilay@cs.wisc.edu case PCI_REVISION_ID: 19711219Snilay@cs.wisc.edu break; 19811219Snilay@cs.wisc.edu default: 19911219Snilay@cs.wisc.edu panic("writing to a read only register"); 20011219Snilay@cs.wisc.edu } 20111219Snilay@cs.wisc.edu DPRINTF(PCIDEV, 20211219Snilay@cs.wisc.edu "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 20311219Snilay@cs.wisc.edu params()->deviceNum, params()->functionNum, offset, 20411219Snilay@cs.wisc.edu (uint32_t)pkt->get<uint8_t>()); 20511219Snilay@cs.wisc.edu break; 20611219Snilay@cs.wisc.edu case sizeof(uint16_t): 20711219Snilay@cs.wisc.edu switch (offset) { 20811219Snilay@cs.wisc.edu case PCI_COMMAND: 20911219Snilay@cs.wisc.edu config.command = pkt->get<uint8_t>(); 21011219Snilay@cs.wisc.edu case PCI_STATUS: 21111219Snilay@cs.wisc.edu config.status = pkt->get<uint8_t>(); 21211219Snilay@cs.wisc.edu case PCI_CACHE_LINE_SIZE: 21311219Snilay@cs.wisc.edu config.cacheLineSize = pkt->get<uint8_t>(); 21411219Snilay@cs.wisc.edu break; 21511219Snilay@cs.wisc.edu default: 21611219Snilay@cs.wisc.edu panic("writing to a read only register"); 21711219Snilay@cs.wisc.edu } 21811219Snilay@cs.wisc.edu DPRINTF(PCIDEV, 21911219Snilay@cs.wisc.edu "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 22011219Snilay@cs.wisc.edu params()->deviceNum, params()->functionNum, offset, 22111219Snilay@cs.wisc.edu (uint32_t)pkt->get<uint16_t>()); 22211219Snilay@cs.wisc.edu break; 22311219Snilay@cs.wisc.edu case sizeof(uint32_t): 22411219Snilay@cs.wisc.edu switch (offset) { 22511219Snilay@cs.wisc.edu case PCI0_BASE_ADDR0: 22611219Snilay@cs.wisc.edu case PCI0_BASE_ADDR1: 22711219Snilay@cs.wisc.edu case PCI0_BASE_ADDR2: 22811219Snilay@cs.wisc.edu case PCI0_BASE_ADDR3: 22911219Snilay@cs.wisc.edu 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