device.cc revision 10479
1/* 2 * Copyright (c) 2013 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2004-2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Ali Saidi 41 * Andrew Schultz 42 * Miguel Serrano 43 */ 44 45/* @file 46 * A single PCI device configuration space entry. 47 */ 48 49#include <list> 50#include <string> 51#include <vector> 52 53#include "base/inifile.hh" 54#include "base/intmath.hh" 55#include "base/misc.hh" 56#include "base/str.hh" 57#include "base/trace.hh" 58#include "debug/PCIDEV.hh" 59#include "dev/alpha/tsunamireg.h" 60#include "dev/pciconfigall.hh" 61#include "dev/pcidev.hh" 62#include "mem/packet.hh" 63#include "mem/packet_access.hh" 64#include "sim/byteswap.hh" 65#include "sim/core.hh" 66 67 68PciDevice::PciConfigPort::PciConfigPort(PciDevice *dev, int busid, int devid, 69 int funcid, Platform *p) 70 : SimpleTimingPort(dev->name() + "-pciconf", dev), device(dev), 71 platform(p), busId(busid), deviceId(devid), functionId(funcid) 72{ 73 configAddr = platform->calcPciConfigAddr(busId, deviceId, functionId); 74} 75 76 77Tick 78PciDevice::PciConfigPort::recvAtomic(PacketPtr pkt) 79{ 80 assert(pkt->getAddr() >= configAddr && 81 pkt->getAddr() < configAddr + PCI_CONFIG_SIZE); 82 // @todo someone should pay for this 83 pkt->firstWordDelay = pkt->lastWordDelay = 0; 84 return pkt->isRead() ? device->readConfig(pkt) : device->writeConfig(pkt); 85} 86 87AddrRangeList 88PciDevice::PciConfigPort::getAddrRanges() const 89{ 90 AddrRangeList ranges; 91 if (configAddr != ULL(-1)) 92 ranges.push_back(RangeSize(configAddr, PCI_CONFIG_SIZE+1)); 93 return ranges; 94} 95 96 97PciDevice::PciDevice(const Params *p) 98 : DmaDevice(p), 99 PMCAP_BASE(p->PMCAPBaseOffset), 100 PMCAP_ID_OFFSET(p->PMCAPBaseOffset+PMCAP_ID), 101 PMCAP_PC_OFFSET(p->PMCAPBaseOffset+PMCAP_PC), 102 PMCAP_PMCS_OFFSET(p->PMCAPBaseOffset+PMCAP_PMCS), 103 MSICAP_BASE(p->MSICAPBaseOffset), 104 MSIXCAP_BASE(p->MSIXCAPBaseOffset), 105 MSIXCAP_ID_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_ID), 106 MSIXCAP_MXC_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MXC), 107 MSIXCAP_MTAB_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MTAB), 108 MSIXCAP_MPBA_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MPBA), 109 PXCAP_BASE(p->PXCAPBaseOffset), 110 platform(p->platform), 111 pioDelay(p->pio_latency), 112 configDelay(p->config_latency), 113 configPort(this, params()->pci_bus, params()->pci_dev, 114 params()->pci_func, params()->platform) 115{ 116 config.vendor = htole(p->VendorID); 117 config.device = htole(p->DeviceID); 118 config.command = htole(p->Command); 119 config.status = htole(p->Status); 120 config.revision = htole(p->Revision); 121 config.progIF = htole(p->ProgIF); 122 config.subClassCode = htole(p->SubClassCode); 123 config.classCode = htole(p->ClassCode); 124 config.cacheLineSize = htole(p->CacheLineSize); 125 config.latencyTimer = htole(p->LatencyTimer); 126 config.headerType = htole(p->HeaderType); 127 config.bist = htole(p->BIST); 128 129 config.baseAddr[0] = htole(p->BAR0); 130 config.baseAddr[1] = htole(p->BAR1); 131 config.baseAddr[2] = htole(p->BAR2); 132 config.baseAddr[3] = htole(p->BAR3); 133 config.baseAddr[4] = htole(p->BAR4); 134 config.baseAddr[5] = htole(p->BAR5); 135 config.cardbusCIS = htole(p->CardbusCIS); 136 config.subsystemVendorID = htole(p->SubsystemVendorID); 137 config.subsystemID = htole(p->SubsystemID); 138 config.expansionROM = htole(p->ExpansionROM); 139 config.capabilityPtr = htole(p->CapabilityPtr); 140 // Zero out the 7 bytes of reserved space in the PCI Config space register. 141 bzero(config.reserved, 7*sizeof(uint8_t)); 142 config.interruptLine = htole(p->InterruptLine); 143 config.interruptPin = htole(p->InterruptPin); 144 config.minimumGrant = htole(p->MinimumGrant); 145 config.maximumLatency = htole(p->MaximumLatency); 146 147 // Initialize the capability lists 148 // These structs are bitunions, meaning the data is stored in host 149 // endianess and must be converted to Little Endian when accessed 150 // by the guest 151 // PMCAP 152 pmcap.pid = (uint16_t)p->PMCAPCapId; // pid.cid 153 pmcap.pid |= (uint16_t)p->PMCAPNextCapability << 8; //pid.next 154 pmcap.pc = p->PMCAPCapabilities; 155 pmcap.pmcs = p->PMCAPCtrlStatus; 156 157 // MSICAP 158 msicap.mid = (uint16_t)p->MSICAPCapId; //mid.cid 159 msicap.mid |= (uint16_t)p->MSICAPNextCapability << 8; //mid.next 160 msicap.mc = p->MSICAPMsgCtrl; 161 msicap.ma = p->MSICAPMsgAddr; 162 msicap.mua = p->MSICAPMsgUpperAddr; 163 msicap.md = p->MSICAPMsgData; 164 msicap.mmask = p->MSICAPMaskBits; 165 msicap.mpend = p->MSICAPPendingBits; 166 167 // MSIXCAP 168 msixcap.mxid = (uint16_t)p->MSIXCAPCapId; //mxid.cid 169 msixcap.mxid |= (uint16_t)p->MSIXCAPNextCapability << 8; //mxid.next 170 msixcap.mxc = p->MSIXMsgCtrl; 171 msixcap.mtab = p->MSIXTableOffset; 172 msixcap.mpba = p->MSIXPbaOffset; 173 174 // allocate MSIX structures if MSIXCAP_BASE 175 // indicates the MSIXCAP is being used by having a 176 // non-zero base address. 177 // The MSIX tables are stored by the guest in 178 // little endian byte-order as according the 179 // PCIe specification. Make sure to take the proper 180 // actions when manipulating these tables on the host 181 uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff; 182 if (MSIXCAP_BASE != 0x0) { 183 int msix_vecs = msixcap_mxc_ts + 1; 184 MSIXTable tmp1 = {{0UL,0UL,0UL,0UL}}; 185 msix_table.resize(msix_vecs, tmp1); 186 187 MSIXPbaEntry tmp2 = {0}; 188 int pba_size = msix_vecs / MSIXVECS_PER_PBA; 189 if ((msix_vecs % MSIXVECS_PER_PBA) > 0) { 190 pba_size++; 191 } 192 msix_pba.resize(pba_size, tmp2); 193 } 194 MSIX_TABLE_OFFSET = msixcap.mtab & 0xfffffffc; 195 MSIX_TABLE_END = MSIX_TABLE_OFFSET + 196 (msixcap_mxc_ts + 1) * sizeof(MSIXTable); 197 MSIX_PBA_OFFSET = msixcap.mpba & 0xfffffffc; 198 MSIX_PBA_END = MSIX_PBA_OFFSET + 199 ((msixcap_mxc_ts + 1) / MSIXVECS_PER_PBA) 200 * sizeof(MSIXPbaEntry); 201 if (((msixcap_mxc_ts + 1) % MSIXVECS_PER_PBA) > 0) { 202 MSIX_PBA_END += sizeof(MSIXPbaEntry); 203 } 204 205 // PXCAP 206 pxcap.pxid = (uint16_t)p->PXCAPCapId; //pxid.cid 207 pxcap.pxid |= (uint16_t)p->PXCAPNextCapability << 8; //pxid.next 208 pxcap.pxcap = p->PXCAPCapabilities; 209 pxcap.pxdcap = p->PXCAPDevCapabilities; 210 pxcap.pxdc = p->PXCAPDevCtrl; 211 pxcap.pxds = p->PXCAPDevStatus; 212 pxcap.pxlcap = p->PXCAPLinkCap; 213 pxcap.pxlc = p->PXCAPLinkCtrl; 214 pxcap.pxls = p->PXCAPLinkStatus; 215 pxcap.pxdcap2 = p->PXCAPDevCap2; 216 pxcap.pxdc2 = p->PXCAPDevCtrl2; 217 218 BARSize[0] = p->BAR0Size; 219 BARSize[1] = p->BAR1Size; 220 BARSize[2] = p->BAR2Size; 221 BARSize[3] = p->BAR3Size; 222 BARSize[4] = p->BAR4Size; 223 BARSize[5] = p->BAR5Size; 224 225 legacyIO[0] = p->BAR0LegacyIO; 226 legacyIO[1] = p->BAR1LegacyIO; 227 legacyIO[2] = p->BAR2LegacyIO; 228 legacyIO[3] = p->BAR3LegacyIO; 229 legacyIO[4] = p->BAR4LegacyIO; 230 legacyIO[5] = p->BAR5LegacyIO; 231 232 for (int i = 0; i < 6; ++i) { 233 if (legacyIO[i]) { 234 BARAddrs[i] = p->LegacyIOBase + letoh(config.baseAddr[i]); 235 config.baseAddr[i] = 0; 236 } else { 237 BARAddrs[i] = 0; 238 uint32_t barsize = BARSize[i]; 239 if (barsize != 0 && !isPowerOf2(barsize)) { 240 fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]); 241 } 242 } 243 } 244 245 platform->registerPciDevice(p->pci_bus, p->pci_dev, p->pci_func, 246 letoh(config.interruptLine)); 247} 248 249void 250PciDevice::init() 251{ 252 if (!configPort.isConnected()) 253 panic("PCI config port on %s not connected to anything!\n", name()); 254 configPort.sendRangeChange(); 255 DmaDevice::init(); 256} 257 258unsigned int 259PciDevice::drain(DrainManager *dm) 260{ 261 unsigned int count; 262 count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm); 263 if (count) 264 setDrainState(Drainable::Draining); 265 else 266 setDrainState(Drainable::Drained); 267 return count; 268} 269 270Tick 271PciDevice::readConfig(PacketPtr pkt) 272{ 273 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 274 275 /* Return 0 for accesses to unimplemented PCI configspace areas */ 276 if (offset >= PCI_DEVICE_SPECIFIC && 277 offset < PCI_CONFIG_SIZE) { 278 warn_once("Device specific PCI config space " 279 "not implemented for %s!\n", this->name()); 280 switch (pkt->getSize()) { 281 case sizeof(uint8_t): 282 pkt->set<uint8_t>(0); 283 break; 284 case sizeof(uint16_t): 285 pkt->set<uint16_t>(0); 286 break; 287 case sizeof(uint32_t): 288 pkt->set<uint32_t>(0); 289 break; 290 default: 291 panic("invalid access size(?) for PCI configspace!\n"); 292 } 293 } else if (offset > PCI_CONFIG_SIZE) { 294 panic("Out-of-range access to PCI config space!\n"); 295 } 296 297 298 299 pkt->allocate(); 300 301 switch (pkt->getSize()) { 302 case sizeof(uint8_t): 303 pkt->set<uint8_t>(config.data[offset]); 304 DPRINTF(PCIDEV, 305 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 306 params()->pci_dev, params()->pci_func, offset, 307 (uint32_t)pkt->get<uint8_t>()); 308 break; 309 case sizeof(uint16_t): 310 pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]); 311 DPRINTF(PCIDEV, 312 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 313 params()->pci_dev, params()->pci_func, offset, 314 (uint32_t)pkt->get<uint16_t>()); 315 break; 316 case sizeof(uint32_t): 317 pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]); 318 DPRINTF(PCIDEV, 319 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 320 params()->pci_dev, params()->pci_func, offset, 321 (uint32_t)pkt->get<uint32_t>()); 322 break; 323 default: 324 panic("invalid access size(?) for PCI configspace!\n"); 325 } 326 pkt->makeAtomicResponse(); 327 return configDelay; 328 329} 330 331AddrRangeList 332PciDevice::getAddrRanges() const 333{ 334 AddrRangeList ranges; 335 int x = 0; 336 for (x = 0; x < 6; x++) 337 if (BARAddrs[x] != 0) 338 ranges.push_back(RangeSize(BARAddrs[x],BARSize[x])); 339 return ranges; 340} 341 342Tick 343PciDevice::writeConfig(PacketPtr pkt) 344{ 345 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 346 347 /* No effect if we write to config space that is not implemented*/ 348 if (offset >= PCI_DEVICE_SPECIFIC && 349 offset < PCI_CONFIG_SIZE) { 350 warn_once("Device specific PCI config space " 351 "not implemented for %s!\n", this->name()); 352 switch (pkt->getSize()) { 353 case sizeof(uint8_t): 354 case sizeof(uint16_t): 355 case sizeof(uint32_t): 356 break; 357 default: 358 panic("invalid access size(?) for PCI configspace!\n"); 359 } 360 } else if (offset > PCI_CONFIG_SIZE) { 361 panic("Out-of-range access to PCI config space!\n"); 362 } 363 364 switch (pkt->getSize()) { 365 case sizeof(uint8_t): 366 switch (offset) { 367 case PCI0_INTERRUPT_LINE: 368 config.interruptLine = pkt->get<uint8_t>(); 369 break; 370 case PCI_CACHE_LINE_SIZE: 371 config.cacheLineSize = pkt->get<uint8_t>(); 372 break; 373 case PCI_LATENCY_TIMER: 374 config.latencyTimer = pkt->get<uint8_t>(); 375 break; 376 /* Do nothing for these read-only registers */ 377 case PCI0_INTERRUPT_PIN: 378 case PCI0_MINIMUM_GRANT: 379 case PCI0_MAXIMUM_LATENCY: 380 case PCI_CLASS_CODE: 381 case PCI_REVISION_ID: 382 break; 383 default: 384 panic("writing to a read only register"); 385 } 386 DPRINTF(PCIDEV, 387 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 388 params()->pci_dev, params()->pci_func, offset, 389 (uint32_t)pkt->get<uint8_t>()); 390 break; 391 case sizeof(uint16_t): 392 switch (offset) { 393 case PCI_COMMAND: 394 config.command = pkt->get<uint8_t>(); 395 break; 396 case PCI_STATUS: 397 config.status = pkt->get<uint8_t>(); 398 break; 399 case PCI_CACHE_LINE_SIZE: 400 config.cacheLineSize = pkt->get<uint8_t>(); 401 break; 402 default: 403 panic("writing to a read only register"); 404 } 405 DPRINTF(PCIDEV, 406 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 407 params()->pci_dev, params()->pci_func, offset, 408 (uint32_t)pkt->get<uint16_t>()); 409 break; 410 case sizeof(uint32_t): 411 switch (offset) { 412 case PCI0_BASE_ADDR0: 413 case PCI0_BASE_ADDR1: 414 case PCI0_BASE_ADDR2: 415 case PCI0_BASE_ADDR3: 416 case PCI0_BASE_ADDR4: 417 case PCI0_BASE_ADDR5: 418 { 419 int barnum = BAR_NUMBER(offset); 420 421 if (!legacyIO[barnum]) { 422 // convert BAR values to host endianness 423 uint32_t he_old_bar = letoh(config.baseAddr[barnum]); 424 uint32_t he_new_bar = letoh(pkt->get<uint32_t>()); 425 426 uint32_t bar_mask = 427 BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK; 428 429 // Writing 0xffffffff to a BAR tells the card to set the 430 // value of the bar to a bitmask indicating the size of 431 // memory it needs 432 if (he_new_bar == 0xffffffff) { 433 he_new_bar = ~(BARSize[barnum] - 1); 434 } else { 435 // does it mean something special to write 0 to a BAR? 436 he_new_bar &= ~bar_mask; 437 if (he_new_bar) { 438 BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ? 439 platform->calcPciIOAddr(he_new_bar) : 440 platform->calcPciMemAddr(he_new_bar); 441 pioPort.sendRangeChange(); 442 } 443 } 444 config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) | 445 (he_old_bar & bar_mask)); 446 } 447 } 448 break; 449 450 case PCI0_ROM_BASE_ADDR: 451 if (letoh(pkt->get<uint32_t>()) == 0xfffffffe) 452 config.expansionROM = htole((uint32_t)0xffffffff); 453 else 454 config.expansionROM = pkt->get<uint32_t>(); 455 break; 456 457 case PCI_COMMAND: 458 // This could also clear some of the error bits in the Status 459 // register. However they should never get set, so lets ignore 460 // it for now 461 config.command = pkt->get<uint32_t>(); 462 break; 463 464 default: 465 DPRINTF(PCIDEV, "Writing to a read only register"); 466 } 467 DPRINTF(PCIDEV, 468 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 469 params()->pci_dev, params()->pci_func, offset, 470 (uint32_t)pkt->get<uint32_t>()); 471 break; 472 default: 473 panic("invalid access size(?) for PCI configspace!\n"); 474 } 475 pkt->makeAtomicResponse(); 476 return configDelay; 477} 478 479void 480PciDevice::serialize(std::ostream &os) 481{ 482 SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 483 SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 484 SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); 485 486 // serialize the capability list registers 487 paramOut(os, csprintf("pmcap.pid"), uint16_t(pmcap.pid)); 488 paramOut(os, csprintf("pmcap.pc"), uint16_t(pmcap.pc)); 489 paramOut(os, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs)); 490 491 paramOut(os, csprintf("msicap.mid"), uint16_t(msicap.mid)); 492 paramOut(os, csprintf("msicap.mc"), uint16_t(msicap.mc)); 493 paramOut(os, csprintf("msicap.ma"), uint32_t(msicap.ma)); 494 SERIALIZE_SCALAR(msicap.mua); 495 paramOut(os, csprintf("msicap.md"), uint16_t(msicap.md)); 496 SERIALIZE_SCALAR(msicap.mmask); 497 SERIALIZE_SCALAR(msicap.mpend); 498 499 paramOut(os, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid)); 500 paramOut(os, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc)); 501 paramOut(os, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab)); 502 paramOut(os, csprintf("msixcap.mpba"), uint32_t(msixcap.mpba)); 503 504 // Only serialize if we have a non-zero base address 505 if (MSIXCAP_BASE != 0x0) { 506 uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff; 507 int msix_array_size = msixcap_mxc_ts + 1; 508 int pba_array_size = msix_array_size/MSIXVECS_PER_PBA; 509 if ((msix_array_size % MSIXVECS_PER_PBA) > 0) { 510 pba_array_size++; 511 } 512 513 SERIALIZE_SCALAR(msix_array_size); 514 SERIALIZE_SCALAR(pba_array_size); 515 516 for (int i = 0; i < msix_array_size; i++) { 517 paramOut(os, csprintf("msix_table[%d].addr_lo", i), 518 msix_table[i].fields.addr_lo); 519 paramOut(os, csprintf("msix_table[%d].addr_hi", i), 520 msix_table[i].fields.addr_hi); 521 paramOut(os, csprintf("msix_table[%d].msg_data", i), 522 msix_table[i].fields.msg_data); 523 paramOut(os, csprintf("msix_table[%d].vec_ctrl", i), 524 msix_table[i].fields.vec_ctrl); 525 } 526 for (int i = 0; i < pba_array_size; i++) { 527 paramOut(os, csprintf("msix_pba[%d].bits", i), 528 msix_pba[i].bits); 529 } 530 } 531 532 paramOut(os, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid)); 533 paramOut(os, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap)); 534 paramOut(os, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap)); 535 paramOut(os, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc)); 536 paramOut(os, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds)); 537 paramOut(os, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap)); 538 paramOut(os, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc)); 539 paramOut(os, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls)); 540 paramOut(os, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2)); 541 paramOut(os, csprintf("pxcap.pxdc2"), uint32_t(pxcap.pxdc2)); 542} 543 544void 545PciDevice::unserialize(Checkpoint *cp, const std::string §ion) 546{ 547 UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 548 UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 549 UNSERIALIZE_ARRAY(config.data, 550 sizeof(config.data) / sizeof(config.data[0])); 551 552 // unserialize the capability list registers 553 uint16_t tmp16; 554 uint32_t tmp32; 555 paramIn(cp, section, csprintf("pmcap.pid"), tmp16); 556 pmcap.pid = tmp16; 557 paramIn(cp, section, csprintf("pmcap.pc"), tmp16); 558 pmcap.pc = tmp16; 559 paramIn(cp, section, csprintf("pmcap.pmcs"), tmp16); 560 pmcap.pmcs = tmp16; 561 562 paramIn(cp, section, csprintf("msicap.mid"), tmp16); 563 msicap.mid = tmp16; 564 paramIn(cp, section, csprintf("msicap.mc"), tmp16); 565 msicap.mc = tmp16; 566 paramIn(cp, section, csprintf("msicap.ma"), tmp32); 567 msicap.ma = tmp32; 568 UNSERIALIZE_SCALAR(msicap.mua); 569 paramIn(cp, section, csprintf("msicap.md"), tmp16);; 570 msicap.md = tmp16; 571 UNSERIALIZE_SCALAR(msicap.mmask); 572 UNSERIALIZE_SCALAR(msicap.mpend); 573 574 paramIn(cp, section, csprintf("msixcap.mxid"), tmp16); 575 msixcap.mxid = tmp16; 576 paramIn(cp, section, csprintf("msixcap.mxc"), tmp16); 577 msixcap.mxc = tmp16; 578 paramIn(cp, section, csprintf("msixcap.mtab"), tmp32); 579 msixcap.mtab = tmp32; 580 paramIn(cp, section, csprintf("msixcap.mpba"), tmp32); 581 msixcap.mpba = tmp32; 582 583 // Only allocate if MSIXCAP_BASE is not 0x0 584 if (MSIXCAP_BASE != 0x0) { 585 int msix_array_size; 586 int pba_array_size; 587 588 UNSERIALIZE_SCALAR(msix_array_size); 589 UNSERIALIZE_SCALAR(pba_array_size); 590 591 MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}}; 592 msix_table.resize(msix_array_size, tmp1); 593 594 MSIXPbaEntry tmp2 = {0}; 595 msix_pba.resize(pba_array_size, tmp2); 596 597 for (int i = 0; i < msix_array_size; i++) { 598 paramIn(cp, section, csprintf("msix_table[%d].addr_lo", i), 599 msix_table[i].fields.addr_lo); 600 paramIn(cp, section, csprintf("msix_table[%d].addr_hi", i), 601 msix_table[i].fields.addr_hi); 602 paramIn(cp, section, csprintf("msix_table[%d].msg_data", i), 603 msix_table[i].fields.msg_data); 604 paramIn(cp, section, csprintf("msix_table[%d].vec_ctrl", i), 605 msix_table[i].fields.vec_ctrl); 606 } 607 for (int i = 0; i < pba_array_size; i++) { 608 paramIn(cp, section, csprintf("msix_pba[%d].bits", i), 609 msix_pba[i].bits); 610 } 611 } 612 613 paramIn(cp, section, csprintf("pxcap.pxid"), tmp16); 614 pxcap.pxid = tmp16; 615 paramIn(cp, section, csprintf("pxcap.pxcap"), tmp16); 616 pxcap.pxcap = tmp16; 617 paramIn(cp, section, csprintf("pxcap.pxdcap"), tmp32); 618 pxcap.pxdcap = tmp32; 619 paramIn(cp, section, csprintf("pxcap.pxdc"), tmp16); 620 pxcap.pxdc = tmp16; 621 paramIn(cp, section, csprintf("pxcap.pxds"), tmp16); 622 pxcap.pxds = tmp16; 623 paramIn(cp, section, csprintf("pxcap.pxlcap"), tmp32); 624 pxcap.pxlcap = tmp32; 625 paramIn(cp, section, csprintf("pxcap.pxlc"), tmp16); 626 pxcap.pxlc = tmp16; 627 paramIn(cp, section, csprintf("pxcap.pxls"), tmp16); 628 pxcap.pxls = tmp16; 629 paramIn(cp, section, csprintf("pxcap.pxdcap2"), tmp32); 630 pxcap.pxdcap2 = tmp32; 631 paramIn(cp, section, csprintf("pxcap.pxdc2"), tmp32); 632 pxcap.pxdc2 = tmp32; 633 pioPort.sendRangeChange(); 634} 635 636