2 * Copyright (c) 2013 ARM Limited
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.
14 * Copyright (c) 2004-2005 The Regents of The University of Michigan
15 * All rights reserved.
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.
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.
46 * A single PCI device configuration space entry.
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"
68 PciDevice::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
)
73 configAddr
= platform
->calcPciConfigAddr(busId
, deviceId
, functionId
);
78 PciDevice::PciConfigPort::recvAtomic(PacketPtr pkt
)
80 assert(pkt
->getAddr() >= configAddr
&&
81 pkt
->getAddr() < configAddr
+ PCI_CONFIG_SIZE
);
82 // @todo someone should pay for this
83 pkt
->headerDelay
= pkt
->payloadDelay
= 0;
84 return pkt
->isRead() ? device
->readConfig(pkt
) : device
->writeConfig(pkt
);
88 PciDevice::PciConfigPort::getAddrRanges() const
91 if (configAddr
!= ULL(-1))
92 ranges
.push_back(RangeSize(configAddr
, PCI_CONFIG_SIZE
+1));
97 PciDevice::PciDevice(const Params
*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
)
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
);
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
);
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
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
;
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
;
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
;
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
);
187 MSIXPbaEntry tmp2
= {0};
188 int pba_size
= msix_vecs
/ MSIXVECS_PER_PBA
;
189 if ((msix_vecs
% MSIXVECS_PER_PBA
) > 0) {
192 msix_pba
.resize(pba_size
, tmp2
);
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
);
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
;
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
;
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
;
232 for (int i
= 0; i
< 6; ++i
) {
234 BARAddrs
[i
] = p
->LegacyIOBase
+ letoh(config
.baseAddr
[i
]);
235 config
.baseAddr
[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
]);
245 platform
->registerPciDevice(p
->pci_bus
, p
->pci_dev
, p
->pci_func
,
246 letoh(config
.interruptLine
));
252 if (!configPort
.isConnected())
253 panic("PCI config port on %s not connected to anything!\n", name());
254 configPort
.sendRangeChange();
259 PciDevice::drain(DrainManager
*dm
)
262 count
= pioPort
.drain(dm
) + dmaPort
.drain(dm
) + configPort
.drain(dm
);
264 setDrainState(Drainable::Draining
);
266 setDrainState(Drainable::Drained
);
271 PciDevice::readConfig(PacketPtr pkt
)
273 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
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);
284 case sizeof(uint16_t):
285 pkt
->set
<uint16_t>(0);
287 case sizeof(uint32_t):
288 pkt
->set
<uint32_t>(0);
291 panic("invalid access size(?) for PCI configspace!\n");
293 } else if (offset
> PCI_CONFIG_SIZE
) {
294 panic("Out-of-range access to PCI config space!\n");
297 switch (pkt
->getSize()) {
298 case sizeof(uint8_t):
299 pkt
->set
<uint8_t>(config
.data
[offset
]);
301 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
302 params()->pci_dev
, params()->pci_func
, offset
,
303 (uint32_t)pkt
->get
<uint8_t>());
305 case sizeof(uint16_t):
306 pkt
->set
<uint16_t>(*(uint16_t*)&config
.data
[offset
]);
308 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
309 params()->pci_dev
, params()->pci_func
, offset
,
310 (uint32_t)pkt
->get
<uint16_t>());
312 case sizeof(uint32_t):
313 pkt
->set
<uint32_t>(*(uint32_t*)&config
.data
[offset
]);
315 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
316 params()->pci_dev
, params()->pci_func
, offset
,
317 (uint32_t)pkt
->get
<uint32_t>());
320 panic("invalid access size(?) for PCI configspace!\n");
322 pkt
->makeAtomicResponse();
328 PciDevice::getAddrRanges() const
330 AddrRangeList ranges
;
332 for (x
= 0; x
< 6; x
++)
333 if (BARAddrs
[x
] != 0)
334 ranges
.push_back(RangeSize(BARAddrs
[x
],BARSize
[x
]));
339 PciDevice::writeConfig(PacketPtr pkt
)
341 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
343 /* No effect if we write to config space that is not implemented*/
344 if (offset
>= PCI_DEVICE_SPECIFIC
&&
345 offset
< PCI_CONFIG_SIZE
) {
346 warn_once("Device specific PCI config space "
347 "not implemented for %s!\n", this->name());
348 switch (pkt
->getSize()) {
349 case sizeof(uint8_t):
350 case sizeof(uint16_t):
351 case sizeof(uint32_t):
354 panic("invalid access size(?) for PCI configspace!\n");
356 } else if (offset
> PCI_CONFIG_SIZE
) {
357 panic("Out-of-range access to PCI config space!\n");
360 switch (pkt
->getSize()) {
361 case sizeof(uint8_t):
363 case PCI0_INTERRUPT_LINE
:
364 config
.interruptLine
= pkt
->get
<uint8_t>();
366 case PCI_CACHE_LINE_SIZE
:
367 config
.cacheLineSize
= pkt
->get
<uint8_t>();
369 case PCI_LATENCY_TIMER
:
370 config
.latencyTimer
= pkt
->get
<uint8_t>();
372 /* Do nothing for these read-only registers */
373 case PCI0_INTERRUPT_PIN
:
374 case PCI0_MINIMUM_GRANT
:
375 case PCI0_MAXIMUM_LATENCY
:
377 case PCI_REVISION_ID
:
380 panic("writing to a read only register");
383 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
384 params()->pci_dev
, params()->pci_func
, offset
,
385 (uint32_t)pkt
->get
<uint8_t>());
387 case sizeof(uint16_t):
390 config
.command
= pkt
->get
<uint8_t>();
393 config
.status
= pkt
->get
<uint8_t>();
395 case PCI_CACHE_LINE_SIZE
:
396 config
.cacheLineSize
= pkt
->get
<uint8_t>();
399 panic("writing to a read only register");
402 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
403 params()->pci_dev
, params()->pci_func
, offset
,
404 (uint32_t)pkt
->get
<uint16_t>());
406 case sizeof(uint32_t):
408 case PCI0_BASE_ADDR0
:
409 case PCI0_BASE_ADDR1
:
410 case PCI0_BASE_ADDR2
:
411 case PCI0_BASE_ADDR3
:
412 case PCI0_BASE_ADDR4
:
413 case PCI0_BASE_ADDR5
:
415 int barnum
= BAR_NUMBER(offset
);
417 if (!legacyIO
[barnum
]) {
418 // convert BAR values to host endianness
419 uint32_t he_old_bar
= letoh(config
.baseAddr
[barnum
]);
420 uint32_t he_new_bar
= letoh(pkt
->get
<uint32_t>());
423 BAR_IO_SPACE(he_old_bar
) ? BAR_IO_MASK
: BAR_MEM_MASK
;
425 // Writing 0xffffffff to a BAR tells the card to set the
426 // value of the bar to a bitmask indicating the size of
428 if (he_new_bar
== 0xffffffff) {
429 he_new_bar
= ~(BARSize
[barnum
] - 1);
431 // does it mean something special to write 0 to a BAR?
432 he_new_bar
&= ~bar_mask
;
434 BARAddrs
[barnum
] = BAR_IO_SPACE(he_old_bar
) ?
435 platform
->calcPciIOAddr(he_new_bar
) :
436 platform
->calcPciMemAddr(he_new_bar
);
437 pioPort
.sendRangeChange();
440 config
.baseAddr
[barnum
] = htole((he_new_bar
& ~bar_mask
) |
441 (he_old_bar
& bar_mask
));
446 case PCI0_ROM_BASE_ADDR
:
447 if (letoh(pkt
->get
<uint32_t>()) == 0xfffffffe)
448 config
.expansionROM
= htole((uint32_t)0xffffffff);
450 config
.expansionROM
= pkt
->get
<uint32_t>();
454 // This could also clear some of the error bits in the Status
455 // register. However they should never get set, so lets ignore
457 config
.command
= pkt
->get
<uint32_t>();
461 DPRINTF(PCIDEV
, "Writing to a read only register");
464 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
465 params()->pci_dev
, params()->pci_func
, offset
,
466 (uint32_t)pkt
->get
<uint32_t>());
469 panic("invalid access size(?) for PCI configspace!\n");
471 pkt
->makeAtomicResponse();
476 PciDevice::serialize(std::ostream
&os
)
478 SERIALIZE_ARRAY(BARSize
, sizeof(BARSize
) / sizeof(BARSize
[0]));
479 SERIALIZE_ARRAY(BARAddrs
, sizeof(BARAddrs
) / sizeof(BARAddrs
[0]));
480 SERIALIZE_ARRAY(config
.data
, sizeof(config
.data
) / sizeof(config
.data
[0]));
482 // serialize the capability list registers
483 paramOut(os
, csprintf("pmcap.pid"), uint16_t(pmcap
.pid
));
484 paramOut(os
, csprintf("pmcap.pc"), uint16_t(pmcap
.pc
));
485 paramOut(os
, csprintf("pmcap.pmcs"), uint16_t(pmcap
.pmcs
));
487 paramOut(os
, csprintf("msicap.mid"), uint16_t(msicap
.mid
));
488 paramOut(os
, csprintf("msicap.mc"), uint16_t(msicap
.mc
));
489 paramOut(os
, csprintf("msicap.ma"), uint32_t(msicap
.ma
));
490 SERIALIZE_SCALAR(msicap
.mua
);
491 paramOut(os
, csprintf("msicap.md"), uint16_t(msicap
.md
));
492 SERIALIZE_SCALAR(msicap
.mmask
);
493 SERIALIZE_SCALAR(msicap
.mpend
);
495 paramOut(os
, csprintf("msixcap.mxid"), uint16_t(msixcap
.mxid
));
496 paramOut(os
, csprintf("msixcap.mxc"), uint16_t(msixcap
.mxc
));
497 paramOut(os
, csprintf("msixcap.mtab"), uint32_t(msixcap
.mtab
));
498 paramOut(os
, csprintf("msixcap.mpba"), uint32_t(msixcap
.mpba
));
500 // Only serialize if we have a non-zero base address
501 if (MSIXCAP_BASE
!= 0x0) {
502 uint16_t msixcap_mxc_ts
= msixcap
.mxc
& 0x07ff;
503 int msix_array_size
= msixcap_mxc_ts
+ 1;
504 int pba_array_size
= msix_array_size
/MSIXVECS_PER_PBA
;
505 if ((msix_array_size
% MSIXVECS_PER_PBA
) > 0) {
509 SERIALIZE_SCALAR(msix_array_size
);
510 SERIALIZE_SCALAR(pba_array_size
);
512 for (int i
= 0; i
< msix_array_size
; i
++) {
513 paramOut(os
, csprintf("msix_table[%d].addr_lo", i
),
514 msix_table
[i
].fields
.addr_lo
);
515 paramOut(os
, csprintf("msix_table[%d].addr_hi", i
),
516 msix_table
[i
].fields
.addr_hi
);
517 paramOut(os
, csprintf("msix_table[%d].msg_data", i
),
518 msix_table
[i
].fields
.msg_data
);
519 paramOut(os
, csprintf("msix_table[%d].vec_ctrl", i
),
520 msix_table
[i
].fields
.vec_ctrl
);
522 for (int i
= 0; i
< pba_array_size
; i
++) {
523 paramOut(os
, csprintf("msix_pba[%d].bits", i
),
528 paramOut(os
, csprintf("pxcap.pxid"), uint16_t(pxcap
.pxid
));
529 paramOut(os
, csprintf("pxcap.pxcap"), uint16_t(pxcap
.pxcap
));
530 paramOut(os
, csprintf("pxcap.pxdcap"), uint32_t(pxcap
.pxdcap
));
531 paramOut(os
, csprintf("pxcap.pxdc"), uint16_t(pxcap
.pxdc
));
532 paramOut(os
, csprintf("pxcap.pxds"), uint16_t(pxcap
.pxds
));
533 paramOut(os
, csprintf("pxcap.pxlcap"), uint32_t(pxcap
.pxlcap
));
534 paramOut(os
, csprintf("pxcap.pxlc"), uint16_t(pxcap
.pxlc
));
535 paramOut(os
, csprintf("pxcap.pxls"), uint16_t(pxcap
.pxls
));
536 paramOut(os
, csprintf("pxcap.pxdcap2"), uint32_t(pxcap
.pxdcap2
));
537 paramOut(os
, csprintf("pxcap.pxdc2"), uint32_t(pxcap
.pxdc2
));
541 PciDevice::unserialize(Checkpoint
*cp
, const std::string
§ion
)
543 UNSERIALIZE_ARRAY(BARSize
, sizeof(BARSize
) / sizeof(BARSize
[0]));
544 UNSERIALIZE_ARRAY(BARAddrs
, sizeof(BARAddrs
) / sizeof(BARAddrs
[0]));
545 UNSERIALIZE_ARRAY(config
.data
,
546 sizeof(config
.data
) / sizeof(config
.data
[0]));
548 // unserialize the capability list registers
551 paramIn(cp
, section
, csprintf("pmcap.pid"), tmp16
);
553 paramIn(cp
, section
, csprintf("pmcap.pc"), tmp16
);
555 paramIn(cp
, section
, csprintf("pmcap.pmcs"), tmp16
);
558 paramIn(cp
, section
, csprintf("msicap.mid"), tmp16
);
560 paramIn(cp
, section
, csprintf("msicap.mc"), tmp16
);
562 paramIn(cp
, section
, csprintf("msicap.ma"), tmp32
);
564 UNSERIALIZE_SCALAR(msicap
.mua
);
565 paramIn(cp
, section
, csprintf("msicap.md"), tmp16
);;
567 UNSERIALIZE_SCALAR(msicap
.mmask
);
568 UNSERIALIZE_SCALAR(msicap
.mpend
);
570 paramIn(cp
, section
, csprintf("msixcap.mxid"), tmp16
);
571 msixcap
.mxid
= tmp16
;
572 paramIn(cp
, section
, csprintf("msixcap.mxc"), tmp16
);
574 paramIn(cp
, section
, csprintf("msixcap.mtab"), tmp32
);
575 msixcap
.mtab
= tmp32
;
576 paramIn(cp
, section
, csprintf("msixcap.mpba"), tmp32
);
577 msixcap
.mpba
= tmp32
;
579 // Only allocate if MSIXCAP_BASE is not 0x0
580 if (MSIXCAP_BASE
!= 0x0) {
584 UNSERIALIZE_SCALAR(msix_array_size
);
585 UNSERIALIZE_SCALAR(pba_array_size
);
587 MSIXTable tmp1
= {{0UL, 0UL, 0UL, 0UL}};
588 msix_table
.resize(msix_array_size
, tmp1
);
590 MSIXPbaEntry tmp2
= {0};
591 msix_pba
.resize(pba_array_size
, tmp2
);
593 for (int i
= 0; i
< msix_array_size
; i
++) {
594 paramIn(cp
, section
, csprintf("msix_table[%d].addr_lo", i
),
595 msix_table
[i
].fields
.addr_lo
);
596 paramIn(cp
, section
, csprintf("msix_table[%d].addr_hi", i
),
597 msix_table
[i
].fields
.addr_hi
);
598 paramIn(cp
, section
, csprintf("msix_table[%d].msg_data", i
),
599 msix_table
[i
].fields
.msg_data
);
600 paramIn(cp
, section
, csprintf("msix_table[%d].vec_ctrl", i
),
601 msix_table
[i
].fields
.vec_ctrl
);
603 for (int i
= 0; i
< pba_array_size
; i
++) {
604 paramIn(cp
, section
, csprintf("msix_pba[%d].bits", i
),
609 paramIn(cp
, section
, csprintf("pxcap.pxid"), tmp16
);
611 paramIn(cp
, section
, csprintf("pxcap.pxcap"), tmp16
);
613 paramIn(cp
, section
, csprintf("pxcap.pxdcap"), tmp32
);
614 pxcap
.pxdcap
= tmp32
;
615 paramIn(cp
, section
, csprintf("pxcap.pxdc"), tmp16
);
617 paramIn(cp
, section
, csprintf("pxcap.pxds"), tmp16
);
619 paramIn(cp
, section
, csprintf("pxcap.pxlcap"), tmp32
);
620 pxcap
.pxlcap
= tmp32
;
621 paramIn(cp
, section
, csprintf("pxcap.pxlc"), tmp16
);
623 paramIn(cp
, section
, csprintf("pxcap.pxls"), tmp16
);
625 paramIn(cp
, section
, csprintf("pxcap.pxdcap2"), tmp32
);
626 pxcap
.pxdcap2
= tmp32
;
627 paramIn(cp
, section
, csprintf("pxcap.pxdc2"), tmp32
);
629 pioPort
.sendRangeChange();