device.cc revision 9957
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->busFirstWordDelay = pkt->busLastWordDelay = 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 MSICAP_BASE(p->MSICAPBaseOffset), 101 MSIXCAP_BASE(p->MSIXCAPBaseOffset), 102 PXCAP_BASE(p->PXCAPBaseOffset), 103 platform(p->platform), 104 pioDelay(p->pio_latency), 105 configDelay(p->config_latency), 106 configPort(this, params()->pci_bus, params()->pci_dev, 107 params()->pci_func, params()->platform) 108{ 109 config.vendor = htole(p->VendorID); 110 config.device = htole(p->DeviceID); 111 config.command = htole(p->Command); 112 config.status = htole(p->Status); 113 config.revision = htole(p->Revision); 114 config.progIF = htole(p->ProgIF); 115 config.subClassCode = htole(p->SubClassCode); 116 config.classCode = htole(p->ClassCode); 117 config.cacheLineSize = htole(p->CacheLineSize); 118 config.latencyTimer = htole(p->LatencyTimer); 119 config.headerType = htole(p->HeaderType); 120 config.bist = htole(p->BIST); 121 122 config.baseAddr[0] = htole(p->BAR0); 123 config.baseAddr[1] = htole(p->BAR1); 124 config.baseAddr[2] = htole(p->BAR2); 125 config.baseAddr[3] = htole(p->BAR3); 126 config.baseAddr[4] = htole(p->BAR4); 127 config.baseAddr[5] = htole(p->BAR5); 128 config.cardbusCIS = htole(p->CardbusCIS); 129 config.subsystemVendorID = htole(p->SubsystemVendorID); 130 config.subsystemID = htole(p->SubsystemID); 131 config.expansionROM = htole(p->ExpansionROM); 132 config.capabilityPtr = htole(p->CapabilityPtr); 133 // Zero out the 7 bytes of reserved space in the PCI Config space register. 134 bzero(config.reserved, 7*sizeof(uint8_t)); 135 config.interruptLine = htole(p->InterruptLine); 136 config.interruptPin = htole(p->InterruptPin); 137 config.minimumGrant = htole(p->MinimumGrant); 138 config.maximumLatency = htole(p->MaximumLatency); 139 140 // Initialize the capability lists 141 // These structs are bitunions, meaning the data is stored in host 142 // endianess and must be converted to Little Endian when accessed 143 // by the guest 144 // PMCAP 145 pmcap.pid.cid = p->PMCAPCapId; 146 pmcap.pid.next = p->PMCAPNextCapability; 147 pmcap.pc = p->PMCAPCapabilities; 148 pmcap.pmcs = p->PMCAPCtrlStatus; 149 150 // MSICAP 151 msicap.mid.cid = p->MSICAPCapId; 152 msicap.mid.next = p->MSICAPNextCapability; 153 msicap.mc = p->MSICAPMsgCtrl; 154 msicap.ma = p->MSICAPMsgAddr; 155 msicap.mua = p->MSICAPMsgUpperAddr; 156 msicap.md = p->MSICAPMsgData; 157 msicap.mmask = p->MSICAPMaskBits; 158 msicap.mpend = p->MSICAPPendingBits; 159 160 // MSIXCAP 161 msixcap.mxid.cid = p->MSIXCAPCapId; 162 msixcap.mxid.next = p->MSIXCAPNextCapability; 163 msixcap.mxc = p->MSIXMsgCtrl; 164 msixcap.mtab = p->MSIXTableOffset; 165 msixcap.mpba = p->MSIXPbaOffset; 166 167 // allocate MSIX structures if MSIXCAP_BASE 168 // indicates the MSIXCAP is being used by having a 169 // non-zero base address. 170 // The MSIX tables are stored by the guest in 171 // little endian byte-order as according the 172 // PCIe specification. Make sure to take the proper 173 // actions when manipulating these tables on the host 174 if (MSIXCAP_BASE != 0x0) { 175 int msix_vecs = msixcap.mxc.ts + 1; 176 MSIXTable tmp1 = {{0UL,0UL,0UL,0UL}}; 177 msix_table.resize(msix_vecs, tmp1); 178 179 MSIXPbaEntry tmp2 = {0}; 180 int pba_size = msix_vecs / MSIXVECS_PER_PBA; 181 if ((msix_vecs % MSIXVECS_PER_PBA) > 0) { 182 pba_size++; 183 } 184 msix_pba.resize(pba_size, tmp2); 185 } 186 187 // PXCAP 188 pxcap.pxid.cid = p->PXCAPCapId; 189 pxcap.pxid.next = p->PXCAPNextCapability; 190 pxcap.pxcap = p->PXCAPCapabilities; 191 pxcap.pxdcap = p->PXCAPDevCapabilities; 192 pxcap.pxdc = p->PXCAPDevCtrl; 193 pxcap.pxds = p->PXCAPDevStatus; 194 pxcap.pxlcap = p->PXCAPLinkCap; 195 pxcap.pxlc = p->PXCAPLinkCtrl; 196 pxcap.pxls = p->PXCAPLinkStatus; 197 pxcap.pxdcap2 = p->PXCAPDevCap2; 198 pxcap.pxdc2 = p->PXCAPDevCtrl2; 199 200 BARSize[0] = p->BAR0Size; 201 BARSize[1] = p->BAR1Size; 202 BARSize[2] = p->BAR2Size; 203 BARSize[3] = p->BAR3Size; 204 BARSize[4] = p->BAR4Size; 205 BARSize[5] = p->BAR5Size; 206 207 legacyIO[0] = p->BAR0LegacyIO; 208 legacyIO[1] = p->BAR1LegacyIO; 209 legacyIO[2] = p->BAR2LegacyIO; 210 legacyIO[3] = p->BAR3LegacyIO; 211 legacyIO[4] = p->BAR4LegacyIO; 212 legacyIO[5] = p->BAR5LegacyIO; 213 214 for (int i = 0; i < 6; ++i) { 215 if (legacyIO[i]) { 216 BARAddrs[i] = platform->calcPciIOAddr(letoh(config.baseAddr[i])); 217 config.baseAddr[i] = 0; 218 } else { 219 BARAddrs[i] = 0; 220 uint32_t barsize = BARSize[i]; 221 if (barsize != 0 && !isPowerOf2(barsize)) { 222 fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]); 223 } 224 } 225 } 226 227 platform->registerPciDevice(p->pci_bus, p->pci_dev, p->pci_func, 228 letoh(config.interruptLine)); 229} 230 231void 232PciDevice::init() 233{ 234 if (!configPort.isConnected()) 235 panic("PCI config port on %s not connected to anything!\n", name()); 236 configPort.sendRangeChange(); 237 DmaDevice::init(); 238} 239 240unsigned int 241PciDevice::drain(DrainManager *dm) 242{ 243 unsigned int count; 244 count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm); 245 if (count) 246 setDrainState(Drainable::Draining); 247 else 248 setDrainState(Drainable::Drained); 249 return count; 250} 251 252Tick 253PciDevice::readConfig(PacketPtr pkt) 254{ 255 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 256 if (offset >= PCI_DEVICE_SPECIFIC) 257 panic("Device specific PCI config space not implemented!\n"); 258 259 pkt->allocate(); 260 261 switch (pkt->getSize()) { 262 case sizeof(uint8_t): 263 pkt->set<uint8_t>(config.data[offset]); 264 DPRINTF(PCIDEV, 265 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 266 params()->pci_dev, params()->pci_func, offset, 267 (uint32_t)pkt->get<uint8_t>()); 268 break; 269 case sizeof(uint16_t): 270 pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]); 271 DPRINTF(PCIDEV, 272 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 273 params()->pci_dev, params()->pci_func, offset, 274 (uint32_t)pkt->get<uint16_t>()); 275 break; 276 case sizeof(uint32_t): 277 pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]); 278 DPRINTF(PCIDEV, 279 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 280 params()->pci_dev, params()->pci_func, offset, 281 (uint32_t)pkt->get<uint32_t>()); 282 break; 283 default: 284 panic("invalid access size(?) for PCI configspace!\n"); 285 } 286 pkt->makeAtomicResponse(); 287 return configDelay; 288 289} 290 291AddrRangeList 292PciDevice::getAddrRanges() const 293{ 294 AddrRangeList ranges; 295 int x = 0; 296 for (x = 0; x < 6; x++) 297 if (BARAddrs[x] != 0) 298 ranges.push_back(RangeSize(BARAddrs[x],BARSize[x])); 299 return ranges; 300} 301 302Tick 303PciDevice::writeConfig(PacketPtr pkt) 304{ 305 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 306 if (offset >= PCI_DEVICE_SPECIFIC) 307 panic("Device specific PCI config space not implemented!\n"); 308 309 switch (pkt->getSize()) { 310 case sizeof(uint8_t): 311 switch (offset) { 312 case PCI0_INTERRUPT_LINE: 313 config.interruptLine = pkt->get<uint8_t>(); 314 break; 315 case PCI_CACHE_LINE_SIZE: 316 config.cacheLineSize = pkt->get<uint8_t>(); 317 break; 318 case PCI_LATENCY_TIMER: 319 config.latencyTimer = pkt->get<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(PCIDEV, 332 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 333 params()->pci_dev, params()->pci_func, offset, 334 (uint32_t)pkt->get<uint8_t>()); 335 break; 336 case sizeof(uint16_t): 337 switch (offset) { 338 case PCI_COMMAND: 339 config.command = pkt->get<uint8_t>(); 340 break; 341 case PCI_STATUS: 342 config.status = pkt->get<uint8_t>(); 343 break; 344 case PCI_CACHE_LINE_SIZE: 345 config.cacheLineSize = pkt->get<uint8_t>(); 346 break; 347 default: 348 panic("writing to a read only register"); 349 } 350 DPRINTF(PCIDEV, 351 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 352 params()->pci_dev, params()->pci_func, offset, 353 (uint32_t)pkt->get<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->get<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 platform->calcPciIOAddr(he_new_bar) : 385 platform->calcPciMemAddr(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->get<uint32_t>()) == 0xfffffffe) 397 config.expansionROM = htole((uint32_t)0xffffffff); 398 else 399 config.expansionROM = pkt->get<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->get<uint32_t>(); 407 break; 408 409 default: 410 DPRINTF(PCIDEV, "Writing to a read only register"); 411 } 412 DPRINTF(PCIDEV, 413 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 414 params()->pci_dev, params()->pci_func, offset, 415 (uint32_t)pkt->get<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(std::ostream &os) 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(os, csprintf("pmcap.pid"), uint16_t(pmcap.pid)); 433 paramOut(os, csprintf("pmcap.pc"), uint16_t(pmcap.pc)); 434 paramOut(os, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs)); 435 436 paramOut(os, csprintf("msicap.mid"), uint16_t(msicap.mid)); 437 paramOut(os, csprintf("msicap.mc"), uint16_t(msicap.mc)); 438 paramOut(os, csprintf("msicap.ma"), uint32_t(msicap.ma)); 439 SERIALIZE_SCALAR(msicap.mua); 440 paramOut(os, csprintf("msicap.md"), uint16_t(msicap.md)); 441 SERIALIZE_SCALAR(msicap.mmask); 442 SERIALIZE_SCALAR(msicap.mpend); 443 444 paramOut(os, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid)); 445 paramOut(os, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc)); 446 paramOut(os, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab)); 447 paramOut(os, 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 int msix_array_size = msixcap.mxc.ts + 1; 452 int pba_array_size = msix_array_size/MSIXVECS_PER_PBA; 453 if ((msix_array_size % MSIXVECS_PER_PBA) > 0) { 454 pba_array_size++; 455 } 456 457 SERIALIZE_SCALAR(msix_array_size); 458 SERIALIZE_SCALAR(pba_array_size); 459 460 for (int i = 0; i < msix_array_size; i++) { 461 paramOut(os, csprintf("msix_table[%d].addr_lo", i), 462 msix_table[i].fields.addr_lo); 463 paramOut(os, csprintf("msix_table[%d].addr_hi", i), 464 msix_table[i].fields.addr_hi); 465 paramOut(os, csprintf("msix_table[%d].msg_data", i), 466 msix_table[i].fields.msg_data); 467 paramOut(os, csprintf("msix_table[%d].vec_ctrl", i), 468 msix_table[i].fields.vec_ctrl); 469 } 470 for (int i = 0; i < pba_array_size; i++) { 471 paramOut(os, csprintf("msix_pba[%d].bits", i), 472 msix_pba[i].bits); 473 } 474 } 475 476 paramOut(os, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid)); 477 paramOut(os, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap)); 478 paramOut(os, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap)); 479 paramOut(os, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc)); 480 paramOut(os, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds)); 481 paramOut(os, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap)); 482 paramOut(os, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc)); 483 paramOut(os, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls)); 484 paramOut(os, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2)); 485 paramOut(os, csprintf("pxcap.pxdc2"), uint32_t(pxcap.pxdc2)); 486} 487 488void 489PciDevice::unserialize(Checkpoint *cp, const std::string §ion) 490{ 491 UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 492 UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 493 UNSERIALIZE_ARRAY(config.data, 494 sizeof(config.data) / sizeof(config.data[0])); 495 496 // unserialize the capability list registers 497 uint16_t tmp16; 498 uint32_t tmp32; 499 paramIn(cp, section, csprintf("pmcap.pid"), tmp16); 500 pmcap.pid = tmp16; 501 paramIn(cp, section, csprintf("pmcap.pc"), tmp16); 502 pmcap.pc = tmp16; 503 paramIn(cp, section, csprintf("pmcap.pmcs"), tmp16); 504 pmcap.pmcs = tmp16; 505 506 paramIn(cp, section, csprintf("msicap.mid"), tmp16); 507 msicap.mid = tmp16; 508 paramIn(cp, section, csprintf("msicap.mc"), tmp16); 509 msicap.mc = tmp16; 510 paramIn(cp, section, csprintf("msicap.ma"), tmp32); 511 msicap.ma = tmp32; 512 UNSERIALIZE_SCALAR(msicap.mua); 513 paramIn(cp, section, csprintf("msicap.md"), tmp16);; 514 msicap.md = tmp16; 515 UNSERIALIZE_SCALAR(msicap.mmask); 516 UNSERIALIZE_SCALAR(msicap.mpend); 517 518 paramIn(cp, section, csprintf("msixcap.mxid"), tmp16); 519 msixcap.mxid = tmp16; 520 paramIn(cp, section, csprintf("msixcap.mxc"), tmp16); 521 msixcap.mxc = tmp16; 522 paramIn(cp, section, csprintf("msixcap.mtab"), tmp32); 523 msixcap.mtab = tmp32; 524 paramIn(cp, section, csprintf("msixcap.mpba"), tmp32); 525 msixcap.mpba = tmp32; 526 527 // Only allocate if MSIXCAP_BASE is not 0x0 528 if (MSIXCAP_BASE != 0x0) { 529 int msix_array_size; 530 int pba_array_size; 531 532 UNSERIALIZE_SCALAR(msix_array_size); 533 UNSERIALIZE_SCALAR(pba_array_size); 534 535 MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}}; 536 msix_table.resize(msix_array_size, tmp1); 537 538 MSIXPbaEntry tmp2 = {0}; 539 msix_pba.resize(pba_array_size, tmp2); 540 541 for (int i = 0; i < msix_array_size; i++) { 542 paramIn(cp, section, csprintf("msix_table[%d].addr_lo", i), 543 msix_table[i].fields.addr_lo); 544 paramIn(cp, section, csprintf("msix_table[%d].addr_hi", i), 545 msix_table[i].fields.addr_hi); 546 paramIn(cp, section, csprintf("msix_table[%d].msg_data", i), 547 msix_table[i].fields.msg_data); 548 paramIn(cp, section, csprintf("msix_table[%d].vec_ctrl", i), 549 msix_table[i].fields.vec_ctrl); 550 } 551 for (int i = 0; i < pba_array_size; i++) { 552 paramIn(cp, section, csprintf("msix_pba[%d].bits", i), 553 msix_pba[i].bits); 554 } 555 } 556 557 paramIn(cp, section, csprintf("pxcap.pxid"), tmp16); 558 pxcap.pxid = tmp16; 559 paramIn(cp, section, csprintf("pxcap.pxcap"), tmp16); 560 pxcap.pxcap = tmp16; 561 paramIn(cp, section, csprintf("pxcap.pxdcap"), tmp32); 562 pxcap.pxdcap = tmp32; 563 paramIn(cp, section, csprintf("pxcap.pxdc"), tmp16); 564 pxcap.pxdc = tmp16; 565 paramIn(cp, section, csprintf("pxcap.pxds"), tmp16); 566 pxcap.pxds = tmp16; 567 paramIn(cp, section, csprintf("pxcap.pxlcap"), tmp32); 568 pxcap.pxlcap = tmp32; 569 paramIn(cp, section, csprintf("pxcap.pxlc"), tmp16); 570 pxcap.pxlc = tmp16; 571 paramIn(cp, section, csprintf("pxcap.pxls"), tmp16); 572 pxcap.pxls = tmp16; 573 paramIn(cp, section, csprintf("pxcap.pxdcap2"), tmp32); 574 pxcap.pxdcap2 = tmp32; 575 paramIn(cp, section, csprintf("pxcap.pxdc2"), tmp32); 576 pxcap.pxdc2 = tmp32; 577 pioPort.sendRangeChange(); 578} 579 580