mem-cache: Add multiple eviction stats
[gem5.git] / src / dev / pci / device.cc
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/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"
65
66 PciDevice::PciDevice(const PciDeviceParams *p)
67 : DmaDevice(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),
80
81 hostInterface(p->host->registerDevice(this, _busAddr,
82 (PciIntPin)p->InterruptPin)),
83 pioDelay(p->pio_latency),
84 configDelay(p->config_latency)
85 {
86 fatal_if(p->InterruptPin >= 5,
87 "Invalid PCI interrupt '%i' specified.", p->InterruptPin);
88
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);
101
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);
119
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
123 // by the guest
124 // PMCAP
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;
129
130 // MSICAP
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;
139
140 // MSIXCAP
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;
146
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);
159
160 MSIXPbaEntry tmp2 = {0};
161 int pba_size = msix_vecs / MSIXVECS_PER_PBA;
162 if ((msix_vecs % MSIXVECS_PER_PBA) > 0) {
163 pba_size++;
164 }
165 msix_pba.resize(pba_size, tmp2);
166 }
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);
176 }
177
178 // PXCAP
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;
190
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;
197
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;
204
205 for (int i = 0; i < 6; ++i) {
206 if (legacyIO[i]) {
207 BARAddrs[i] = p->LegacyIOBase + letoh(config.baseAddr[i]);
208 config.baseAddr[i] = 0;
209 } else {
210 BARAddrs[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]);
214 }
215 }
216 }
217 }
218
219 Tick
220 PciDevice::readConfig(PacketPtr pkt)
221 {
222 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
223
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->setLE<uint8_t>(0);
232 break;
233 case sizeof(uint16_t):
234 pkt->setLE<uint16_t>(0);
235 break;
236 case sizeof(uint32_t):
237 pkt->setLE<uint32_t>(0);
238 break;
239 default:
240 panic("invalid access size(?) for PCI configspace!\n");
241 }
242 } else if (offset > PCI_CONFIG_SIZE) {
243 panic("Out-of-range access to PCI config space!\n");
244 }
245
246 switch (pkt->getSize()) {
247 case sizeof(uint8_t):
248 pkt->setLE<uint8_t>(config.data[offset]);
249 DPRINTF(PciDevice,
250 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
251 _busAddr.dev, _busAddr.func, offset,
252 (uint32_t)pkt->getLE<uint8_t>());
253 break;
254 case sizeof(uint16_t):
255 pkt->setLE<uint16_t>(*(uint16_t*)&config.data[offset]);
256 DPRINTF(PciDevice,
257 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
258 _busAddr.dev, _busAddr.func, offset,
259 (uint32_t)pkt->getLE<uint16_t>());
260 break;
261 case sizeof(uint32_t):
262 pkt->setLE<uint32_t>(*(uint32_t*)&config.data[offset]);
263 DPRINTF(PciDevice,
264 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
265 _busAddr.dev, _busAddr.func, offset,
266 (uint32_t)pkt->getLE<uint32_t>());
267 break;
268 default:
269 panic("invalid access size(?) for PCI configspace!\n");
270 }
271 pkt->makeAtomicResponse();
272 return configDelay;
273
274 }
275
276 AddrRangeList
277 PciDevice::getAddrRanges() const
278 {
279 AddrRangeList ranges;
280 int x = 0;
281 for (x = 0; x < 6; x++)
282 if (BARAddrs[x] != 0)
283 ranges.push_back(RangeSize(BARAddrs[x],BARSize[x]));
284 return ranges;
285 }
286
287 Tick
288 PciDevice::writeConfig(PacketPtr pkt)
289 {
290 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
291
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):
301 break;
302 default:
303 panic("invalid access size(?) for PCI configspace!\n");
304 }
305 } else if (offset > PCI_CONFIG_SIZE) {
306 panic("Out-of-range access to PCI config space!\n");
307 }
308
309 switch (pkt->getSize()) {
310 case sizeof(uint8_t):
311 switch (offset) {
312 case PCI0_INTERRUPT_LINE:
313 config.interruptLine = pkt->getLE<uint8_t>();
314 break;
315 case PCI_CACHE_LINE_SIZE:
316 config.cacheLineSize = pkt->getLE<uint8_t>();
317 break;
318 case PCI_LATENCY_TIMER:
319 config.latencyTimer = pkt->getLE<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(PciDevice,
332 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
333 _busAddr.dev, _busAddr.func, offset,
334 (uint32_t)pkt->getLE<uint8_t>());
335 break;
336 case sizeof(uint16_t):
337 switch (offset) {
338 case PCI_COMMAND:
339 config.command = pkt->getLE<uint8_t>();
340 break;
341 case PCI_STATUS:
342 config.status = pkt->getLE<uint8_t>();
343 break;
344 case PCI_CACHE_LINE_SIZE:
345 config.cacheLineSize = pkt->getLE<uint8_t>();
346 break;
347 default:
348 panic("writing to a read only register");
349 }
350 DPRINTF(PciDevice,
351 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
352 _busAddr.dev, _busAddr.func, offset,
353 (uint32_t)pkt->getLE<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->getLE<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 if (isLargeBAR(barnum)) {
384 if (BAR_IO_SPACE(he_old_bar))
385 warn("IO BARs can't be set as large BAR");
386 uint64_t he_large_bar =
387 letoh(config.baseAddr[barnum + 1]);
388 he_large_bar = he_large_bar << 32;
389 he_large_bar += he_new_bar;
390 BARAddrs[barnum] =
391 hostInterface.memAddr(he_large_bar);
392 } else if (isLargeBAR(barnum - 1)) {
393 BARAddrs[barnum] = 0;
394 uint64_t he_large_bar = he_new_bar;
395 he_large_bar = he_large_bar << 32;
396 // We need to apply mask to lower bits
397 he_large_bar +=
398 letoh(config.baseAddr[barnum - 1]
399 & ~bar_mask);
400 BARAddrs[barnum - 1] =
401 hostInterface.memAddr(he_large_bar);
402 } else {
403 BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ?
404 hostInterface.pioAddr(he_new_bar) :
405 hostInterface.memAddr(he_new_bar);
406 }
407 pioPort.sendRangeChange();
408 }
409 }
410 config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) |
411 (he_old_bar & bar_mask));
412 }
413 }
414 break;
415
416 case PCI0_ROM_BASE_ADDR:
417 if (letoh(pkt->getLE<uint32_t>()) == 0xfffffffe)
418 config.expansionROM = htole((uint32_t)0xffffffff);
419 else
420 config.expansionROM = pkt->getLE<uint32_t>();
421 break;
422
423 case PCI_COMMAND:
424 // This could also clear some of the error bits in the Status
425 // register. However they should never get set, so lets ignore
426 // it for now
427 config.command = pkt->getLE<uint32_t>();
428 break;
429
430 default:
431 DPRINTF(PciDevice, "Writing to a read only register");
432 }
433 DPRINTF(PciDevice,
434 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
435 _busAddr.dev, _busAddr.func, offset,
436 (uint32_t)pkt->getLE<uint32_t>());
437 break;
438 default:
439 panic("invalid access size(?) for PCI configspace!\n");
440 }
441 pkt->makeAtomicResponse();
442 return configDelay;
443 }
444
445 void
446 PciDevice::serialize(CheckpointOut &cp) const
447 {
448 SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0]));
449 SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
450 SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0]));
451
452 // serialize the capability list registers
453 paramOut(cp, csprintf("pmcap.pid"), uint16_t(pmcap.pid));
454 paramOut(cp, csprintf("pmcap.pc"), uint16_t(pmcap.pc));
455 paramOut(cp, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs));
456
457 paramOut(cp, csprintf("msicap.mid"), uint16_t(msicap.mid));
458 paramOut(cp, csprintf("msicap.mc"), uint16_t(msicap.mc));
459 paramOut(cp, csprintf("msicap.ma"), uint32_t(msicap.ma));
460 SERIALIZE_SCALAR(msicap.mua);
461 paramOut(cp, csprintf("msicap.md"), uint16_t(msicap.md));
462 SERIALIZE_SCALAR(msicap.mmask);
463 SERIALIZE_SCALAR(msicap.mpend);
464
465 paramOut(cp, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid));
466 paramOut(cp, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc));
467 paramOut(cp, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab));
468 paramOut(cp, csprintf("msixcap.mpba"), uint32_t(msixcap.mpba));
469
470 // Only serialize if we have a non-zero base address
471 if (MSIXCAP_BASE != 0x0) {
472 uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff;
473 int msix_array_size = msixcap_mxc_ts + 1;
474 int pba_array_size = msix_array_size/MSIXVECS_PER_PBA;
475 if ((msix_array_size % MSIXVECS_PER_PBA) > 0) {
476 pba_array_size++;
477 }
478
479 SERIALIZE_SCALAR(msix_array_size);
480 SERIALIZE_SCALAR(pba_array_size);
481
482 for (int i = 0; i < msix_array_size; i++) {
483 paramOut(cp, csprintf("msix_table[%d].addr_lo", i),
484 msix_table[i].fields.addr_lo);
485 paramOut(cp, csprintf("msix_table[%d].addr_hi", i),
486 msix_table[i].fields.addr_hi);
487 paramOut(cp, csprintf("msix_table[%d].msg_data", i),
488 msix_table[i].fields.msg_data);
489 paramOut(cp, csprintf("msix_table[%d].vec_ctrl", i),
490 msix_table[i].fields.vec_ctrl);
491 }
492 for (int i = 0; i < pba_array_size; i++) {
493 paramOut(cp, csprintf("msix_pba[%d].bits", i),
494 msix_pba[i].bits);
495 }
496 }
497
498 paramOut(cp, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid));
499 paramOut(cp, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap));
500 paramOut(cp, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap));
501 paramOut(cp, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc));
502 paramOut(cp, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds));
503 paramOut(cp, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap));
504 paramOut(cp, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc));
505 paramOut(cp, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls));
506 paramOut(cp, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2));
507 paramOut(cp, csprintf("pxcap.pxdc2"), uint32_t(pxcap.pxdc2));
508 }
509
510 void
511 PciDevice::unserialize(CheckpointIn &cp)
512 {
513 UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0]));
514 UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
515 UNSERIALIZE_ARRAY(config.data,
516 sizeof(config.data) / sizeof(config.data[0]));
517
518 // unserialize the capability list registers
519 uint16_t tmp16;
520 uint32_t tmp32;
521 paramIn(cp, csprintf("pmcap.pid"), tmp16);
522 pmcap.pid = tmp16;
523 paramIn(cp, csprintf("pmcap.pc"), tmp16);
524 pmcap.pc = tmp16;
525 paramIn(cp, csprintf("pmcap.pmcs"), tmp16);
526 pmcap.pmcs = tmp16;
527
528 paramIn(cp, csprintf("msicap.mid"), tmp16);
529 msicap.mid = tmp16;
530 paramIn(cp, csprintf("msicap.mc"), tmp16);
531 msicap.mc = tmp16;
532 paramIn(cp, csprintf("msicap.ma"), tmp32);
533 msicap.ma = tmp32;
534 UNSERIALIZE_SCALAR(msicap.mua);
535 paramIn(cp, csprintf("msicap.md"), tmp16);;
536 msicap.md = tmp16;
537 UNSERIALIZE_SCALAR(msicap.mmask);
538 UNSERIALIZE_SCALAR(msicap.mpend);
539
540 paramIn(cp, csprintf("msixcap.mxid"), tmp16);
541 msixcap.mxid = tmp16;
542 paramIn(cp, csprintf("msixcap.mxc"), tmp16);
543 msixcap.mxc = tmp16;
544 paramIn(cp, csprintf("msixcap.mtab"), tmp32);
545 msixcap.mtab = tmp32;
546 paramIn(cp, csprintf("msixcap.mpba"), tmp32);
547 msixcap.mpba = tmp32;
548
549 // Only allocate if MSIXCAP_BASE is not 0x0
550 if (MSIXCAP_BASE != 0x0) {
551 int msix_array_size;
552 int pba_array_size;
553
554 UNSERIALIZE_SCALAR(msix_array_size);
555 UNSERIALIZE_SCALAR(pba_array_size);
556
557 MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}};
558 msix_table.resize(msix_array_size, tmp1);
559
560 MSIXPbaEntry tmp2 = {0};
561 msix_pba.resize(pba_array_size, tmp2);
562
563 for (int i = 0; i < msix_array_size; i++) {
564 paramIn(cp, csprintf("msix_table[%d].addr_lo", i),
565 msix_table[i].fields.addr_lo);
566 paramIn(cp, csprintf("msix_table[%d].addr_hi", i),
567 msix_table[i].fields.addr_hi);
568 paramIn(cp, csprintf("msix_table[%d].msg_data", i),
569 msix_table[i].fields.msg_data);
570 paramIn(cp, csprintf("msix_table[%d].vec_ctrl", i),
571 msix_table[i].fields.vec_ctrl);
572 }
573 for (int i = 0; i < pba_array_size; i++) {
574 paramIn(cp, csprintf("msix_pba[%d].bits", i),
575 msix_pba[i].bits);
576 }
577 }
578
579 paramIn(cp, csprintf("pxcap.pxid"), tmp16);
580 pxcap.pxid = tmp16;
581 paramIn(cp, csprintf("pxcap.pxcap"), tmp16);
582 pxcap.pxcap = tmp16;
583 paramIn(cp, csprintf("pxcap.pxdcap"), tmp32);
584 pxcap.pxdcap = tmp32;
585 paramIn(cp, csprintf("pxcap.pxdc"), tmp16);
586 pxcap.pxdc = tmp16;
587 paramIn(cp, csprintf("pxcap.pxds"), tmp16);
588 pxcap.pxds = tmp16;
589 paramIn(cp, csprintf("pxcap.pxlcap"), tmp32);
590 pxcap.pxlcap = tmp32;
591 paramIn(cp, csprintf("pxcap.pxlc"), tmp16);
592 pxcap.pxlc = tmp16;
593 paramIn(cp, csprintf("pxcap.pxls"), tmp16);
594 pxcap.pxls = tmp16;
595 paramIn(cp, csprintf("pxcap.pxdcap2"), tmp32);
596 pxcap.pxdcap2 = tmp32;
597 paramIn(cp, csprintf("pxcap.pxdc2"), tmp32);
598 pxcap.pxdc2 = tmp32;
599 pioPort.sendRangeChange();
600 }
601