adc12bb55aa24fa879bb6d2c23273c1f3bea9633
[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->busFirstWordDelay = pkt->busLastWordDelay = 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 MSICAP_BASE(p->MSICAPBaseOffset),
101 MSIXCAP_BASE(p->MSIXCAPBaseOffset),
102 PXCAP_BASE(p->PXCAPBaseOffset),
103 platform(p->platform),
104 pioDelay(p->pio_latency),
105 configDelay(p->config_latency),
106 configPort(this, params()->pci_bus, params()->pci_dev,
107 params()->pci_func, params()->platform)
108 {
109 config.vendor = htole(p->VendorID);
110 config.device = htole(p->DeviceID);
111 config.command = htole(p->Command);
112 config.status = htole(p->Status);
113 config.revision = htole(p->Revision);
114 config.progIF = htole(p->ProgIF);
115 config.subClassCode = htole(p->SubClassCode);
116 config.classCode = htole(p->ClassCode);
117 config.cacheLineSize = htole(p->CacheLineSize);
118 config.latencyTimer = htole(p->LatencyTimer);
119 config.headerType = htole(p->HeaderType);
120 config.bist = htole(p->BIST);
121
122 config.baseAddr[0] = htole(p->BAR0);
123 config.baseAddr[1] = htole(p->BAR1);
124 config.baseAddr[2] = htole(p->BAR2);
125 config.baseAddr[3] = htole(p->BAR3);
126 config.baseAddr[4] = htole(p->BAR4);
127 config.baseAddr[5] = htole(p->BAR5);
128 config.cardbusCIS = htole(p->CardbusCIS);
129 config.subsystemVendorID = htole(p->SubsystemVendorID);
130 config.subsystemID = htole(p->SubsystemID);
131 config.expansionROM = htole(p->ExpansionROM);
132 config.capabilityPtr = htole(p->CapabilityPtr);
133 // Zero out the 7 bytes of reserved space in the PCI Config space register.
134 bzero(config.reserved, 7*sizeof(uint8_t));
135 config.interruptLine = htole(p->InterruptLine);
136 config.interruptPin = htole(p->InterruptPin);
137 config.minimumGrant = htole(p->MinimumGrant);
138 config.maximumLatency = htole(p->MaximumLatency);
139
140 // Initialize the capability lists
141 // These structs are bitunions, meaning the data is stored in host
142 // endianess and must be converted to Little Endian when accessed
143 // by the guest
144 // PMCAP
145 pmcap.pid.cid = p->PMCAPCapId;
146 pmcap.pid.next = p->PMCAPNextCapability;
147 pmcap.pc = p->PMCAPCapabilities;
148 pmcap.pmcs = p->PMCAPCtrlStatus;
149
150 // MSICAP
151 msicap.mid.cid = p->MSICAPCapId;
152 msicap.mid.next = p->MSICAPNextCapability;
153 msicap.mc = p->MSICAPMsgCtrl;
154 msicap.ma = p->MSICAPMsgAddr;
155 msicap.mua = p->MSICAPMsgUpperAddr;
156 msicap.md = p->MSICAPMsgData;
157 msicap.mmask = p->MSICAPMaskBits;
158 msicap.mpend = p->MSICAPPendingBits;
159
160 // MSIXCAP
161 msixcap.mxid.cid = p->MSIXCAPCapId;
162 msixcap.mxid.next = p->MSIXCAPNextCapability;
163 msixcap.mxc = p->MSIXMsgCtrl;
164 msixcap.mtab = p->MSIXTableOffset;
165 msixcap.mpba = p->MSIXPbaOffset;
166
167 // allocate MSIX structures if MSIXCAP_BASE
168 // indicates the MSIXCAP is being used by having a
169 // non-zero base address.
170 // The MSIX tables are stored by the guest in
171 // little endian byte-order as according the
172 // PCIe specification. Make sure to take the proper
173 // actions when manipulating these tables on the host
174 if (MSIXCAP_BASE != 0x0) {
175 int msix_vecs = msixcap.mxc.ts + 1;
176 MSIXTable tmp1 = {{0UL,0UL,0UL,0UL}};
177 msix_table.resize(msix_vecs, tmp1);
178
179 MSIXPbaEntry tmp2 = {0};
180 int pba_size = msix_vecs / MSIXVECS_PER_PBA;
181 if ((msix_vecs % MSIXVECS_PER_PBA) > 0) {
182 pba_size++;
183 }
184 msix_pba.resize(pba_size, tmp2);
185 }
186
187 // PXCAP
188 pxcap.pxid.cid = p->PXCAPCapId;
189 pxcap.pxid.next = p->PXCAPNextCapability;
190 pxcap.pxcap = p->PXCAPCapabilities;
191 pxcap.pxdcap = p->PXCAPDevCapabilities;
192 pxcap.pxdc = p->PXCAPDevCtrl;
193 pxcap.pxds = p->PXCAPDevStatus;
194 pxcap.pxlcap = p->PXCAPLinkCap;
195 pxcap.pxlc = p->PXCAPLinkCtrl;
196 pxcap.pxls = p->PXCAPLinkStatus;
197 pxcap.pxdcap2 = p->PXCAPDevCap2;
198 pxcap.pxdc2 = p->PXCAPDevCtrl2;
199
200 BARSize[0] = p->BAR0Size;
201 BARSize[1] = p->BAR1Size;
202 BARSize[2] = p->BAR2Size;
203 BARSize[3] = p->BAR3Size;
204 BARSize[4] = p->BAR4Size;
205 BARSize[5] = p->BAR5Size;
206
207 legacyIO[0] = p->BAR0LegacyIO;
208 legacyIO[1] = p->BAR1LegacyIO;
209 legacyIO[2] = p->BAR2LegacyIO;
210 legacyIO[3] = p->BAR3LegacyIO;
211 legacyIO[4] = p->BAR4LegacyIO;
212 legacyIO[5] = p->BAR5LegacyIO;
213
214 for (int i = 0; i < 6; ++i) {
215 if (legacyIO[i]) {
216 BARAddrs[i] = p->LegacyIOBase + letoh(config.baseAddr[i]);
217 config.baseAddr[i] = 0;
218 } else {
219 BARAddrs[i] = 0;
220 uint32_t barsize = BARSize[i];
221 if (barsize != 0 && !isPowerOf2(barsize)) {
222 fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]);
223 }
224 }
225 }
226
227 platform->registerPciDevice(p->pci_bus, p->pci_dev, p->pci_func,
228 letoh(config.interruptLine));
229 }
230
231 void
232 PciDevice::init()
233 {
234 if (!configPort.isConnected())
235 panic("PCI config port on %s not connected to anything!\n", name());
236 configPort.sendRangeChange();
237 DmaDevice::init();
238 }
239
240 unsigned int
241 PciDevice::drain(DrainManager *dm)
242 {
243 unsigned int count;
244 count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm);
245 if (count)
246 setDrainState(Drainable::Draining);
247 else
248 setDrainState(Drainable::Drained);
249 return count;
250 }
251
252 Tick
253 PciDevice::readConfig(PacketPtr pkt)
254 {
255 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
256 if (offset >= PCI_DEVICE_SPECIFIC)
257 panic("Device specific PCI config space not implemented!\n");
258
259 pkt->allocate();
260
261 switch (pkt->getSize()) {
262 case sizeof(uint8_t):
263 pkt->set<uint8_t>(config.data[offset]);
264 DPRINTF(PCIDEV,
265 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
266 params()->pci_dev, params()->pci_func, offset,
267 (uint32_t)pkt->get<uint8_t>());
268 break;
269 case sizeof(uint16_t):
270 pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]);
271 DPRINTF(PCIDEV,
272 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
273 params()->pci_dev, params()->pci_func, offset,
274 (uint32_t)pkt->get<uint16_t>());
275 break;
276 case sizeof(uint32_t):
277 pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]);
278 DPRINTF(PCIDEV,
279 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
280 params()->pci_dev, params()->pci_func, offset,
281 (uint32_t)pkt->get<uint32_t>());
282 break;
283 default:
284 panic("invalid access size(?) for PCI configspace!\n");
285 }
286 pkt->makeAtomicResponse();
287 return configDelay;
288
289 }
290
291 AddrRangeList
292 PciDevice::getAddrRanges() const
293 {
294 AddrRangeList ranges;
295 int x = 0;
296 for (x = 0; x < 6; x++)
297 if (BARAddrs[x] != 0)
298 ranges.push_back(RangeSize(BARAddrs[x],BARSize[x]));
299 return ranges;
300 }
301
302 Tick
303 PciDevice::writeConfig(PacketPtr pkt)
304 {
305 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
306 if (offset >= PCI_DEVICE_SPECIFIC)
307 panic("Device specific PCI config space not implemented!\n");
308
309 switch (pkt->getSize()) {
310 case sizeof(uint8_t):
311 switch (offset) {
312 case PCI0_INTERRUPT_LINE:
313 config.interruptLine = pkt->get<uint8_t>();
314 break;
315 case PCI_CACHE_LINE_SIZE:
316 config.cacheLineSize = pkt->get<uint8_t>();
317 break;
318 case PCI_LATENCY_TIMER:
319 config.latencyTimer = pkt->get<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(PCIDEV,
332 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
333 params()->pci_dev, params()->pci_func, offset,
334 (uint32_t)pkt->get<uint8_t>());
335 break;
336 case sizeof(uint16_t):
337 switch (offset) {
338 case PCI_COMMAND:
339 config.command = pkt->get<uint8_t>();
340 break;
341 case PCI_STATUS:
342 config.status = pkt->get<uint8_t>();
343 break;
344 case PCI_CACHE_LINE_SIZE:
345 config.cacheLineSize = pkt->get<uint8_t>();
346 break;
347 default:
348 panic("writing to a read only register");
349 }
350 DPRINTF(PCIDEV,
351 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
352 params()->pci_dev, params()->pci_func, offset,
353 (uint32_t)pkt->get<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->get<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 BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ?
384 platform->calcPciIOAddr(he_new_bar) :
385 platform->calcPciMemAddr(he_new_bar);
386 pioPort.sendRangeChange();
387 }
388 }
389 config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) |
390 (he_old_bar & bar_mask));
391 }
392 }
393 break;
394
395 case PCI0_ROM_BASE_ADDR:
396 if (letoh(pkt->get<uint32_t>()) == 0xfffffffe)
397 config.expansionROM = htole((uint32_t)0xffffffff);
398 else
399 config.expansionROM = pkt->get<uint32_t>();
400 break;
401
402 case PCI_COMMAND:
403 // This could also clear some of the error bits in the Status
404 // register. However they should never get set, so lets ignore
405 // it for now
406 config.command = pkt->get<uint32_t>();
407 break;
408
409 default:
410 DPRINTF(PCIDEV, "Writing to a read only register");
411 }
412 DPRINTF(PCIDEV,
413 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
414 params()->pci_dev, params()->pci_func, offset,
415 (uint32_t)pkt->get<uint32_t>());
416 break;
417 default:
418 panic("invalid access size(?) for PCI configspace!\n");
419 }
420 pkt->makeAtomicResponse();
421 return configDelay;
422 }
423
424 void
425 PciDevice::serialize(std::ostream &os)
426 {
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]));
430
431 // serialize the capability list registers
432 paramOut(os, csprintf("pmcap.pid"), uint16_t(pmcap.pid));
433 paramOut(os, csprintf("pmcap.pc"), uint16_t(pmcap.pc));
434 paramOut(os, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs));
435
436 paramOut(os, csprintf("msicap.mid"), uint16_t(msicap.mid));
437 paramOut(os, csprintf("msicap.mc"), uint16_t(msicap.mc));
438 paramOut(os, csprintf("msicap.ma"), uint32_t(msicap.ma));
439 SERIALIZE_SCALAR(msicap.mua);
440 paramOut(os, csprintf("msicap.md"), uint16_t(msicap.md));
441 SERIALIZE_SCALAR(msicap.mmask);
442 SERIALIZE_SCALAR(msicap.mpend);
443
444 paramOut(os, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid));
445 paramOut(os, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc));
446 paramOut(os, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab));
447 paramOut(os, csprintf("msixcap.mpba"), uint32_t(msixcap.mpba));
448
449 // Only serialize if we have a non-zero base address
450 if (MSIXCAP_BASE != 0x0) {
451 int msix_array_size = msixcap.mxc.ts + 1;
452 int pba_array_size = msix_array_size/MSIXVECS_PER_PBA;
453 if ((msix_array_size % MSIXVECS_PER_PBA) > 0) {
454 pba_array_size++;
455 }
456
457 SERIALIZE_SCALAR(msix_array_size);
458 SERIALIZE_SCALAR(pba_array_size);
459
460 for (int i = 0; i < msix_array_size; i++) {
461 paramOut(os, csprintf("msix_table[%d].addr_lo", i),
462 msix_table[i].fields.addr_lo);
463 paramOut(os, csprintf("msix_table[%d].addr_hi", i),
464 msix_table[i].fields.addr_hi);
465 paramOut(os, csprintf("msix_table[%d].msg_data", i),
466 msix_table[i].fields.msg_data);
467 paramOut(os, csprintf("msix_table[%d].vec_ctrl", i),
468 msix_table[i].fields.vec_ctrl);
469 }
470 for (int i = 0; i < pba_array_size; i++) {
471 paramOut(os, csprintf("msix_pba[%d].bits", i),
472 msix_pba[i].bits);
473 }
474 }
475
476 paramOut(os, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid));
477 paramOut(os, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap));
478 paramOut(os, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap));
479 paramOut(os, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc));
480 paramOut(os, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds));
481 paramOut(os, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap));
482 paramOut(os, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc));
483 paramOut(os, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls));
484 paramOut(os, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2));
485 paramOut(os, csprintf("pxcap.pxdc2"), uint32_t(pxcap.pxdc2));
486 }
487
488 void
489 PciDevice::unserialize(Checkpoint *cp, const std::string &section)
490 {
491 UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0]));
492 UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
493 UNSERIALIZE_ARRAY(config.data,
494 sizeof(config.data) / sizeof(config.data[0]));
495
496 // unserialize the capability list registers
497 uint16_t tmp16;
498 uint32_t tmp32;
499 paramIn(cp, section, csprintf("pmcap.pid"), tmp16);
500 pmcap.pid = tmp16;
501 paramIn(cp, section, csprintf("pmcap.pc"), tmp16);
502 pmcap.pc = tmp16;
503 paramIn(cp, section, csprintf("pmcap.pmcs"), tmp16);
504 pmcap.pmcs = tmp16;
505
506 paramIn(cp, section, csprintf("msicap.mid"), tmp16);
507 msicap.mid = tmp16;
508 paramIn(cp, section, csprintf("msicap.mc"), tmp16);
509 msicap.mc = tmp16;
510 paramIn(cp, section, csprintf("msicap.ma"), tmp32);
511 msicap.ma = tmp32;
512 UNSERIALIZE_SCALAR(msicap.mua);
513 paramIn(cp, section, csprintf("msicap.md"), tmp16);;
514 msicap.md = tmp16;
515 UNSERIALIZE_SCALAR(msicap.mmask);
516 UNSERIALIZE_SCALAR(msicap.mpend);
517
518 paramIn(cp, section, csprintf("msixcap.mxid"), tmp16);
519 msixcap.mxid = tmp16;
520 paramIn(cp, section, csprintf("msixcap.mxc"), tmp16);
521 msixcap.mxc = tmp16;
522 paramIn(cp, section, csprintf("msixcap.mtab"), tmp32);
523 msixcap.mtab = tmp32;
524 paramIn(cp, section, csprintf("msixcap.mpba"), tmp32);
525 msixcap.mpba = tmp32;
526
527 // Only allocate if MSIXCAP_BASE is not 0x0
528 if (MSIXCAP_BASE != 0x0) {
529 int msix_array_size;
530 int pba_array_size;
531
532 UNSERIALIZE_SCALAR(msix_array_size);
533 UNSERIALIZE_SCALAR(pba_array_size);
534
535 MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}};
536 msix_table.resize(msix_array_size, tmp1);
537
538 MSIXPbaEntry tmp2 = {0};
539 msix_pba.resize(pba_array_size, tmp2);
540
541 for (int i = 0; i < msix_array_size; i++) {
542 paramIn(cp, section, csprintf("msix_table[%d].addr_lo", i),
543 msix_table[i].fields.addr_lo);
544 paramIn(cp, section, csprintf("msix_table[%d].addr_hi", i),
545 msix_table[i].fields.addr_hi);
546 paramIn(cp, section, csprintf("msix_table[%d].msg_data", i),
547 msix_table[i].fields.msg_data);
548 paramIn(cp, section, csprintf("msix_table[%d].vec_ctrl", i),
549 msix_table[i].fields.vec_ctrl);
550 }
551 for (int i = 0; i < pba_array_size; i++) {
552 paramIn(cp, section, csprintf("msix_pba[%d].bits", i),
553 msix_pba[i].bits);
554 }
555 }
556
557 paramIn(cp, section, csprintf("pxcap.pxid"), tmp16);
558 pxcap.pxid = tmp16;
559 paramIn(cp, section, csprintf("pxcap.pxcap"), tmp16);
560 pxcap.pxcap = tmp16;
561 paramIn(cp, section, csprintf("pxcap.pxdcap"), tmp32);
562 pxcap.pxdcap = tmp32;
563 paramIn(cp, section, csprintf("pxcap.pxdc"), tmp16);
564 pxcap.pxdc = tmp16;
565 paramIn(cp, section, csprintf("pxcap.pxds"), tmp16);
566 pxcap.pxds = tmp16;
567 paramIn(cp, section, csprintf("pxcap.pxlcap"), tmp32);
568 pxcap.pxlcap = tmp32;
569 paramIn(cp, section, csprintf("pxcap.pxlc"), tmp16);
570 pxcap.pxlc = tmp16;
571 paramIn(cp, section, csprintf("pxcap.pxls"), tmp16);
572 pxcap.pxls = tmp16;
573 paramIn(cp, section, csprintf("pxcap.pxdcap2"), tmp32);
574 pxcap.pxdcap2 = tmp32;
575 paramIn(cp, section, csprintf("pxcap.pxdc2"), tmp32);
576 pxcap.pxdc2 = tmp32;
577 pioPort.sendRangeChange();
578 }
579