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