1/* 2 * Copyright (c) 2013, 2015 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 "dev/pci/device.hh" 50 51#include <list> 52#include <string> 53#include <vector> 54 55#include "base/inifile.hh" 56#include "base/intmath.hh" 57#include "base/logging.hh" 58#include "base/str.hh" 59#include "base/trace.hh" 60#include "debug/PciDevice.hh" 61#include "mem/packet.hh" 62#include "mem/packet_access.hh" 63#include "sim/byteswap.hh" 64#include "sim/core.hh" 65 66PciDevice::PciDevice(const PciDeviceParams *p) 67 : DmaDevice(p), 68 _busAddr(p->pci_bus, p->pci_dev, p->pci_func), 69 PMCAP_BASE(p->PMCAPBaseOffset), 70 PMCAP_ID_OFFSET(p->PMCAPBaseOffset+PMCAP_ID), 71 PMCAP_PC_OFFSET(p->PMCAPBaseOffset+PMCAP_PC), 72 PMCAP_PMCS_OFFSET(p->PMCAPBaseOffset+PMCAP_PMCS), 73 MSICAP_BASE(p->MSICAPBaseOffset), 74 MSIXCAP_BASE(p->MSIXCAPBaseOffset), 75 MSIXCAP_ID_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_ID), 76 MSIXCAP_MXC_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MXC), 77 MSIXCAP_MTAB_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MTAB), 78 MSIXCAP_MPBA_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MPBA), 79 PXCAP_BASE(p->PXCAPBaseOffset), 80 81 hostInterface(p->host->registerDevice(this, _busAddr, 82 (PciIntPin)p->InterruptPin)), 83 pioDelay(p->pio_latency), 84 configDelay(p->config_latency) 85{ 86 fatal_if(p->InterruptPin >= 5, 87 "Invalid PCI interrupt '%i' specified.", p->InterruptPin); 88 89 config.vendor = htole(p->VendorID); 90 config.device = htole(p->DeviceID); 91 config.command = htole(p->Command); 92 config.status = htole(p->Status); 93 config.revision = htole(p->Revision); 94 config.progIF = htole(p->ProgIF); 95 config.subClassCode = htole(p->SubClassCode); 96 config.classCode = htole(p->ClassCode); 97 config.cacheLineSize = htole(p->CacheLineSize); 98 config.latencyTimer = htole(p->LatencyTimer); 99 config.headerType = htole(p->HeaderType); 100 config.bist = htole(p->BIST); 101 102 config.baseAddr[0] = htole(p->BAR0); 103 config.baseAddr[1] = htole(p->BAR1); 104 config.baseAddr[2] = htole(p->BAR2); 105 config.baseAddr[3] = htole(p->BAR3); 106 config.baseAddr[4] = htole(p->BAR4); 107 config.baseAddr[5] = htole(p->BAR5); 108 config.cardbusCIS = htole(p->CardbusCIS); 109 config.subsystemVendorID = htole(p->SubsystemVendorID); 110 config.subsystemID = htole(p->SubsystemID); 111 config.expansionROM = htole(p->ExpansionROM); 112 config.capabilityPtr = htole(p->CapabilityPtr); 113 // Zero out the 7 bytes of reserved space in the PCI Config space register. 114 bzero(config.reserved, 7*sizeof(uint8_t)); 115 config.interruptLine = htole(p->InterruptLine); 116 config.interruptPin = htole(p->InterruptPin); 117 config.minimumGrant = htole(p->MinimumGrant); 118 config.maximumLatency = htole(p->MaximumLatency); 119 120 // Initialize the capability lists 121 // These structs are bitunions, meaning the data is stored in host 122 // endianess and must be converted to Little Endian when accessed 123 // by the guest 124 // PMCAP 125 pmcap.pid = (uint16_t)p->PMCAPCapId; // pid.cid 126 pmcap.pid |= (uint16_t)p->PMCAPNextCapability << 8; //pid.next 127 pmcap.pc = p->PMCAPCapabilities; 128 pmcap.pmcs = p->PMCAPCtrlStatus; 129 130 // MSICAP 131 msicap.mid = (uint16_t)p->MSICAPCapId; //mid.cid 132 msicap.mid |= (uint16_t)p->MSICAPNextCapability << 8; //mid.next 133 msicap.mc = p->MSICAPMsgCtrl; 134 msicap.ma = p->MSICAPMsgAddr; 135 msicap.mua = p->MSICAPMsgUpperAddr; 136 msicap.md = p->MSICAPMsgData; 137 msicap.mmask = p->MSICAPMaskBits; 138 msicap.mpend = p->MSICAPPendingBits; 139 140 // MSIXCAP 141 msixcap.mxid = (uint16_t)p->MSIXCAPCapId; //mxid.cid 142 msixcap.mxid |= (uint16_t)p->MSIXCAPNextCapability << 8; //mxid.next 143 msixcap.mxc = p->MSIXMsgCtrl; 144 msixcap.mtab = p->MSIXTableOffset; 145 msixcap.mpba = p->MSIXPbaOffset; 146 147 // allocate MSIX structures if MSIXCAP_BASE 148 // indicates the MSIXCAP is being used by having a 149 // non-zero base address. 150 // The MSIX tables are stored by the guest in 151 // little endian byte-order as according the 152 // PCIe specification. Make sure to take the proper 153 // actions when manipulating these tables on the host 154 uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff; 155 if (MSIXCAP_BASE != 0x0) { 156 int msix_vecs = msixcap_mxc_ts + 1; 157 MSIXTable tmp1 = {{0UL,0UL,0UL,0UL}}; 158 msix_table.resize(msix_vecs, tmp1); 159 160 MSIXPbaEntry tmp2 = {0}; 161 int pba_size = msix_vecs / MSIXVECS_PER_PBA; 162 if ((msix_vecs % MSIXVECS_PER_PBA) > 0) { 163 pba_size++; 164 } 165 msix_pba.resize(pba_size, tmp2); 166 } 167 MSIX_TABLE_OFFSET = msixcap.mtab & 0xfffffffc; 168 MSIX_TABLE_END = MSIX_TABLE_OFFSET + 169 (msixcap_mxc_ts + 1) * sizeof(MSIXTable); 170 MSIX_PBA_OFFSET = msixcap.mpba & 0xfffffffc; 171 MSIX_PBA_END = MSIX_PBA_OFFSET + 172 ((msixcap_mxc_ts + 1) / MSIXVECS_PER_PBA) 173 * sizeof(MSIXPbaEntry); 174 if (((msixcap_mxc_ts + 1) % MSIXVECS_PER_PBA) > 0) { 175 MSIX_PBA_END += sizeof(MSIXPbaEntry); 176 } 177 178 // PXCAP 179 pxcap.pxid = (uint16_t)p->PXCAPCapId; //pxid.cid 180 pxcap.pxid |= (uint16_t)p->PXCAPNextCapability << 8; //pxid.next 181 pxcap.pxcap = p->PXCAPCapabilities; 182 pxcap.pxdcap = p->PXCAPDevCapabilities; 183 pxcap.pxdc = p->PXCAPDevCtrl; 184 pxcap.pxds = p->PXCAPDevStatus; 185 pxcap.pxlcap = p->PXCAPLinkCap; 186 pxcap.pxlc = p->PXCAPLinkCtrl; 187 pxcap.pxls = p->PXCAPLinkStatus; 188 pxcap.pxdcap2 = p->PXCAPDevCap2; 189 pxcap.pxdc2 = p->PXCAPDevCtrl2; 190 191 BARSize[0] = p->BAR0Size; 192 BARSize[1] = p->BAR1Size; 193 BARSize[2] = p->BAR2Size; 194 BARSize[3] = p->BAR3Size; 195 BARSize[4] = p->BAR4Size; 196 BARSize[5] = p->BAR5Size; 197 198 legacyIO[0] = p->BAR0LegacyIO; 199 legacyIO[1] = p->BAR1LegacyIO; 200 legacyIO[2] = p->BAR2LegacyIO; 201 legacyIO[3] = p->BAR3LegacyIO; 202 legacyIO[4] = p->BAR4LegacyIO; 203 legacyIO[5] = p->BAR5LegacyIO; 204 205 for (int i = 0; i < 6; ++i) { 206 if (legacyIO[i]) { 207 BARAddrs[i] = p->LegacyIOBase + letoh(config.baseAddr[i]); 208 config.baseAddr[i] = 0; 209 } else { 210 BARAddrs[i] = 0; 211 uint32_t barsize = BARSize[i]; 212 if (barsize != 0 && !isPowerOf2(barsize)) { 213 fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]); 214 } 215 } 216 } 217} 218 219Tick 220PciDevice::readConfig(PacketPtr pkt) 221{ 222 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 223 224 /* Return 0 for accesses to unimplemented PCI configspace areas */ 225 if (offset >= PCI_DEVICE_SPECIFIC && 226 offset < PCI_CONFIG_SIZE) { 227 warn_once("Device specific PCI config space " 228 "not implemented for %s!\n", this->name()); 229 switch (pkt->getSize()) { 230 case sizeof(uint8_t): 231 pkt->setLE<uint8_t>(0); 232 break; 233 case sizeof(uint16_t): 234 pkt->setLE<uint16_t>(0); 235 break; 236 case sizeof(uint32_t): 237 pkt->setLE<uint32_t>(0); 238 break; 239 default: 240 panic("invalid access size(?) for PCI configspace!\n"); 241 } 242 } else if (offset > PCI_CONFIG_SIZE) { 243 panic("Out-of-range access to PCI config space!\n"); 244 } 245 246 switch (pkt->getSize()) { 247 case sizeof(uint8_t): 248 pkt->setLE<uint8_t>(config.data[offset]); 249 DPRINTF(PciDevice, 250 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 251 _busAddr.dev, _busAddr.func, offset, 252 (uint32_t)pkt->getLE<uint8_t>()); 253 break; 254 case sizeof(uint16_t): 255 pkt->setLE<uint16_t>(*(uint16_t*)&config.data[offset]); 256 DPRINTF(PciDevice, 257 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 258 _busAddr.dev, _busAddr.func, offset, 259 (uint32_t)pkt->getLE<uint16_t>()); 260 break; 261 case sizeof(uint32_t): 262 pkt->setLE<uint32_t>(*(uint32_t*)&config.data[offset]); 263 DPRINTF(PciDevice, 264 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 265 _busAddr.dev, _busAddr.func, offset, 266 (uint32_t)pkt->getLE<uint32_t>()); 267 break; 268 default: 269 panic("invalid access size(?) for PCI configspace!\n"); 270 } 271 pkt->makeAtomicResponse(); 272 return configDelay; 273 274} 275 276AddrRangeList 277PciDevice::getAddrRanges() const 278{ 279 AddrRangeList ranges; 280 int x = 0; 281 for (x = 0; x < 6; x++) 282 if (BARAddrs[x] != 0) 283 ranges.push_back(RangeSize(BARAddrs[x],BARSize[x])); 284 return ranges; 285} 286 287Tick 288PciDevice::writeConfig(PacketPtr pkt) 289{ 290 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 291 292 /* No effect if we write to config space that is not implemented*/ 293 if (offset >= PCI_DEVICE_SPECIFIC && 294 offset < PCI_CONFIG_SIZE) { 295 warn_once("Device specific PCI config space " 296 "not implemented for %s!\n", this->name()); 297 switch (pkt->getSize()) { 298 case sizeof(uint8_t): 299 case sizeof(uint16_t): 300 case sizeof(uint32_t): 301 break; 302 default: 303 panic("invalid access size(?) for PCI configspace!\n"); 304 } 305 } else if (offset > PCI_CONFIG_SIZE) { 306 panic("Out-of-range access to PCI config space!\n"); 307 } 308 309 switch (pkt->getSize()) { 310 case sizeof(uint8_t): 311 switch (offset) { 312 case PCI0_INTERRUPT_LINE: 313 config.interruptLine = pkt->getLE<uint8_t>(); 314 break; 315 case PCI_CACHE_LINE_SIZE: 316 config.cacheLineSize = pkt->getLE<uint8_t>(); 317 break; 318 case PCI_LATENCY_TIMER: 319 config.latencyTimer = pkt->getLE<uint8_t>(); 320 break; 321 /* Do nothing for these read-only registers */ 322 case PCI0_INTERRUPT_PIN: 323 case PCI0_MINIMUM_GRANT: 324 case PCI0_MAXIMUM_LATENCY: 325 case PCI_CLASS_CODE: 326 case PCI_REVISION_ID: 327 break; 328 default: 329 panic("writing to a read only register"); 330 } 331 DPRINTF(PciDevice, 332 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 333 _busAddr.dev, _busAddr.func, offset, 334 (uint32_t)pkt->getLE<uint8_t>()); 335 break; 336 case sizeof(uint16_t): 337 switch (offset) { 338 case PCI_COMMAND: 339 config.command = pkt->getLE<uint8_t>(); 340 break; 341 case PCI_STATUS: 342 config.status = pkt->getLE<uint8_t>(); 343 break; 344 case PCI_CACHE_LINE_SIZE: 345 config.cacheLineSize = pkt->getLE<uint8_t>(); 346 break; 347 default: 348 panic("writing to a read only register"); 349 } 350 DPRINTF(PciDevice, 351 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 352 _busAddr.dev, _busAddr.func, offset, 353 (uint32_t)pkt->getLE<uint16_t>()); 354 break; 355 case sizeof(uint32_t): 356 switch (offset) { 357 case PCI0_BASE_ADDR0: 358 case PCI0_BASE_ADDR1: 359 case PCI0_BASE_ADDR2: 360 case PCI0_BASE_ADDR3: 361 case PCI0_BASE_ADDR4: 362 case PCI0_BASE_ADDR5: 363 { 364 int barnum = BAR_NUMBER(offset); 365 366 if (!legacyIO[barnum]) { 367 // convert BAR values to host endianness 368 uint32_t he_old_bar = letoh(config.baseAddr[barnum]); 369 uint32_t he_new_bar = letoh(pkt->getLE<uint32_t>()); 370 371 uint32_t bar_mask = 372 BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK; 373 374 // Writing 0xffffffff to a BAR tells the card to set the 375 // value of the bar to a bitmask indicating the size of 376 // memory it needs 377 if (he_new_bar == 0xffffffff) { 378 he_new_bar = ~(BARSize[barnum] - 1); 379 } else { 380 // does it mean something special to write 0 to a BAR? 381 he_new_bar &= ~bar_mask; 382 if (he_new_bar) { 383 BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ? 384 hostInterface.pioAddr(he_new_bar) : 385 hostInterface.memAddr(he_new_bar); 386 pioPort.sendRangeChange(); 387 } 388 } 389 config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) | 390 (he_old_bar & bar_mask)); 391 } 392 } 393 break; 394 395 case PCI0_ROM_BASE_ADDR: 396 if (letoh(pkt->getLE<uint32_t>()) == 0xfffffffe) 397 config.expansionROM = htole((uint32_t)0xffffffff); 398 else 399 config.expansionROM = pkt->getLE<uint32_t>(); 400 break; 401 402 case PCI_COMMAND: 403 // This could also clear some of the error bits in the Status 404 // register. However they should never get set, so lets ignore 405 // it for now 406 config.command = pkt->getLE<uint32_t>(); 407 break; 408 409 default: 410 DPRINTF(PciDevice, "Writing to a read only register"); 411 } 412 DPRINTF(PciDevice, 413 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 414 _busAddr.dev, _busAddr.func, offset, 415 (uint32_t)pkt->getLE<uint32_t>()); 416 break; 417 default: 418 panic("invalid access size(?) for PCI configspace!\n"); 419 } 420 pkt->makeAtomicResponse(); 421 return configDelay; 422} 423 424void 425PciDevice::serialize(CheckpointOut &cp) const 426{ 427 SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 428 SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 429 SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); 430 431 // serialize the capability list registers 432 paramOut(cp, csprintf("pmcap.pid"), uint16_t(pmcap.pid)); 433 paramOut(cp, csprintf("pmcap.pc"), uint16_t(pmcap.pc)); 434 paramOut(cp, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs)); 435 436 paramOut(cp, csprintf("msicap.mid"), uint16_t(msicap.mid)); 437 paramOut(cp, csprintf("msicap.mc"), uint16_t(msicap.mc)); 438 paramOut(cp, csprintf("msicap.ma"), uint32_t(msicap.ma)); 439 SERIALIZE_SCALAR(msicap.mua); 440 paramOut(cp, csprintf("msicap.md"), uint16_t(msicap.md)); 441 SERIALIZE_SCALAR(msicap.mmask); 442 SERIALIZE_SCALAR(msicap.mpend); 443 444 paramOut(cp, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid)); 445 paramOut(cp, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc)); 446 paramOut(cp, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab)); 447 paramOut(cp, csprintf("msixcap.mpba"), uint32_t(msixcap.mpba)); 448 449 // Only serialize if we have a non-zero base address 450 if (MSIXCAP_BASE != 0x0) { 451 uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff; 452 int msix_array_size = msixcap_mxc_ts + 1; 453 int pba_array_size = msix_array_size/MSIXVECS_PER_PBA; 454 if ((msix_array_size % MSIXVECS_PER_PBA) > 0) { 455 pba_array_size++; 456 } 457 458 SERIALIZE_SCALAR(msix_array_size); 459 SERIALIZE_SCALAR(pba_array_size); 460 461 for (int i = 0; i < msix_array_size; i++) { 462 paramOut(cp, csprintf("msix_table[%d].addr_lo", i), 463 msix_table[i].fields.addr_lo); 464 paramOut(cp, csprintf("msix_table[%d].addr_hi", i), 465 msix_table[i].fields.addr_hi); 466 paramOut(cp, csprintf("msix_table[%d].msg_data", i), 467 msix_table[i].fields.msg_data); 468 paramOut(cp, csprintf("msix_table[%d].vec_ctrl", i), 469 msix_table[i].fields.vec_ctrl); 470 } 471 for (int i = 0; i < pba_array_size; i++) { 472 paramOut(cp, csprintf("msix_pba[%d].bits", i), 473 msix_pba[i].bits); 474 } 475 } 476 477 paramOut(cp, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid)); 478 paramOut(cp, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap)); 479 paramOut(cp, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap)); 480 paramOut(cp, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc)); 481 paramOut(cp, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds)); 482 paramOut(cp, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap)); 483 paramOut(cp, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc)); 484 paramOut(cp, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls)); 485 paramOut(cp, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2)); 486 paramOut(cp, csprintf("pxcap.pxdc2"), uint32_t(pxcap.pxdc2)); 487} 488 489void 490PciDevice::unserialize(CheckpointIn &cp) 491{ 492 UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 493 UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 494 UNSERIALIZE_ARRAY(config.data, 495 sizeof(config.data) / sizeof(config.data[0])); 496 497 // unserialize the capability list registers 498 uint16_t tmp16; 499 uint32_t tmp32; 500 paramIn(cp, csprintf("pmcap.pid"), tmp16); 501 pmcap.pid = tmp16; 502 paramIn(cp, csprintf("pmcap.pc"), tmp16); 503 pmcap.pc = tmp16; 504 paramIn(cp, csprintf("pmcap.pmcs"), tmp16); 505 pmcap.pmcs = tmp16; 506 507 paramIn(cp, csprintf("msicap.mid"), tmp16); 508 msicap.mid = tmp16; 509 paramIn(cp, csprintf("msicap.mc"), tmp16); 510 msicap.mc = tmp16; 511 paramIn(cp, csprintf("msicap.ma"), tmp32); 512 msicap.ma = tmp32; 513 UNSERIALIZE_SCALAR(msicap.mua); 514 paramIn(cp, csprintf("msicap.md"), tmp16);; 515 msicap.md = tmp16; 516 UNSERIALIZE_SCALAR(msicap.mmask); 517 UNSERIALIZE_SCALAR(msicap.mpend); 518 519 paramIn(cp, csprintf("msixcap.mxid"), tmp16); 520 msixcap.mxid = tmp16; 521 paramIn(cp, csprintf("msixcap.mxc"), tmp16); 522 msixcap.mxc = tmp16; 523 paramIn(cp, csprintf("msixcap.mtab"), tmp32); 524 msixcap.mtab = tmp32; 525 paramIn(cp, csprintf("msixcap.mpba"), tmp32); 526 msixcap.mpba = tmp32; 527 528 // Only allocate if MSIXCAP_BASE is not 0x0 529 if (MSIXCAP_BASE != 0x0) { 530 int msix_array_size; 531 int pba_array_size; 532 533 UNSERIALIZE_SCALAR(msix_array_size); 534 UNSERIALIZE_SCALAR(pba_array_size); 535 536 MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}}; 537 msix_table.resize(msix_array_size, tmp1); 538 539 MSIXPbaEntry tmp2 = {0}; 540 msix_pba.resize(pba_array_size, tmp2); 541 542 for (int i = 0; i < msix_array_size; i++) { 543 paramIn(cp, csprintf("msix_table[%d].addr_lo", i), 544 msix_table[i].fields.addr_lo); 545 paramIn(cp, csprintf("msix_table[%d].addr_hi", i), 546 msix_table[i].fields.addr_hi); 547 paramIn(cp, csprintf("msix_table[%d].msg_data", i), 548 msix_table[i].fields.msg_data); 549 paramIn(cp, csprintf("msix_table[%d].vec_ctrl", i), 550 msix_table[i].fields.vec_ctrl); 551 } 552 for (int i = 0; i < pba_array_size; i++) { 553 paramIn(cp, csprintf("msix_pba[%d].bits", i), 554 msix_pba[i].bits); 555 } 556 } 557 558 paramIn(cp, csprintf("pxcap.pxid"), tmp16); 559 pxcap.pxid = tmp16; 560 paramIn(cp, csprintf("pxcap.pxcap"), tmp16); 561 pxcap.pxcap = tmp16; 562 paramIn(cp, csprintf("pxcap.pxdcap"), tmp32); 563 pxcap.pxdcap = tmp32; 564 paramIn(cp, csprintf("pxcap.pxdc"), tmp16); 565 pxcap.pxdc = tmp16; 566 paramIn(cp, csprintf("pxcap.pxds"), tmp16); 567 pxcap.pxds = tmp16; 568 paramIn(cp, csprintf("pxcap.pxlcap"), tmp32); 569 pxcap.pxlcap = tmp32; 570 paramIn(cp, csprintf("pxcap.pxlc"), tmp16); 571 pxcap.pxlc = tmp16; 572 paramIn(cp, csprintf("pxcap.pxls"), tmp16); 573 pxcap.pxls = tmp16; 574 paramIn(cp, csprintf("pxcap.pxdcap2"), tmp32); 575 pxcap.pxdcap2 = tmp32; 576 paramIn(cp, csprintf("pxcap.pxdc2"), tmp32); 577 pxcap.pxdc2 = tmp32; 578 pioPort.sendRangeChange(); 579} 580 581