sim, arm: add checkpoint upgrader for d02b45a5
[gem5.git] / src / dev / pcidev.cc
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
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)
72 {
73 configAddr = platform->calcPciConfigAddr(busId, deviceId, functionId);
74 }
75
76
77 Tick
78 PciDevice::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->headerDelay = pkt->payloadDelay = 0;
84 return pkt->isRead() ? device->readConfig(pkt) : device->writeConfig(pkt);
85 }
86
87 AddrRangeList
88 PciDevice::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
97 PciDevice::PciDevice(const Params *p)
98 : DmaDevice(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)
115 {
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);
128
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);
146
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
150 // by the guest
151 // PMCAP
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;
156
157 // MSICAP
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;
166
167 // MSIXCAP
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;
173
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);
186
187 MSIXPbaEntry tmp2 = {0};
188 int pba_size = msix_vecs / MSIXVECS_PER_PBA;
189 if ((msix_vecs % MSIXVECS_PER_PBA) > 0) {
190 pba_size++;
191 }
192 msix_pba.resize(pba_size, tmp2);
193 }
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);
203 }
204
205 // PXCAP
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;
217
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;
224
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;
231
232 for (int i = 0; i < 6; ++i) {
233 if (legacyIO[i]) {
234 BARAddrs[i] = p->LegacyIOBase + letoh(config.baseAddr[i]);
235 config.baseAddr[i] = 0;
236 } else {
237 BARAddrs[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]);
241 }
242 }
243 }
244
245 platform->registerPciDevice(p->pci_bus, p->pci_dev, p->pci_func,
246 letoh(config.interruptLine));
247 }
248
249 void
250 PciDevice::init()
251 {
252 if (!configPort.isConnected())
253 panic("PCI config port on %s not connected to anything!\n", name());
254 configPort.sendRangeChange();
255 DmaDevice::init();
256 }
257
258 unsigned int
259 PciDevice::drain(DrainManager *dm)
260 {
261 unsigned int count;
262 count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm);
263 if (count)
264 setDrainState(Drainable::Draining);
265 else
266 setDrainState(Drainable::Drained);
267 return count;
268 }
269
270 Tick
271 PciDevice::readConfig(PacketPtr pkt)
272 {
273 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
274
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);
283 break;
284 case sizeof(uint16_t):
285 pkt->set<uint16_t>(0);
286 break;
287 case sizeof(uint32_t):
288 pkt->set<uint32_t>(0);
289 break;
290 default:
291 panic("invalid access size(?) for PCI configspace!\n");
292 }
293 } else if (offset > PCI_CONFIG_SIZE) {
294 panic("Out-of-range access to PCI config space!\n");
295 }
296
297 switch (pkt->getSize()) {
298 case sizeof(uint8_t):
299 pkt->set<uint8_t>(config.data[offset]);
300 DPRINTF(PCIDEV,
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>());
304 break;
305 case sizeof(uint16_t):
306 pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]);
307 DPRINTF(PCIDEV,
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>());
311 break;
312 case sizeof(uint32_t):
313 pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]);
314 DPRINTF(PCIDEV,
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>());
318 break;
319 default:
320 panic("invalid access size(?) for PCI configspace!\n");
321 }
322 pkt->makeAtomicResponse();
323 return configDelay;
324
325 }
326
327 AddrRangeList
328 PciDevice::getAddrRanges() const
329 {
330 AddrRangeList ranges;
331 int x = 0;
332 for (x = 0; x < 6; x++)
333 if (BARAddrs[x] != 0)
334 ranges.push_back(RangeSize(BARAddrs[x],BARSize[x]));
335 return ranges;
336 }
337
338 Tick
339 PciDevice::writeConfig(PacketPtr pkt)
340 {
341 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
342
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):
352 break;
353 default:
354 panic("invalid access size(?) for PCI configspace!\n");
355 }
356 } else if (offset > PCI_CONFIG_SIZE) {
357 panic("Out-of-range access to PCI config space!\n");
358 }
359
360 switch (pkt->getSize()) {
361 case sizeof(uint8_t):
362 switch (offset) {
363 case PCI0_INTERRUPT_LINE:
364 config.interruptLine = pkt->get<uint8_t>();
365 break;
366 case PCI_CACHE_LINE_SIZE:
367 config.cacheLineSize = pkt->get<uint8_t>();
368 break;
369 case PCI_LATENCY_TIMER:
370 config.latencyTimer = pkt->get<uint8_t>();
371 break;
372 /* Do nothing for these read-only registers */
373 case PCI0_INTERRUPT_PIN:
374 case PCI0_MINIMUM_GRANT:
375 case PCI0_MAXIMUM_LATENCY:
376 case PCI_CLASS_CODE:
377 case PCI_REVISION_ID:
378 break;
379 default:
380 panic("writing to a read only register");
381 }
382 DPRINTF(PCIDEV,
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>());
386 break;
387 case sizeof(uint16_t):
388 switch (offset) {
389 case PCI_COMMAND:
390 config.command = pkt->get<uint8_t>();
391 break;
392 case PCI_STATUS:
393 config.status = pkt->get<uint8_t>();
394 break;
395 case PCI_CACHE_LINE_SIZE:
396 config.cacheLineSize = pkt->get<uint8_t>();
397 break;
398 default:
399 panic("writing to a read only register");
400 }
401 DPRINTF(PCIDEV,
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>());
405 break;
406 case sizeof(uint32_t):
407 switch (offset) {
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:
414 {
415 int barnum = BAR_NUMBER(offset);
416
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>());
421
422 uint32_t bar_mask =
423 BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK;
424
425 // Writing 0xffffffff to a BAR tells the card to set the
426 // value of the bar to a bitmask indicating the size of
427 // memory it needs
428 if (he_new_bar == 0xffffffff) {
429 he_new_bar = ~(BARSize[barnum] - 1);
430 } else {
431 // does it mean something special to write 0 to a BAR?
432 he_new_bar &= ~bar_mask;
433 if (he_new_bar) {
434 BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ?
435 platform->calcPciIOAddr(he_new_bar) :
436 platform->calcPciMemAddr(he_new_bar);
437 pioPort.sendRangeChange();
438 }
439 }
440 config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) |
441 (he_old_bar & bar_mask));
442 }
443 }
444 break;
445
446 case PCI0_ROM_BASE_ADDR:
447 if (letoh(pkt->get<uint32_t>()) == 0xfffffffe)
448 config.expansionROM = htole((uint32_t)0xffffffff);
449 else
450 config.expansionROM = pkt->get<uint32_t>();
451 break;
452
453 case PCI_COMMAND:
454 // This could also clear some of the error bits in the Status
455 // register. However they should never get set, so lets ignore
456 // it for now
457 config.command = pkt->get<uint32_t>();
458 break;
459
460 default:
461 DPRINTF(PCIDEV, "Writing to a read only register");
462 }
463 DPRINTF(PCIDEV,
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>());
467 break;
468 default:
469 panic("invalid access size(?) for PCI configspace!\n");
470 }
471 pkt->makeAtomicResponse();
472 return configDelay;
473 }
474
475 void
476 PciDevice::serialize(std::ostream &os)
477 {
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]));
481
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));
486
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);
494
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));
499
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) {
506 pba_array_size++;
507 }
508
509 SERIALIZE_SCALAR(msix_array_size);
510 SERIALIZE_SCALAR(pba_array_size);
511
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);
521 }
522 for (int i = 0; i < pba_array_size; i++) {
523 paramOut(os, csprintf("msix_pba[%d].bits", i),
524 msix_pba[i].bits);
525 }
526 }
527
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));
538 }
539
540 void
541 PciDevice::unserialize(Checkpoint *cp, const std::string &section)
542 {
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]));
547
548 // unserialize the capability list registers
549 uint16_t tmp16;
550 uint32_t tmp32;
551 paramIn(cp, section, csprintf("pmcap.pid"), tmp16);
552 pmcap.pid = tmp16;
553 paramIn(cp, section, csprintf("pmcap.pc"), tmp16);
554 pmcap.pc = tmp16;
555 paramIn(cp, section, csprintf("pmcap.pmcs"), tmp16);
556 pmcap.pmcs = tmp16;
557
558 paramIn(cp, section, csprintf("msicap.mid"), tmp16);
559 msicap.mid = tmp16;
560 paramIn(cp, section, csprintf("msicap.mc"), tmp16);
561 msicap.mc = tmp16;
562 paramIn(cp, section, csprintf("msicap.ma"), tmp32);
563 msicap.ma = tmp32;
564 UNSERIALIZE_SCALAR(msicap.mua);
565 paramIn(cp, section, csprintf("msicap.md"), tmp16);;
566 msicap.md = tmp16;
567 UNSERIALIZE_SCALAR(msicap.mmask);
568 UNSERIALIZE_SCALAR(msicap.mpend);
569
570 paramIn(cp, section, csprintf("msixcap.mxid"), tmp16);
571 msixcap.mxid = tmp16;
572 paramIn(cp, section, csprintf("msixcap.mxc"), tmp16);
573 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;
578
579 // Only allocate if MSIXCAP_BASE is not 0x0
580 if (MSIXCAP_BASE != 0x0) {
581 int msix_array_size;
582 int pba_array_size;
583
584 UNSERIALIZE_SCALAR(msix_array_size);
585 UNSERIALIZE_SCALAR(pba_array_size);
586
587 MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}};
588 msix_table.resize(msix_array_size, tmp1);
589
590 MSIXPbaEntry tmp2 = {0};
591 msix_pba.resize(pba_array_size, tmp2);
592
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);
602 }
603 for (int i = 0; i < pba_array_size; i++) {
604 paramIn(cp, section, csprintf("msix_pba[%d].bits", i),
605 msix_pba[i].bits);
606 }
607 }
608
609 paramIn(cp, section, csprintf("pxcap.pxid"), tmp16);
610 pxcap.pxid = tmp16;
611 paramIn(cp, section, csprintf("pxcap.pxcap"), tmp16);
612 pxcap.pxcap = tmp16;
613 paramIn(cp, section, csprintf("pxcap.pxdcap"), tmp32);
614 pxcap.pxdcap = tmp32;
615 paramIn(cp, section, csprintf("pxcap.pxdc"), tmp16);
616 pxcap.pxdc = tmp16;
617 paramIn(cp, section, csprintf("pxcap.pxds"), tmp16);
618 pxcap.pxds = tmp16;
619 paramIn(cp, section, csprintf("pxcap.pxlcap"), tmp32);
620 pxcap.pxlcap = tmp32;
621 paramIn(cp, section, csprintf("pxcap.pxlc"), tmp16);
622 pxcap.pxlc = tmp16;
623 paramIn(cp, section, csprintf("pxcap.pxls"), tmp16);
624 pxcap.pxls = tmp16;
625 paramIn(cp, section, csprintf("pxcap.pxdcap2"), tmp32);
626 pxcap.pxdcap2 = tmp32;
627 paramIn(cp, section, csprintf("pxcap.pxdc2"), tmp32);
628 pxcap.pxdc2 = tmp32;
629 pioPort.sendRangeChange();
630 }
631