summaryrefslogtreecommitdiff
path: root/src/dev/pcidev.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev/pcidev.cc')
-rw-r--r--src/dev/pcidev.cc84
1 files changed, 70 insertions, 14 deletions
diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc
index b27547519..232aa9e8b 100644
--- a/src/dev/pcidev.cc
+++ b/src/dev/pcidev.cc
@@ -97,8 +97,15 @@ PciDevice::PciConfigPort::getAddrRanges() const
PciDevice::PciDevice(const Params *p)
: DmaDevice(p),
PMCAP_BASE(p->PMCAPBaseOffset),
+ PMCAP_ID_OFFSET(p->PMCAPBaseOffset+PMCAP_ID),
+ PMCAP_PC_OFFSET(p->PMCAPBaseOffset+PMCAP_PC),
+ PMCAP_PMCS_OFFSET(p->PMCAPBaseOffset+PMCAP_PMCS),
MSICAP_BASE(p->MSICAPBaseOffset),
MSIXCAP_BASE(p->MSIXCAPBaseOffset),
+ MSIXCAP_ID_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_ID),
+ MSIXCAP_MXC_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MXC),
+ MSIXCAP_MTAB_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MTAB),
+ MSIXCAP_MPBA_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MPBA),
PXCAP_BASE(p->PXCAPBaseOffset),
platform(p->platform),
pioDelay(p->pio_latency),
@@ -142,14 +149,14 @@ PciDevice::PciDevice(const Params *p)
// endianess and must be converted to Little Endian when accessed
// by the guest
// PMCAP
- pmcap.pid.cid = p->PMCAPCapId;
- pmcap.pid.next = p->PMCAPNextCapability;
+ pmcap.pid = (uint16_t)p->PMCAPCapId; // pid.cid
+ pmcap.pid |= (uint16_t)p->PMCAPNextCapability << 8; //pid.next
pmcap.pc = p->PMCAPCapabilities;
pmcap.pmcs = p->PMCAPCtrlStatus;
// MSICAP
- msicap.mid.cid = p->MSICAPCapId;
- msicap.mid.next = p->MSICAPNextCapability;
+ msicap.mid = (uint16_t)p->MSICAPCapId; //mid.cid
+ msicap.mid |= (uint16_t)p->MSICAPNextCapability << 8; //mid.next
msicap.mc = p->MSICAPMsgCtrl;
msicap.ma = p->MSICAPMsgAddr;
msicap.mua = p->MSICAPMsgUpperAddr;
@@ -158,8 +165,8 @@ PciDevice::PciDevice(const Params *p)
msicap.mpend = p->MSICAPPendingBits;
// MSIXCAP
- msixcap.mxid.cid = p->MSIXCAPCapId;
- msixcap.mxid.next = p->MSIXCAPNextCapability;
+ msixcap.mxid = (uint16_t)p->MSIXCAPCapId; //mxid.cid
+ msixcap.mxid |= (uint16_t)p->MSIXCAPNextCapability << 8; //mxid.next
msixcap.mxc = p->MSIXMsgCtrl;
msixcap.mtab = p->MSIXTableOffset;
msixcap.mpba = p->MSIXPbaOffset;
@@ -171,8 +178,9 @@ PciDevice::PciDevice(const Params *p)
// little endian byte-order as according the
// PCIe specification. Make sure to take the proper
// actions when manipulating these tables on the host
+ uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff;
if (MSIXCAP_BASE != 0x0) {
- int msix_vecs = msixcap.mxc.ts + 1;
+ int msix_vecs = msixcap_mxc_ts + 1;
MSIXTable tmp1 = {{0UL,0UL,0UL,0UL}};
msix_table.resize(msix_vecs, tmp1);
@@ -183,10 +191,20 @@ PciDevice::PciDevice(const Params *p)
}
msix_pba.resize(pba_size, tmp2);
}
+ MSIX_TABLE_OFFSET = msixcap.mtab & 0xfffffffc;
+ MSIX_TABLE_END = MSIX_TABLE_OFFSET +
+ (msixcap_mxc_ts + 1) * sizeof(MSIXTable);
+ MSIX_PBA_OFFSET = msixcap.mpba & 0xfffffffc;
+ MSIX_PBA_END = MSIX_PBA_OFFSET +
+ ((msixcap_mxc_ts + 1) / MSIXVECS_PER_PBA)
+ * sizeof(MSIXPbaEntry);
+ if (((msixcap_mxc_ts + 1) % MSIXVECS_PER_PBA) > 0) {
+ MSIX_PBA_END += sizeof(MSIXPbaEntry);
+ }
// PXCAP
- pxcap.pxid.cid = p->PXCAPCapId;
- pxcap.pxid.next = p->PXCAPNextCapability;
+ pxcap.pxid = (uint16_t)p->PXCAPCapId; //pxid.cid
+ pxcap.pxid |= (uint16_t)p->PXCAPNextCapability << 8; //pxid.next
pxcap.pxcap = p->PXCAPCapabilities;
pxcap.pxdcap = p->PXCAPDevCapabilities;
pxcap.pxdc = p->PXCAPDevCtrl;
@@ -253,8 +271,30 @@ Tick
PciDevice::readConfig(PacketPtr pkt)
{
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
- if (offset >= PCI_DEVICE_SPECIFIC)
- panic("Device specific PCI config space not implemented!\n");
+
+ /* Return 0 for accesses to unimplemented PCI configspace areas */
+ if (offset >= PCI_DEVICE_SPECIFIC &&
+ offset < PCI_CONFIG_SIZE) {
+ warn_once("Device specific PCI config space "
+ "not implemented for %s!\n", this->name());
+ switch (pkt->getSize()) {
+ case sizeof(uint8_t):
+ pkt->set<uint8_t>(0);
+ break;
+ case sizeof(uint16_t):
+ pkt->set<uint16_t>(0);
+ break;
+ case sizeof(uint32_t):
+ pkt->set<uint32_t>(0);
+ break;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ } else if (offset > PCI_CONFIG_SIZE) {
+ panic("Out-of-range access to PCI config space!\n");
+ }
+
+
pkt->allocate();
@@ -303,8 +343,23 @@ Tick
PciDevice::writeConfig(PacketPtr pkt)
{
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
- if (offset >= PCI_DEVICE_SPECIFIC)
- panic("Device specific PCI config space not implemented!\n");
+
+ /* No effect if we write to config space that is not implemented*/
+ if (offset >= PCI_DEVICE_SPECIFIC &&
+ offset < PCI_CONFIG_SIZE) {
+ warn_once("Device specific PCI config space "
+ "not implemented for %s!\n", this->name());
+ switch (pkt->getSize()) {
+ case sizeof(uint8_t):
+ case sizeof(uint16_t):
+ case sizeof(uint32_t):
+ break;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ } else if (offset > PCI_CONFIG_SIZE) {
+ panic("Out-of-range access to PCI config space!\n");
+ }
switch (pkt->getSize()) {
case sizeof(uint8_t):
@@ -448,7 +503,8 @@ PciDevice::serialize(std::ostream &os)
// Only serialize if we have a non-zero base address
if (MSIXCAP_BASE != 0x0) {
- int msix_array_size = msixcap.mxc.ts + 1;
+ uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff;
+ int msix_array_size = msixcap_mxc_ts + 1;
int pba_array_size = msix_array_size/MSIXVECS_PER_PBA;
if ((msix_array_size % MSIXVECS_PER_PBA) > 0) {
pba_array_size++;