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.
46 * A single PCI device configuration space entry.
49 #include "dev/pci/device.hh"
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"
66 PciDevice::PciDevice(const PciDeviceParams
*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
),
81 hostInterface(p
->host
->registerDevice(this, _busAddr
,
82 (PciIntPin
)p
->InterruptPin
)),
83 pioDelay(p
->pio_latency
),
84 configDelay(p
->config_latency
)
86 fatal_if(p
->InterruptPin
>= 5,
87 "Invalid PCI interrupt '%i' specified.", p
->InterruptPin
);
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
);
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
);
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
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
;
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
;
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
;
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
);
160 MSIXPbaEntry tmp2
= {0};
161 int pba_size
= msix_vecs
/ MSIXVECS_PER_PBA
;
162 if ((msix_vecs
% MSIXVECS_PER_PBA
) > 0) {
165 msix_pba
.resize(pba_size
, tmp2
);
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
);
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
;
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
;
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
;
205 for (int i
= 0; i
< 6; ++i
) {
207 BARAddrs
[i
] = p
->LegacyIOBase
+ letoh(config
.baseAddr
[i
]);
208 config
.baseAddr
[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
]);
220 PciDevice::readConfig(PacketPtr pkt
)
222 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
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
->set
<uint8_t>(0);
233 case sizeof(uint16_t):
234 pkt
->set
<uint16_t>(0);
236 case sizeof(uint32_t):
237 pkt
->set
<uint32_t>(0);
240 panic("invalid access size(?) for PCI configspace!\n");
242 } else if (offset
> PCI_CONFIG_SIZE
) {
243 panic("Out-of-range access to PCI config space!\n");
246 switch (pkt
->getSize()) {
247 case sizeof(uint8_t):
248 pkt
->set
<uint8_t>(config
.data
[offset
]);
250 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
251 _busAddr
.dev
, _busAddr
.func
, offset
,
252 (uint32_t)pkt
->get
<uint8_t>());
254 case sizeof(uint16_t):
255 pkt
->set
<uint16_t>(*(uint16_t*)&config
.data
[offset
]);
257 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
258 _busAddr
.dev
, _busAddr
.func
, offset
,
259 (uint32_t)pkt
->get
<uint16_t>());
261 case sizeof(uint32_t):
262 pkt
->set
<uint32_t>(*(uint32_t*)&config
.data
[offset
]);
264 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
265 _busAddr
.dev
, _busAddr
.func
, offset
,
266 (uint32_t)pkt
->get
<uint32_t>());
269 panic("invalid access size(?) for PCI configspace!\n");
271 pkt
->makeAtomicResponse();
277 PciDevice::getAddrRanges() const
279 AddrRangeList ranges
;
281 for (x
= 0; x
< 6; x
++)
282 if (BARAddrs
[x
] != 0)
283 ranges
.push_back(RangeSize(BARAddrs
[x
],BARSize
[x
]));
288 PciDevice::writeConfig(PacketPtr pkt
)
290 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
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):
303 panic("invalid access size(?) for PCI configspace!\n");
305 } else if (offset
> PCI_CONFIG_SIZE
) {
306 panic("Out-of-range access to PCI config space!\n");
309 switch (pkt
->getSize()) {
310 case sizeof(uint8_t):
312 case PCI0_INTERRUPT_LINE
:
313 config
.interruptLine
= pkt
->get
<uint8_t>();
315 case PCI_CACHE_LINE_SIZE
:
316 config
.cacheLineSize
= pkt
->get
<uint8_t>();
318 case PCI_LATENCY_TIMER
:
319 config
.latencyTimer
= pkt
->get
<uint8_t>();
321 /* Do nothing for these read-only registers */
322 case PCI0_INTERRUPT_PIN
:
323 case PCI0_MINIMUM_GRANT
:
324 case PCI0_MAXIMUM_LATENCY
:
326 case PCI_REVISION_ID
:
329 panic("writing to a read only register");
332 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
333 _busAddr
.dev
, _busAddr
.func
, offset
,
334 (uint32_t)pkt
->get
<uint8_t>());
336 case sizeof(uint16_t):
339 config
.command
= pkt
->get
<uint8_t>();
342 config
.status
= pkt
->get
<uint8_t>();
344 case PCI_CACHE_LINE_SIZE
:
345 config
.cacheLineSize
= pkt
->get
<uint8_t>();
348 panic("writing to a read only register");
351 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
352 _busAddr
.dev
, _busAddr
.func
, offset
,
353 (uint32_t)pkt
->get
<uint16_t>());
355 case sizeof(uint32_t):
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
:
364 int barnum
= BAR_NUMBER(offset
);
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>());
372 BAR_IO_SPACE(he_old_bar
) ? BAR_IO_MASK
: BAR_MEM_MASK
;
374 // Writing 0xffffffff to a BAR tells the card to set the
375 // value of the bar to a bitmask indicating the size of
377 if (he_new_bar
== 0xffffffff) {
378 he_new_bar
= ~(BARSize
[barnum
] - 1);
380 // does it mean something special to write 0 to a BAR?
381 he_new_bar
&= ~bar_mask
;
383 BARAddrs
[barnum
] = BAR_IO_SPACE(he_old_bar
) ?
384 hostInterface
.pioAddr(he_new_bar
) :
385 hostInterface
.memAddr(he_new_bar
);
386 pioPort
.sendRangeChange();
389 config
.baseAddr
[barnum
] = htole((he_new_bar
& ~bar_mask
) |
390 (he_old_bar
& bar_mask
));
395 case PCI0_ROM_BASE_ADDR
:
396 if (letoh(pkt
->get
<uint32_t>()) == 0xfffffffe)
397 config
.expansionROM
= htole((uint32_t)0xffffffff);
399 config
.expansionROM
= pkt
->get
<uint32_t>();
403 // This could also clear some of the error bits in the Status
404 // register. However they should never get set, so lets ignore
406 config
.command
= pkt
->get
<uint32_t>();
410 DPRINTF(PciDevice
, "Writing to a read only register");
413 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
414 _busAddr
.dev
, _busAddr
.func
, offset
,
415 (uint32_t)pkt
->get
<uint32_t>());
418 panic("invalid access size(?) for PCI configspace!\n");
420 pkt
->makeAtomicResponse();
425 PciDevice::serialize(CheckpointOut
&cp
) const
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]));
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
));
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
);
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
));
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) {
458 SERIALIZE_SCALAR(msix_array_size
);
459 SERIALIZE_SCALAR(pba_array_size
);
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
);
471 for (int i
= 0; i
< pba_array_size
; i
++) {
472 paramOut(cp
, csprintf("msix_pba[%d].bits", i
),
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
));
490 PciDevice::unserialize(CheckpointIn
&cp
)
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]));
497 // unserialize the capability list registers
500 paramIn(cp
, csprintf("pmcap.pid"), tmp16
);
502 paramIn(cp
, csprintf("pmcap.pc"), tmp16
);
504 paramIn(cp
, csprintf("pmcap.pmcs"), tmp16
);
507 paramIn(cp
, csprintf("msicap.mid"), tmp16
);
509 paramIn(cp
, csprintf("msicap.mc"), tmp16
);
511 paramIn(cp
, csprintf("msicap.ma"), tmp32
);
513 UNSERIALIZE_SCALAR(msicap
.mua
);
514 paramIn(cp
, csprintf("msicap.md"), tmp16
);;
516 UNSERIALIZE_SCALAR(msicap
.mmask
);
517 UNSERIALIZE_SCALAR(msicap
.mpend
);
519 paramIn(cp
, csprintf("msixcap.mxid"), tmp16
);
520 msixcap
.mxid
= tmp16
;
521 paramIn(cp
, csprintf("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
;
528 // Only allocate if MSIXCAP_BASE is not 0x0
529 if (MSIXCAP_BASE
!= 0x0) {
533 UNSERIALIZE_SCALAR(msix_array_size
);
534 UNSERIALIZE_SCALAR(pba_array_size
);
536 MSIXTable tmp1
= {{0UL, 0UL, 0UL, 0UL}};
537 msix_table
.resize(msix_array_size
, tmp1
);
539 MSIXPbaEntry tmp2
= {0};
540 msix_pba
.resize(pba_array_size
, tmp2
);
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
);
552 for (int i
= 0; i
< pba_array_size
; i
++) {
553 paramIn(cp
, csprintf("msix_pba[%d].bits", i
),
558 paramIn(cp
, csprintf("pxcap.pxid"), tmp16
);
560 paramIn(cp
, csprintf("pxcap.pxcap"), tmp16
);
562 paramIn(cp
, csprintf("pxcap.pxdcap"), tmp32
);
563 pxcap
.pxdcap
= tmp32
;
564 paramIn(cp
, csprintf("pxcap.pxdc"), tmp16
);
566 paramIn(cp
, csprintf("pxcap.pxds"), tmp16
);
568 paramIn(cp
, csprintf("pxcap.pxlcap"), tmp32
);
569 pxcap
.pxlcap
= tmp32
;
570 paramIn(cp
, csprintf("pxcap.pxlc"), tmp16
);
572 paramIn(cp
, csprintf("pxcap.pxls"), tmp16
);
574 paramIn(cp
, csprintf("pxcap.pxdcap2"), tmp32
);
575 pxcap
.pxdcap2
= tmp32
;
576 paramIn(cp
, csprintf("pxcap.pxdc2"), tmp32
);
578 pioPort
.sendRangeChange();