summaryrefslogtreecommitdiff
path: root/src/dev/pcidev.cc
diff options
context:
space:
mode:
authorGeoffrey Blake <Geoffrey.Blake@arm.com>2014-10-16 05:49:57 -0400
committerGeoffrey Blake <Geoffrey.Blake@arm.com>2014-10-16 05:49:57 -0400
commit2d2006ddb3df926d79d0d744af81e8260f5c466c (patch)
treea6ac888662a8f0b1c90827f22c3abd260cba289c /src/dev/pcidev.cc
parentd6732895a5c2e81da47ada339b5d9269c02e5e8b (diff)
downloadgem5-2d2006ddb3df926d79d0d744af81e8260f5c466c.tar.xz
dev: refactor pci config space for sysfs scanning
Sysfs on ubuntu scrapes the entire PCI config space when it discovers a device using 4 byte accesses. This was not supported by our devices, in particular the NIC that implemented the extended PCI config space. This change allows the extended PCI config space to be accessed by sysfs properly.
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++;