2 * Copyright (c) 2013, 2015 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.
42 * A single PCI device configuration space entry.
45 #include "dev/pci/device.hh"
51 #include "base/inifile.hh"
52 #include "base/intmath.hh"
53 #include "base/logging.hh"
54 #include "base/str.hh"
55 #include "base/trace.hh"
56 #include "debug/PciDevice.hh"
57 #include "mem/packet.hh"
58 #include "mem/packet_access.hh"
59 #include "sim/byteswap.hh"
60 #include "sim/core.hh"
62 PciDevice::PciDevice(const PciDeviceParams
*p
)
64 _busAddr(p
->pci_bus
, p
->pci_dev
, p
->pci_func
),
65 PMCAP_BASE(p
->PMCAPBaseOffset
),
66 PMCAP_ID_OFFSET(p
->PMCAPBaseOffset
+PMCAP_ID
),
67 PMCAP_PC_OFFSET(p
->PMCAPBaseOffset
+PMCAP_PC
),
68 PMCAP_PMCS_OFFSET(p
->PMCAPBaseOffset
+PMCAP_PMCS
),
69 MSICAP_BASE(p
->MSICAPBaseOffset
),
70 MSIXCAP_BASE(p
->MSIXCAPBaseOffset
),
71 MSIXCAP_ID_OFFSET(p
->MSIXCAPBaseOffset
+MSIXCAP_ID
),
72 MSIXCAP_MXC_OFFSET(p
->MSIXCAPBaseOffset
+MSIXCAP_MXC
),
73 MSIXCAP_MTAB_OFFSET(p
->MSIXCAPBaseOffset
+MSIXCAP_MTAB
),
74 MSIXCAP_MPBA_OFFSET(p
->MSIXCAPBaseOffset
+MSIXCAP_MPBA
),
75 PXCAP_BASE(p
->PXCAPBaseOffset
),
77 hostInterface(p
->host
->registerDevice(this, _busAddr
,
78 (PciIntPin
)p
->InterruptPin
)),
79 pioDelay(p
->pio_latency
),
80 configDelay(p
->config_latency
)
82 fatal_if(p
->InterruptPin
>= 5,
83 "Invalid PCI interrupt '%i' specified.", p
->InterruptPin
);
85 config
.vendor
= htole(p
->VendorID
);
86 config
.device
= htole(p
->DeviceID
);
87 config
.command
= htole(p
->Command
);
88 config
.status
= htole(p
->Status
);
89 config
.revision
= htole(p
->Revision
);
90 config
.progIF
= htole(p
->ProgIF
);
91 config
.subClassCode
= htole(p
->SubClassCode
);
92 config
.classCode
= htole(p
->ClassCode
);
93 config
.cacheLineSize
= htole(p
->CacheLineSize
);
94 config
.latencyTimer
= htole(p
->LatencyTimer
);
95 config
.headerType
= htole(p
->HeaderType
);
96 config
.bist
= htole(p
->BIST
);
98 config
.baseAddr
[0] = htole(p
->BAR0
);
99 config
.baseAddr
[1] = htole(p
->BAR1
);
100 config
.baseAddr
[2] = htole(p
->BAR2
);
101 config
.baseAddr
[3] = htole(p
->BAR3
);
102 config
.baseAddr
[4] = htole(p
->BAR4
);
103 config
.baseAddr
[5] = htole(p
->BAR5
);
104 config
.cardbusCIS
= htole(p
->CardbusCIS
);
105 config
.subsystemVendorID
= htole(p
->SubsystemVendorID
);
106 config
.subsystemID
= htole(p
->SubsystemID
);
107 config
.expansionROM
= htole(p
->ExpansionROM
);
108 config
.capabilityPtr
= htole(p
->CapabilityPtr
);
109 // Zero out the 7 bytes of reserved space in the PCI Config space register.
110 bzero(config
.reserved
, 7*sizeof(uint8_t));
111 config
.interruptLine
= htole(p
->InterruptLine
);
112 config
.interruptPin
= htole(p
->InterruptPin
);
113 config
.minimumGrant
= htole(p
->MinimumGrant
);
114 config
.maximumLatency
= htole(p
->MaximumLatency
);
116 // Initialize the capability lists
117 // These structs are bitunions, meaning the data is stored in host
118 // endianess and must be converted to Little Endian when accessed
121 pmcap
.pid
= (uint16_t)p
->PMCAPCapId
; // pid.cid
122 pmcap
.pid
|= (uint16_t)p
->PMCAPNextCapability
<< 8; //pid.next
123 pmcap
.pc
= p
->PMCAPCapabilities
;
124 pmcap
.pmcs
= p
->PMCAPCtrlStatus
;
127 msicap
.mid
= (uint16_t)p
->MSICAPCapId
; //mid.cid
128 msicap
.mid
|= (uint16_t)p
->MSICAPNextCapability
<< 8; //mid.next
129 msicap
.mc
= p
->MSICAPMsgCtrl
;
130 msicap
.ma
= p
->MSICAPMsgAddr
;
131 msicap
.mua
= p
->MSICAPMsgUpperAddr
;
132 msicap
.md
= p
->MSICAPMsgData
;
133 msicap
.mmask
= p
->MSICAPMaskBits
;
134 msicap
.mpend
= p
->MSICAPPendingBits
;
137 msixcap
.mxid
= (uint16_t)p
->MSIXCAPCapId
; //mxid.cid
138 msixcap
.mxid
|= (uint16_t)p
->MSIXCAPNextCapability
<< 8; //mxid.next
139 msixcap
.mxc
= p
->MSIXMsgCtrl
;
140 msixcap
.mtab
= p
->MSIXTableOffset
;
141 msixcap
.mpba
= p
->MSIXPbaOffset
;
143 // allocate MSIX structures if MSIXCAP_BASE
144 // indicates the MSIXCAP is being used by having a
145 // non-zero base address.
146 // The MSIX tables are stored by the guest in
147 // little endian byte-order as according the
148 // PCIe specification. Make sure to take the proper
149 // actions when manipulating these tables on the host
150 uint16_t msixcap_mxc_ts
= msixcap
.mxc
& 0x07ff;
151 if (MSIXCAP_BASE
!= 0x0) {
152 int msix_vecs
= msixcap_mxc_ts
+ 1;
153 MSIXTable tmp1
= {{0UL,0UL,0UL,0UL}};
154 msix_table
.resize(msix_vecs
, tmp1
);
156 MSIXPbaEntry tmp2
= {0};
157 int pba_size
= msix_vecs
/ MSIXVECS_PER_PBA
;
158 if ((msix_vecs
% MSIXVECS_PER_PBA
) > 0) {
161 msix_pba
.resize(pba_size
, tmp2
);
163 MSIX_TABLE_OFFSET
= msixcap
.mtab
& 0xfffffffc;
164 MSIX_TABLE_END
= MSIX_TABLE_OFFSET
+
165 (msixcap_mxc_ts
+ 1) * sizeof(MSIXTable
);
166 MSIX_PBA_OFFSET
= msixcap
.mpba
& 0xfffffffc;
167 MSIX_PBA_END
= MSIX_PBA_OFFSET
+
168 ((msixcap_mxc_ts
+ 1) / MSIXVECS_PER_PBA
)
169 * sizeof(MSIXPbaEntry
);
170 if (((msixcap_mxc_ts
+ 1) % MSIXVECS_PER_PBA
) > 0) {
171 MSIX_PBA_END
+= sizeof(MSIXPbaEntry
);
175 pxcap
.pxid
= (uint16_t)p
->PXCAPCapId
; //pxid.cid
176 pxcap
.pxid
|= (uint16_t)p
->PXCAPNextCapability
<< 8; //pxid.next
177 pxcap
.pxcap
= p
->PXCAPCapabilities
;
178 pxcap
.pxdcap
= p
->PXCAPDevCapabilities
;
179 pxcap
.pxdc
= p
->PXCAPDevCtrl
;
180 pxcap
.pxds
= p
->PXCAPDevStatus
;
181 pxcap
.pxlcap
= p
->PXCAPLinkCap
;
182 pxcap
.pxlc
= p
->PXCAPLinkCtrl
;
183 pxcap
.pxls
= p
->PXCAPLinkStatus
;
184 pxcap
.pxdcap2
= p
->PXCAPDevCap2
;
185 pxcap
.pxdc2
= p
->PXCAPDevCtrl2
;
187 BARSize
[0] = p
->BAR0Size
;
188 BARSize
[1] = p
->BAR1Size
;
189 BARSize
[2] = p
->BAR2Size
;
190 BARSize
[3] = p
->BAR3Size
;
191 BARSize
[4] = p
->BAR4Size
;
192 BARSize
[5] = p
->BAR5Size
;
194 legacyIO
[0] = p
->BAR0LegacyIO
;
195 legacyIO
[1] = p
->BAR1LegacyIO
;
196 legacyIO
[2] = p
->BAR2LegacyIO
;
197 legacyIO
[3] = p
->BAR3LegacyIO
;
198 legacyIO
[4] = p
->BAR4LegacyIO
;
199 legacyIO
[5] = p
->BAR5LegacyIO
;
201 for (int i
= 0; i
< 6; ++i
) {
203 BARAddrs
[i
] = p
->LegacyIOBase
+ letoh(config
.baseAddr
[i
]);
204 config
.baseAddr
[i
] = 0;
207 uint32_t barsize
= BARSize
[i
];
208 if (barsize
!= 0 && !isPowerOf2(barsize
)) {
209 fatal("BAR %d size %d is not a power of 2\n", i
, BARSize
[i
]);
216 PciDevice::readConfig(PacketPtr pkt
)
218 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
220 /* Return 0 for accesses to unimplemented PCI configspace areas */
221 if (offset
>= PCI_DEVICE_SPECIFIC
&&
222 offset
< PCI_CONFIG_SIZE
) {
223 warn_once("Device specific PCI config space "
224 "not implemented for %s!\n", this->name());
225 switch (pkt
->getSize()) {
226 case sizeof(uint8_t):
227 pkt
->setLE
<uint8_t>(0);
229 case sizeof(uint16_t):
230 pkt
->setLE
<uint16_t>(0);
232 case sizeof(uint32_t):
233 pkt
->setLE
<uint32_t>(0);
236 panic("invalid access size(?) for PCI configspace!\n");
238 } else if (offset
> PCI_CONFIG_SIZE
) {
239 panic("Out-of-range access to PCI config space!\n");
242 switch (pkt
->getSize()) {
243 case sizeof(uint8_t):
244 pkt
->setLE
<uint8_t>(config
.data
[offset
]);
246 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
247 _busAddr
.dev
, _busAddr
.func
, offset
,
248 (uint32_t)pkt
->getLE
<uint8_t>());
250 case sizeof(uint16_t):
251 pkt
->setLE
<uint16_t>(*(uint16_t*)&config
.data
[offset
]);
253 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
254 _busAddr
.dev
, _busAddr
.func
, offset
,
255 (uint32_t)pkt
->getLE
<uint16_t>());
257 case sizeof(uint32_t):
258 pkt
->setLE
<uint32_t>(*(uint32_t*)&config
.data
[offset
]);
260 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
261 _busAddr
.dev
, _busAddr
.func
, offset
,
262 (uint32_t)pkt
->getLE
<uint32_t>());
265 panic("invalid access size(?) for PCI configspace!\n");
267 pkt
->makeAtomicResponse();
273 PciDevice::getAddrRanges() const
275 AddrRangeList ranges
;
277 for (x
= 0; x
< 6; x
++)
278 if (BARAddrs
[x
] != 0)
279 ranges
.push_back(RangeSize(BARAddrs
[x
],BARSize
[x
]));
284 PciDevice::writeConfig(PacketPtr pkt
)
286 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
288 /* No effect if we write to config space that is not implemented*/
289 if (offset
>= PCI_DEVICE_SPECIFIC
&&
290 offset
< PCI_CONFIG_SIZE
) {
291 warn_once("Device specific PCI config space "
292 "not implemented for %s!\n", this->name());
293 switch (pkt
->getSize()) {
294 case sizeof(uint8_t):
295 case sizeof(uint16_t):
296 case sizeof(uint32_t):
299 panic("invalid access size(?) for PCI configspace!\n");
301 } else if (offset
> PCI_CONFIG_SIZE
) {
302 panic("Out-of-range access to PCI config space!\n");
305 switch (pkt
->getSize()) {
306 case sizeof(uint8_t):
308 case PCI0_INTERRUPT_LINE
:
309 config
.interruptLine
= pkt
->getLE
<uint8_t>();
311 case PCI_CACHE_LINE_SIZE
:
312 config
.cacheLineSize
= pkt
->getLE
<uint8_t>();
314 case PCI_LATENCY_TIMER
:
315 config
.latencyTimer
= pkt
->getLE
<uint8_t>();
317 /* Do nothing for these read-only registers */
318 case PCI0_INTERRUPT_PIN
:
319 case PCI0_MINIMUM_GRANT
:
320 case PCI0_MAXIMUM_LATENCY
:
322 case PCI_REVISION_ID
:
325 panic("writing to a read only register");
328 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
329 _busAddr
.dev
, _busAddr
.func
, offset
,
330 (uint32_t)pkt
->getLE
<uint8_t>());
332 case sizeof(uint16_t):
335 config
.command
= pkt
->getLE
<uint8_t>();
338 config
.status
= pkt
->getLE
<uint8_t>();
340 case PCI_CACHE_LINE_SIZE
:
341 config
.cacheLineSize
= pkt
->getLE
<uint8_t>();
344 panic("writing to a read only register");
347 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
348 _busAddr
.dev
, _busAddr
.func
, offset
,
349 (uint32_t)pkt
->getLE
<uint16_t>());
351 case sizeof(uint32_t):
353 case PCI0_BASE_ADDR0
:
354 case PCI0_BASE_ADDR1
:
355 case PCI0_BASE_ADDR2
:
356 case PCI0_BASE_ADDR3
:
357 case PCI0_BASE_ADDR4
:
358 case PCI0_BASE_ADDR5
:
360 int barnum
= BAR_NUMBER(offset
);
362 if (!legacyIO
[barnum
]) {
363 // convert BAR values to host endianness
364 uint32_t he_old_bar
= letoh(config
.baseAddr
[barnum
]);
365 uint32_t he_new_bar
= letoh(pkt
->getLE
<uint32_t>());
368 BAR_IO_SPACE(he_old_bar
) ? BAR_IO_MASK
: BAR_MEM_MASK
;
370 // Writing 0xffffffff to a BAR tells the card to set the
371 // value of the bar to a bitmask indicating the size of
373 if (he_new_bar
== 0xffffffff) {
374 he_new_bar
= ~(BARSize
[barnum
] - 1);
376 // does it mean something special to write 0 to a BAR?
377 he_new_bar
&= ~bar_mask
;
379 if (isLargeBAR(barnum
)) {
380 if (BAR_IO_SPACE(he_old_bar
))
381 warn("IO BARs can't be set as large BAR");
382 uint64_t he_large_bar
=
383 letoh(config
.baseAddr
[barnum
+ 1]);
384 he_large_bar
= he_large_bar
<< 32;
385 he_large_bar
+= he_new_bar
;
387 hostInterface
.memAddr(he_large_bar
);
388 } else if (isLargeBAR(barnum
- 1)) {
389 BARAddrs
[barnum
] = 0;
390 uint64_t he_large_bar
= he_new_bar
;
391 he_large_bar
= he_large_bar
<< 32;
392 // We need to apply mask to lower bits
394 letoh(config
.baseAddr
[barnum
- 1]
396 BARAddrs
[barnum
- 1] =
397 hostInterface
.memAddr(he_large_bar
);
399 BARAddrs
[barnum
] = BAR_IO_SPACE(he_old_bar
) ?
400 hostInterface
.pioAddr(he_new_bar
) :
401 hostInterface
.memAddr(he_new_bar
);
403 pioPort
.sendRangeChange();
406 config
.baseAddr
[barnum
] = htole((he_new_bar
& ~bar_mask
) |
407 (he_old_bar
& bar_mask
));
412 case PCI0_ROM_BASE_ADDR
:
413 if (letoh(pkt
->getLE
<uint32_t>()) == 0xfffffffe)
414 config
.expansionROM
= htole((uint32_t)0xffffffff);
416 config
.expansionROM
= pkt
->getLE
<uint32_t>();
420 // This could also clear some of the error bits in the Status
421 // register. However they should never get set, so lets ignore
423 config
.command
= pkt
->getLE
<uint32_t>();
427 DPRINTF(PciDevice
, "Writing to a read only register");
430 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
431 _busAddr
.dev
, _busAddr
.func
, offset
,
432 (uint32_t)pkt
->getLE
<uint32_t>());
435 panic("invalid access size(?) for PCI configspace!\n");
437 pkt
->makeAtomicResponse();
442 PciDevice::serialize(CheckpointOut
&cp
) const
444 SERIALIZE_ARRAY(BARSize
, sizeof(BARSize
) / sizeof(BARSize
[0]));
445 SERIALIZE_ARRAY(BARAddrs
, sizeof(BARAddrs
) / sizeof(BARAddrs
[0]));
446 SERIALIZE_ARRAY(config
.data
, sizeof(config
.data
) / sizeof(config
.data
[0]));
448 // serialize the capability list registers
449 paramOut(cp
, csprintf("pmcap.pid"), uint16_t(pmcap
.pid
));
450 paramOut(cp
, csprintf("pmcap.pc"), uint16_t(pmcap
.pc
));
451 paramOut(cp
, csprintf("pmcap.pmcs"), uint16_t(pmcap
.pmcs
));
453 paramOut(cp
, csprintf("msicap.mid"), uint16_t(msicap
.mid
));
454 paramOut(cp
, csprintf("msicap.mc"), uint16_t(msicap
.mc
));
455 paramOut(cp
, csprintf("msicap.ma"), uint32_t(msicap
.ma
));
456 SERIALIZE_SCALAR(msicap
.mua
);
457 paramOut(cp
, csprintf("msicap.md"), uint16_t(msicap
.md
));
458 SERIALIZE_SCALAR(msicap
.mmask
);
459 SERIALIZE_SCALAR(msicap
.mpend
);
461 paramOut(cp
, csprintf("msixcap.mxid"), uint16_t(msixcap
.mxid
));
462 paramOut(cp
, csprintf("msixcap.mxc"), uint16_t(msixcap
.mxc
));
463 paramOut(cp
, csprintf("msixcap.mtab"), uint32_t(msixcap
.mtab
));
464 paramOut(cp
, csprintf("msixcap.mpba"), uint32_t(msixcap
.mpba
));
466 // Only serialize if we have a non-zero base address
467 if (MSIXCAP_BASE
!= 0x0) {
468 uint16_t msixcap_mxc_ts
= msixcap
.mxc
& 0x07ff;
469 int msix_array_size
= msixcap_mxc_ts
+ 1;
470 int pba_array_size
= msix_array_size
/MSIXVECS_PER_PBA
;
471 if ((msix_array_size
% MSIXVECS_PER_PBA
) > 0) {
475 SERIALIZE_SCALAR(msix_array_size
);
476 SERIALIZE_SCALAR(pba_array_size
);
478 for (int i
= 0; i
< msix_array_size
; i
++) {
479 paramOut(cp
, csprintf("msix_table[%d].addr_lo", i
),
480 msix_table
[i
].fields
.addr_lo
);
481 paramOut(cp
, csprintf("msix_table[%d].addr_hi", i
),
482 msix_table
[i
].fields
.addr_hi
);
483 paramOut(cp
, csprintf("msix_table[%d].msg_data", i
),
484 msix_table
[i
].fields
.msg_data
);
485 paramOut(cp
, csprintf("msix_table[%d].vec_ctrl", i
),
486 msix_table
[i
].fields
.vec_ctrl
);
488 for (int i
= 0; i
< pba_array_size
; i
++) {
489 paramOut(cp
, csprintf("msix_pba[%d].bits", i
),
494 paramOut(cp
, csprintf("pxcap.pxid"), uint16_t(pxcap
.pxid
));
495 paramOut(cp
, csprintf("pxcap.pxcap"), uint16_t(pxcap
.pxcap
));
496 paramOut(cp
, csprintf("pxcap.pxdcap"), uint32_t(pxcap
.pxdcap
));
497 paramOut(cp
, csprintf("pxcap.pxdc"), uint16_t(pxcap
.pxdc
));
498 paramOut(cp
, csprintf("pxcap.pxds"), uint16_t(pxcap
.pxds
));
499 paramOut(cp
, csprintf("pxcap.pxlcap"), uint32_t(pxcap
.pxlcap
));
500 paramOut(cp
, csprintf("pxcap.pxlc"), uint16_t(pxcap
.pxlc
));
501 paramOut(cp
, csprintf("pxcap.pxls"), uint16_t(pxcap
.pxls
));
502 paramOut(cp
, csprintf("pxcap.pxdcap2"), uint32_t(pxcap
.pxdcap2
));
503 paramOut(cp
, csprintf("pxcap.pxdc2"), uint32_t(pxcap
.pxdc2
));
507 PciDevice::unserialize(CheckpointIn
&cp
)
509 UNSERIALIZE_ARRAY(BARSize
, sizeof(BARSize
) / sizeof(BARSize
[0]));
510 UNSERIALIZE_ARRAY(BARAddrs
, sizeof(BARAddrs
) / sizeof(BARAddrs
[0]));
511 UNSERIALIZE_ARRAY(config
.data
,
512 sizeof(config
.data
) / sizeof(config
.data
[0]));
514 // unserialize the capability list registers
517 paramIn(cp
, csprintf("pmcap.pid"), tmp16
);
519 paramIn(cp
, csprintf("pmcap.pc"), tmp16
);
521 paramIn(cp
, csprintf("pmcap.pmcs"), tmp16
);
524 paramIn(cp
, csprintf("msicap.mid"), tmp16
);
526 paramIn(cp
, csprintf("msicap.mc"), tmp16
);
528 paramIn(cp
, csprintf("msicap.ma"), tmp32
);
530 UNSERIALIZE_SCALAR(msicap
.mua
);
531 paramIn(cp
, csprintf("msicap.md"), tmp16
);;
533 UNSERIALIZE_SCALAR(msicap
.mmask
);
534 UNSERIALIZE_SCALAR(msicap
.mpend
);
536 paramIn(cp
, csprintf("msixcap.mxid"), tmp16
);
537 msixcap
.mxid
= tmp16
;
538 paramIn(cp
, csprintf("msixcap.mxc"), tmp16
);
540 paramIn(cp
, csprintf("msixcap.mtab"), tmp32
);
541 msixcap
.mtab
= tmp32
;
542 paramIn(cp
, csprintf("msixcap.mpba"), tmp32
);
543 msixcap
.mpba
= tmp32
;
545 // Only allocate if MSIXCAP_BASE is not 0x0
546 if (MSIXCAP_BASE
!= 0x0) {
550 UNSERIALIZE_SCALAR(msix_array_size
);
551 UNSERIALIZE_SCALAR(pba_array_size
);
553 MSIXTable tmp1
= {{0UL, 0UL, 0UL, 0UL}};
554 msix_table
.resize(msix_array_size
, tmp1
);
556 MSIXPbaEntry tmp2
= {0};
557 msix_pba
.resize(pba_array_size
, tmp2
);
559 for (int i
= 0; i
< msix_array_size
; i
++) {
560 paramIn(cp
, csprintf("msix_table[%d].addr_lo", i
),
561 msix_table
[i
].fields
.addr_lo
);
562 paramIn(cp
, csprintf("msix_table[%d].addr_hi", i
),
563 msix_table
[i
].fields
.addr_hi
);
564 paramIn(cp
, csprintf("msix_table[%d].msg_data", i
),
565 msix_table
[i
].fields
.msg_data
);
566 paramIn(cp
, csprintf("msix_table[%d].vec_ctrl", i
),
567 msix_table
[i
].fields
.vec_ctrl
);
569 for (int i
= 0; i
< pba_array_size
; i
++) {
570 paramIn(cp
, csprintf("msix_pba[%d].bits", i
),
575 paramIn(cp
, csprintf("pxcap.pxid"), tmp16
);
577 paramIn(cp
, csprintf("pxcap.pxcap"), tmp16
);
579 paramIn(cp
, csprintf("pxcap.pxdcap"), tmp32
);
580 pxcap
.pxdcap
= tmp32
;
581 paramIn(cp
, csprintf("pxcap.pxdc"), tmp16
);
583 paramIn(cp
, csprintf("pxcap.pxds"), tmp16
);
585 paramIn(cp
, csprintf("pxcap.pxlcap"), tmp32
);
586 pxcap
.pxlcap
= tmp32
;
587 paramIn(cp
, csprintf("pxcap.pxlc"), tmp16
);
589 paramIn(cp
, csprintf("pxcap.pxls"), tmp16
);
591 paramIn(cp
, csprintf("pxcap.pxdcap2"), tmp32
);
592 pxcap
.pxdcap2
= tmp32
;
593 paramIn(cp
, csprintf("pxcap.pxdc2"), tmp32
);
595 pioPort
.sendRangeChange();