summaryrefslogtreecommitdiff
path: root/src/dev
diff options
context:
space:
mode:
authorGeoffrey Blake <Geoffrey.Blake@arm.com>2013-10-31 13:41:13 -0500
committerGeoffrey Blake <Geoffrey.Blake@arm.com>2013-10-31 13:41:13 -0500
commitc32fbb7c008d86abc59f56c93b1ff5876fff0ab3 (patch)
tree7ea346abfcb7bf1c55d6fccec0d358e042993856 /src/dev
parentbe4aa2b6ba0b70b13df2ad84a372320c5a7ea939 (diff)
downloadgem5-c32fbb7c008d86abc59f56c93b1ff5876fff0ab3.tar.xz
dev: Add support for MSI-X and Capability Lists for ARM and PCI devices
This patch adds the registers and fields to the PCI device to support Capability lists and to support MSI-X in the GIC.
Diffstat (limited to 'src/dev')
-rw-r--r--src/dev/Pci.py63
-rw-r--r--src/dev/arm/Gic.py2
-rw-r--r--src/dev/arm/gic_pl390.cc63
-rw-r--r--src/dev/arm/gic_pl390.hh18
-rw-r--r--src/dev/pcidev.cc224
-rw-r--r--src/dev/pcidev.hh32
-rw-r--r--src/dev/pcireg.h317
7 files changed, 709 insertions, 10 deletions
diff --git a/src/dev/Pci.py b/src/dev/Pci.py
index fa3fc854e..79ea1f68a 100644
--- a/src/dev/Pci.py
+++ b/src/dev/Pci.py
@@ -1,3 +1,15 @@
+# Copyright (c) 2013 ARM Limited
+# All rights reserved
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder. You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
@@ -91,9 +103,60 @@ class PciDevice(DmaDevice):
SubsystemID = Param.UInt16(0x00, "Subsystem ID")
SubsystemVendorID = Param.UInt16(0x00, "Subsystem Vendor ID")
ExpansionROM = Param.UInt32(0x00, "Expansion ROM Base Address")
+ CapabilityPtr = Param.UInt8(0x00, "Capability List Pointer offset")
InterruptLine = Param.UInt8(0x00, "Interrupt Line")
InterruptPin = Param.UInt8(0x00, "Interrupt Pin")
MaximumLatency = Param.UInt8(0x00, "Maximum Latency")
MinimumGrant = Param.UInt8(0x00, "Minimum Grant")
+ # Capabilities List structures for PCIe devices
+ # PMCAP - PCI Power Management Capability
+ PMCAPBaseOffset = \
+ Param.UInt8(0x00, "Base offset of PMCAP in PCI Config space")
+ PMCAPNextCapability = \
+ Param.UInt8(0x00, "Pointer to next capability block")
+ PMCAPCapId = \
+ Param.UInt8(0x00, "Specifies this is the Power Management capability")
+ PMCAPCapabilities = \
+ Param.UInt16(0x0000, "PCI Power Management Capabilities Register")
+ PMCAPCtrlStatus = \
+ Param.UInt16(0x0000, "PCI Power Management Control and Status")
+
+ # MSICAP - Message Signaled Interrupt Capability
+ MSICAPBaseOffset = \
+ Param.UInt8(0x00, "Base offset of MSICAP in PCI Config space")
+ MSICAPNextCapability = \
+ Param.UInt8(0x00, "Pointer to next capability block")
+ MSICAPCapId = Param.UInt8(0x00, "Specifies this is the MSI Capability")
+ MSICAPMsgCtrl = Param.UInt16(0x0000, "MSI Message Control")
+ MSICAPMsgAddr = Param.UInt32(0x00000000, "MSI Message Address")
+ MSICAPMsgUpperAddr = Param.UInt32(0x00000000, "MSI Message Upper Address")
+ MSICAPMsgData = Param.UInt16(0x0000, "MSI Message Data")
+ MSICAPMaskBits = Param.UInt32(0x00000000, "MSI Interrupt Mask Bits")
+ MSICAPPendingBits = Param.UInt32(0x00000000, "MSI Pending Bits")
+
+ # MSIXCAP - MSI-X Capability
+ MSIXCAPBaseOffset = \
+ Param.UInt8(0x00, "Base offset of MSIXCAP in PCI Config space")
+ MSIXCAPNextCapability = \
+ Param.UInt8(0x00, "Pointer to next capability block")
+ MSIXCAPCapId = Param.UInt8(0x00, "Specifices this the MSI-X Capability")
+ MSIXMsgCtrl = Param.UInt16(0x0000, "MSI-X Message Control")
+ MSIXTableOffset = \
+ Param.UInt32(0x00000000, "MSI-X Table Offset and Table BIR")
+ MSIXPbaOffset = Param.UInt32(0x00000000, "MSI-X PBA Offset and PBA BIR")
+ # PXCAP - PCI Express Capability
+ PXCAPBaseOffset = \
+ Param.UInt8(0x00, "Base offset of PXCAP in PCI Config space")
+ PXCAPNextCapability = Param.UInt8(0x00, "Pointer to next capability block")
+ PXCAPCapId = Param.UInt8(0x00, "Specifies this is the PCIe Capability")
+ PXCAPCapabilities = Param.UInt16(0x0000, "PCIe Capabilities")
+ PXCAPDevCapabilities = Param.UInt32(0x00000000, "PCIe Device Capabilities")
+ PXCAPDevCtrl = Param.UInt16(0x0000, "PCIe Device Control")
+ PXCAPDevStatus = Param.UInt16(0x0000, "PCIe Device Status")
+ PXCAPLinkCap = Param.UInt32(0x00000000, "PCIe Link Capabilities")
+ PXCAPLinkCtrl = Param.UInt16(0x0000, "PCIe Link Control")
+ PXCAPLinkStatus = Param.UInt16(0x0000, "PCIe Link Status")
+ PXCAPDevCap2 = Param.UInt32(0x00000000, "PCIe Device Capabilities 2")
+ PXCAPDevCtrl2 = Param.UInt32(0x00000000, "PCIe Device Control 2")
diff --git a/src/dev/arm/Gic.py b/src/dev/arm/Gic.py
index 0461758ed..766049296 100644
--- a/src/dev/arm/Gic.py
+++ b/src/dev/arm/Gic.py
@@ -54,8 +54,8 @@ class Pl390(BaseGic):
dist_addr = Param.Addr(0x1f001000, "Address for distributor")
cpu_addr = Param.Addr(0x1f000100, "Address for cpu")
+ msix_addr = Param.Addr(0x0, "Address for MSI-X register")
dist_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to distributor")
cpu_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to cpu interface")
int_latency = Param.Latency('10ns', "Delay for interrupt to get to CPU")
it_lines = Param.UInt32(128, "Number of interrupt lines supported (max = 1020)")
-
diff --git a/src/dev/arm/gic_pl390.cc b/src/dev/arm/gic_pl390.cc
index fc49aa63e..d2a660e88 100644
--- a/src/dev/arm/gic_pl390.cc
+++ b/src/dev/arm/gic_pl390.cc
@@ -56,7 +56,8 @@ Pl390::Pl390(const Params *p)
: BaseGic(p), distAddr(p->dist_addr),
cpuAddr(p->cpu_addr), distPioDelay(p->dist_pio_delay),
cpuPioDelay(p->cpu_pio_delay), intLatency(p->int_latency),
- enabled(false), itLines(p->it_lines)
+ enabled(false), itLines(p->it_lines), msixRegAddr(p->msix_addr),
+ msixReg(0x0)
{
itLinesLog2 = ceilLog2(itLines);
@@ -117,6 +118,10 @@ Pl390::read(PacketPtr pkt)
return readDistributor(pkt);
else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE)
return readCpu(pkt);
+ else if (msixRegAddr != 0x0 &&
+ addr >= msixRegAddr &&
+ addr < msixRegAddr + MSIX_SIZE)
+ return readMsix(pkt);
else
panic("Read to unknown address %#x\n", pkt->getAddr());
}
@@ -132,6 +137,10 @@ Pl390::write(PacketPtr pkt)
return writeDistributor(pkt);
else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE)
return writeCpu(pkt);
+ else if (msixRegAddr != 0x0 &&
+ addr >= msixRegAddr &&
+ addr < msixRegAddr + MSIX_SIZE)
+ return writeMsix(pkt);
else
panic("Write to unknown address %#x\n", pkt->getAddr());
}
@@ -355,6 +364,26 @@ Pl390::readCpu(PacketPtr pkt)
return cpuPioDelay;
}
+Tick
+Pl390::readMsix(PacketPtr pkt)
+{
+ Addr daddr = pkt->getAddr() - msixRegAddr;
+ pkt->allocate();
+
+ DPRINTF(GIC, "Gic MSIX read register %#x\n", daddr);
+
+ switch (daddr) {
+ case MSIX_SR:
+ pkt->set<uint32_t>(msixReg);
+ break;
+ default:
+ panic("Tried to read Gic MSIX register at offset %#x\n", daddr);
+ break;
+ }
+
+ pkt->makeAtomicResponse();
+ return distPioDelay;
+}
Tick
Pl390::writeDistributor(PacketPtr pkt)
@@ -535,6 +564,31 @@ Pl390::writeCpu(PacketPtr pkt)
return cpuPioDelay;
}
+Tick
+Pl390::writeMsix(PacketPtr pkt)
+{
+ Addr daddr = pkt->getAddr() - msixRegAddr;
+ pkt->allocate();
+
+ DPRINTF(GIC, "Gic MSI-X write register %#x data %d\n",
+ daddr, pkt->get<uint32_t>());
+
+ switch (daddr) {
+ case MSIX_SR:
+ // This value is little endian, just like the ARM guest
+ msixReg = pkt->get<uint32_t>();
+ pendingInt[intNumToWord(letoh(msixReg))] |= 1UL << intNumToBit(letoh(msixReg));
+ updateIntState(-1);
+ break;
+ default:
+ panic("Tried to write Gic MSI-X register at offset %#x\n", daddr);
+ break;
+ }
+
+ pkt->makeAtomicResponse();
+ return distPioDelay;
+}
+
void
Pl390::softInt(int ctx_id, SWI swi)
{
@@ -726,6 +780,9 @@ Pl390::getAddrRanges() const
AddrRangeList ranges;
ranges.push_back(RangeSize(distAddr, DIST_SIZE));
ranges.push_back(RangeSize(cpuAddr, CPU_SIZE));
+ if (msixRegAddr != 0) {
+ ranges.push_back(RangeSize(msixRegAddr, MSIX_SIZE));
+ }
return ranges;
}
@@ -742,6 +799,8 @@ Pl390::serialize(std::ostream &os)
SERIALIZE_SCALAR(enabled);
SERIALIZE_SCALAR(itLines);
SERIALIZE_SCALAR(itLinesLog2);
+ SERIALIZE_SCALAR(msixRegAddr);
+ SERIALIZE_SCALAR(msixReg);
SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
SERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
@@ -782,6 +841,8 @@ Pl390::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(enabled);
UNSERIALIZE_SCALAR(itLines);
UNSERIALIZE_SCALAR(itLinesLog2);
+ UNSERIALIZE_SCALAR(msixRegAddr);
+ UNSERIALIZE_SCALAR(msixReg);
UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
diff --git a/src/dev/arm/gic_pl390.hh b/src/dev/arm/gic_pl390.hh
index 2621e1a27..5b84ea92b 100644
--- a/src/dev/arm/gic_pl390.hh
+++ b/src/dev/arm/gic_pl390.hh
@@ -113,6 +113,10 @@ class Pl390 : public BaseGic
static const int INT_BITS_MAX = 32;
static const int INT_LINES_MAX = 1020;
+ /** MSI-X register offset and size */
+ static const int MSIX_SR = 0x0; // MSI register devices will write to
+ static const int MSIX_SIZE = 0x4; // Size of MSI-X register space
+
BitUnion32(SWI)
Bitfield<3,0> sgi_id;
Bitfield<23,16> cpu_list;
@@ -207,6 +211,10 @@ class Pl390 : public BaseGic
/** IRQ Enable Used for debug */
bool irqEnable;
+ /** MSIX Register */
+ Addr msixRegAddr;
+ uint32_t msixReg;
+
/** software generated interrupt
* @param data data to decode that indicates which cpus to interrupt
*/
@@ -314,6 +322,11 @@ class Pl390 : public BaseGic
*/
Tick readCpu(PacketPtr pkt);
+ /** Handle a read to the MSI-X register on the GIC
+ * @param pkt packet to respond to
+ */
+ Tick readMsix(PacketPtr pkt);
+
/** Handle a write to the distributor poriton of the GIC
* @param pkt packet to respond to
*/
@@ -323,6 +336,11 @@ class Pl390 : public BaseGic
* @param pkt packet to respond to
*/
Tick writeCpu(PacketPtr pkt);
+
+ /** Handle a write to the MSI-X register on the GIC
+ * @param pkt packet to process
+ */
+ Tick writeMsix(PacketPtr pkt);
};
#endif //__DEV_ARM_GIC_H__
diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc
index 3ca807d06..a24fa8da8 100644
--- a/src/dev/pcidev.cc
+++ b/src/dev/pcidev.cc
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2013 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -83,7 +95,13 @@ PciDevice::PciConfigPort::getAddrRanges() const
PciDevice::PciDevice(const Params *p)
- : DmaDevice(p), platform(p->platform), pioDelay(p->pio_latency),
+ : DmaDevice(p),
+ PMCAP_BASE(p->PMCAPBaseOffset),
+ MSICAP_BASE(p->MSICAPBaseOffset),
+ MSIXCAP_BASE(p->MSIXCAPBaseOffset),
+ PXCAP_BASE(p->PXCAPBaseOffset),
+ platform(p->platform),
+ pioDelay(p->pio_latency),
configDelay(p->config_latency),
configPort(this, params()->pci_bus, params()->pci_dev,
params()->pci_func, params()->platform)
@@ -111,13 +129,74 @@ PciDevice::PciDevice(const Params *p)
config.subsystemVendorID = htole(p->SubsystemVendorID);
config.subsystemID = htole(p->SubsystemID);
config.expansionROM = htole(p->ExpansionROM);
- config.reserved0 = 0;
- config.reserved1 = 0;
+ config.capabilityPtr = htole(p->CapabilityPtr);
+ // Zero out the 7 bytes of reserved space in the PCI Config space register.
+ bzero(config.reserved, 7*sizeof(uint8_t));
config.interruptLine = htole(p->InterruptLine);
config.interruptPin = htole(p->InterruptPin);
config.minimumGrant = htole(p->MinimumGrant);
config.maximumLatency = htole(p->MaximumLatency);
+ // Initialize the capability lists
+ // These structs are bitunions, meaning the data is stored in host
+ // 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.pc = p->PMCAPCapabilities;
+ pmcap.pmcs = p->PMCAPCtrlStatus;
+
+ // MSICAP
+ msicap.mid.cid = p->MSICAPCapId;
+ msicap.mid.next = p->MSICAPNextCapability;
+ msicap.mc = p->MSICAPMsgCtrl;
+ msicap.ma = p->MSICAPMsgAddr;
+ msicap.mua = p->MSICAPMsgUpperAddr;
+ msicap.md = p->MSICAPMsgData;
+ msicap.mmask = p->MSICAPMaskBits;
+ msicap.mpend = p->MSICAPPendingBits;
+
+ // MSIXCAP
+ msixcap.mxid.cid = p->MSIXCAPCapId;
+ msixcap.mxid.next = p->MSIXCAPNextCapability;
+ msixcap.mxc = p->MSIXMsgCtrl;
+ msixcap.mtab = p->MSIXTableOffset;
+ msixcap.mpba = p->MSIXPbaOffset;
+
+ // allocate MSIX structures if MSIXCAP_BASE
+ // indicates the MSIXCAP is being used by having a
+ // non-zero base address.
+ // The MSIX tables are stored by the guest in
+ // little endian byte-order as according the
+ // PCIe specification. Make sure to take the proper
+ // actions when manipulating these tables on the host
+ if (MSIXCAP_BASE != 0x0) {
+ int msix_vecs = msixcap.mxc.ts + 1;
+ MSIXTable tmp1 = {{0UL,0UL,0UL,0UL}};
+ msix_table.resize(msix_vecs, tmp1);
+
+ MSIXPbaEntry tmp2 = {0};
+ int pba_size = msix_vecs / MSIXVECS_PER_PBA;
+ if ((msix_vecs % MSIXVECS_PER_PBA) > 0) {
+ pba_size++;
+ }
+ msix_pba.resize(pba_size, tmp2);
+ }
+
+ // PXCAP
+ pxcap.pxid.cid = p->PXCAPCapId;
+ pxcap.pxid.next = p->PXCAPNextCapability;
+ pxcap.pxcap = p->PXCAPCapabilities;
+ pxcap.pxdcap = p->PXCAPDevCapabilities;
+ pxcap.pxdc = p->PXCAPDevCtrl;
+ pxcap.pxds = p->PXCAPDevStatus;
+ pxcap.pxlcap = p->PXCAPLinkCap;
+ pxcap.pxlc = p->PXCAPLinkCtrl;
+ pxcap.pxls = p->PXCAPLinkStatus;
+ pxcap.pxdcap2 = p->PXCAPDevCap2;
+ pxcap.pxdc2 = p->PXCAPDevCtrl2;
+
BARSize[0] = p->BAR0Size;
BARSize[1] = p->BAR1Size;
BARSize[2] = p->BAR2Size;
@@ -348,6 +427,62 @@ PciDevice::serialize(std::ostream &os)
SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0]));
SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0]));
+
+ // serialize the capability list registers
+ paramOut(os, csprintf("pmcap.pid"), uint16_t(pmcap.pid));
+ paramOut(os, csprintf("pmcap.pc"), uint16_t(pmcap.pc));
+ paramOut(os, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs));
+
+ paramOut(os, csprintf("msicap.mid"), uint16_t(msicap.mid));
+ paramOut(os, csprintf("msicap.mc"), uint16_t(msicap.mc));
+ paramOut(os, csprintf("msicap.ma"), uint32_t(msicap.ma));
+ SERIALIZE_SCALAR(msicap.mua);
+ paramOut(os, csprintf("msicap.md"), uint16_t(msicap.md));
+ SERIALIZE_SCALAR(msicap.mmask);
+ SERIALIZE_SCALAR(msicap.mpend);
+
+ paramOut(os, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid));
+ paramOut(os, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc));
+ paramOut(os, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab));
+ paramOut(os, csprintf("msixcap.mpba"), uint32_t(msixcap.mpba));
+
+ // Only serialize if we have a non-zero base address
+ if (MSIXCAP_BASE != 0x0) {
+ 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++;
+ }
+
+ SERIALIZE_SCALAR(msix_array_size);
+ SERIALIZE_SCALAR(pba_array_size);
+
+ for (int i = 0; i < msix_array_size; i++) {
+ paramOut(os, csprintf("msix_table[%d].addr_lo", i),
+ msix_table[i].fields.addr_lo);
+ paramOut(os, csprintf("msix_table[%d].addr_hi", i),
+ msix_table[i].fields.addr_hi);
+ paramOut(os, csprintf("msix_table[%d].msg_data", i),
+ msix_table[i].fields.msg_data);
+ paramOut(os, csprintf("msix_table[%d].vec_ctrl", i),
+ msix_table[i].fields.vec_ctrl);
+ }
+ for (int i = 0; i < pba_array_size; i++) {
+ paramOut(os, csprintf("msix_pba[%d].bits", i),
+ msix_pba[i].bits);
+ }
+ }
+
+ paramOut(os, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid));
+ paramOut(os, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap));
+ paramOut(os, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap));
+ paramOut(os, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc));
+ paramOut(os, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds));
+ paramOut(os, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap));
+ paramOut(os, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc));
+ paramOut(os, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls));
+ paramOut(os, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2));
+ paramOut(os, csprintf("pxcap.pxdc2"), uint32_t(pxcap.pxdc2));
}
void
@@ -357,7 +492,88 @@ PciDevice::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
UNSERIALIZE_ARRAY(config.data,
sizeof(config.data) / sizeof(config.data[0]));
- pioPort.sendRangeChange();
+ // unserialize the capability list registers
+ uint16_t tmp16;
+ uint32_t tmp32;
+ paramIn(cp, section, csprintf("pmcap.pid"), tmp16);
+ pmcap.pid = tmp16;
+ paramIn(cp, section, csprintf("pmcap.pc"), tmp16);
+ pmcap.pc = tmp16;
+ paramIn(cp, section, csprintf("pmcap.pmcs"), tmp16);
+ pmcap.pmcs = tmp16;
+
+ paramIn(cp, section, csprintf("msicap.mid"), tmp16);
+ msicap.mid = tmp16;
+ paramIn(cp, section, csprintf("msicap.mc"), tmp16);
+ msicap.mc = tmp16;
+ paramIn(cp, section, csprintf("msicap.ma"), tmp32);
+ msicap.ma = tmp32;
+ UNSERIALIZE_SCALAR(msicap.mua);
+ paramIn(cp, section, csprintf("msicap.md"), tmp16);;
+ msicap.md = tmp16;
+ UNSERIALIZE_SCALAR(msicap.mmask);
+ UNSERIALIZE_SCALAR(msicap.mpend);
+
+ paramIn(cp, section, csprintf("msixcap.mxid"), tmp16);
+ msixcap.mxid = tmp16;
+ paramIn(cp, section, csprintf("msixcap.mxc"), tmp16);
+ msixcap.mxc = tmp16;
+ paramIn(cp, section, csprintf("msixcap.mtab"), tmp32);
+ msixcap.mtab = tmp32;
+ paramIn(cp, section, csprintf("msixcap.mpba"), tmp32);
+ msixcap.mpba = tmp32;
+
+ // Only allocate if MSIXCAP_BASE is not 0x0
+ if (MSIXCAP_BASE != 0x0) {
+ int msix_array_size;
+ int pba_array_size;
+
+ UNSERIALIZE_SCALAR(msix_array_size);
+ UNSERIALIZE_SCALAR(pba_array_size);
+
+ MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}};
+ msix_table.resize(msix_array_size, tmp1);
+
+ MSIXPbaEntry tmp2 = {0};
+ msix_pba.resize(pba_array_size, tmp2);
+
+ for (int i = 0; i < msix_array_size; i++) {
+ paramIn(cp, section, csprintf("msix_table[%d].addr_lo", i),
+ msix_table[i].fields.addr_lo);
+ paramIn(cp, section, csprintf("msix_table[%d].addr_hi", i),
+ msix_table[i].fields.addr_hi);
+ paramIn(cp, section, csprintf("msix_table[%d].msg_data", i),
+ msix_table[i].fields.msg_data);
+ paramIn(cp, section, csprintf("msix_table[%d].vec_ctrl", i),
+ msix_table[i].fields.vec_ctrl);
+ }
+ for (int i = 0; i < pba_array_size; i++) {
+ paramIn(cp, section, csprintf("msix_pba[%d].bits", i),
+ msix_pba[i].bits);
+ }
+ }
+
+ paramIn(cp, section, csprintf("pxcap.pxid"), tmp16);
+ pxcap.pxid = tmp16;
+ paramIn(cp, section, csprintf("pxcap.pxcap"), tmp16);
+ pxcap.pxcap = tmp16;
+ paramIn(cp, section, csprintf("pxcap.pxdcap"), tmp32);
+ pxcap.pxdcap = tmp32;
+ paramIn(cp, section, csprintf("pxcap.pxdc"), tmp16);
+ pxcap.pxdc = tmp16;
+ paramIn(cp, section, csprintf("pxcap.pxds"), tmp16);
+ pxcap.pxds = tmp16;
+ paramIn(cp, section, csprintf("pxcap.pxlcap"), tmp32);
+ pxcap.pxlcap = tmp32;
+ paramIn(cp, section, csprintf("pxcap.pxlc"), tmp16);
+ pxcap.pxlc = tmp16;
+ paramIn(cp, section, csprintf("pxcap.pxls"), tmp16);
+ pxcap.pxls = tmp16;
+ paramIn(cp, section, csprintf("pxcap.pxdcap2"), tmp32);
+ pxcap.pxdcap2 = tmp32;
+ paramIn(cp, section, csprintf("pxcap.pxdc2"), tmp32);
+ pxcap.pxdc2 = tmp32;
+ pioPort.sendRangeChange();
}
diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh
index d4820c0ee..4f3dfd219 100644
--- a/src/dev/pcidev.hh
+++ b/src/dev/pcidev.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2013 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -38,6 +50,7 @@
#define __DEV_PCIDEV_HH__
#include <cstring>
+#include <vector>
#include "dev/dma_device.hh"
#include "dev/pcireg.h"
@@ -91,6 +104,25 @@ class PciDevice : public DmaDevice
protected:
/** The current config space. */
PCIConfig config;
+ /** The capability list structures and base addresses
+ * @{
+ */
+ const int PMCAP_BASE;
+ PMCAP pmcap;
+
+ const int MSICAP_BASE;
+ MSICAP msicap;
+
+ const int MSIXCAP_BASE;
+ MSIXCAP msixcap;
+
+ const int PXCAP_BASE;
+ PXCAP pxcap;
+ /** @} */
+
+ /** MSIX Table and PBA Structures */
+ std::vector<MSIXTable> msix_table;
+ std::vector<MSIXPbaEntry> msix_pba;
/** The size of the BARs */
uint32_t BARSize[6];
diff --git a/src/dev/pcireg.h b/src/dev/pcireg.h
index 5639d8e29..045b88965 100644
--- a/src/dev/pcireg.h
+++ b/src/dev/pcireg.h
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2013 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -38,6 +50,9 @@
#include <sys/types.h>
+#include "base/bitfield.hh"
+#include "base/bitunion.hh"
+
union PCIConfig {
uint8_t data[64];
@@ -59,8 +74,11 @@ union PCIConfig {
uint16_t subsystemVendorID;
uint16_t subsystemID;
uint32_t expansionROM;
- uint32_t reserved0;
- uint32_t reserved1;
+ uint8_t capabilityPtr;
+ // Was 8 bytes in the legacy PCI spec, but to support PCIe
+ // this field is now 7 bytes with PCIe's addition of the
+ // capability list pointer.
+ uint8_t reserved[7];
uint8_t interruptLine;
uint8_t interruptPin;
uint8_t minimumGrant;
@@ -98,8 +116,8 @@ union PCIConfig {
#define PCI0_SUB_VENDOR_ID 0x2C // Sub-Vendor ID ro
#define PCI0_SUB_SYSTEM_ID 0x2E // Sub-System ID ro
#define PCI0_ROM_BASE_ADDR 0x30 // Expansion ROM Base Address rw
-#define PCI0_RESERVED0 0x34
-#define PCI0_RESERVED1 0x38
+#define PCI0_CAP_PTR 0x34 // Capability list pointer ro
+#define PCI0_RESERVED 0x35
#define PCI0_INTERRUPT_LINE 0x3C // Interrupt Line rw
#define PCI0_INTERRUPT_PIN 0x3D // Interrupt Pin ro
#define PCI0_MINIMUM_GRANT 0x3E // Maximum Grant ro
@@ -146,4 +164,295 @@ union PCIConfig {
#define PCI_PRODUCT_SIMOS_SIMOS 0x1291
#define PCI_PRODUCT_SIMOS_ETHER 0x1292
+/**
+ * PCIe capability list offsets internal to the entry.
+ * Actual offsets in the PCI config space are defined in
+ * the python files setting up the system.
+ */
+#define PMCAP_ID 0x00
+#define PMCAP_PC 0x02
+#define PMCAP_PMCS 0x04
+#define PMCAP_SIZE 0x06
+
+#define MSICAP_ID 0x00
+#define MSICAP_MC 0x02
+#define MSICAP_MA 0x04
+#define MSICAP_MUA 0x08
+#define MSICAP_MD 0x0C
+#define MSICAP_MMASK 0x10
+#define MSICAP_MPEND 0x14
+#define MSICAP_SIZE 0x18
+
+#define MSIXCAP_ID 0x00
+#define MSIXCAP_MXC 0x02
+#define MSIXCAP_MTAB 0x04
+#define MSIXCAP_MPBA 0x08
+#define MSIXCAP_SIZE 0x0C
+
+#define PXCAP_ID 0x00
+#define PXCAP_PXCAP 0x02
+#define PXCAP_PXDCAP 0x04
+#define PXCAP_PXDC 0x08
+#define PXCAP_PXDS 0x0A
+#define PXCAP_PXLCAP 0x0C
+#define PXCAP_PXLC 0x10
+#define PXCAP_PXLS 0x12
+#define PXCAP_PXDCAP2 0x24
+#define PXCAP_PXDC2 0x28
+#define PXCAP_SIZE 0x30
+
+/** @struct PMCAP
+ * Defines the Power Management capability register and all its associated
+ * bitfields for a PCIe device.
+ */
+struct PMCAP {
+ BitUnion16(PID)
+ Bitfield<7,0> cid;
+ Bitfield<15,8> next;
+ EndBitUnion(PID)
+ PID pid;
+
+ BitUnion16(PC)
+ Bitfield<2,0> vs;
+ Bitfield<3> pmec;
+ Bitfield<4> reserved;
+ Bitfield<5> dsi;
+ Bitfield<8,6> auxc;
+ Bitfield<9> d1s;
+ Bitfield<10> d2s;
+ Bitfield<15,11> psup;
+ EndBitUnion(PC)
+ PC pc;
+
+ BitUnion16(PMCS)
+ Bitfield<1,0> ps;
+ Bitfield<2> reserved0;
+ Bitfield<3> nsfrst;
+ Bitfield<7,4> reserved1;
+ Bitfield<8> pmee;
+ Bitfield<12,9> dse;
+ Bitfield<14,13> dsc;
+ Bitfield<15> pmes;
+ EndBitUnion(PMCS)
+ PMCS pmcs;
+};
+
+/** @struct MSICAP
+ * Defines the MSI Capability register and its associated bitfields for
+ * the a PCI/PCIe device. Both the MSI capability and the MSIX capability
+ * can be filled in if a device model supports both, but only 1 of
+ * MSI/MSIX/INTx interrupt mode can be selected at a given time.
+ */
+struct MSICAP {
+ BitUnion16(MID)
+ Bitfield<7,0> cid;
+ Bitfield<15,8> next;
+ EndBitUnion(MID)
+ MID mid;
+
+ BitUnion16(MC)
+ Bitfield<0> msie;
+ Bitfield<3,1> mmc;
+ Bitfield<6,4> mme;
+ Bitfield<7> c64;
+ Bitfield<8> pvm;
+ Bitfield<15,9> reserved;
+ EndBitUnion(MC)
+ MC mc;
+
+ BitUnion32(MA)
+ Bitfield<1,0> reserved;
+ Bitfield<31,2> addr;
+ EndBitUnion(MA)
+ MA ma;
+
+ uint32_t mua;
+
+ BitUnion16(MD)
+ Bitfield<15,0> data;
+ EndBitUnion(MD)
+ MD md;
+
+ uint32_t mmask;
+ uint32_t mpend;
+};
+
+/** @struct MSIX
+ * Defines the MSI-X Capability register and its associated bitfields for
+ * a PCIe device.
+ */
+struct MSIXCAP {
+ BitUnion16(MXID)
+ Bitfield<7,0> cid;
+ Bitfield<15,8> next;
+ EndBitUnion(MXID)
+ MXID mxid;
+
+ BitUnion16(MXC)
+ Bitfield<10,0> ts;
+ Bitfield<13,11> reserved;
+ Bitfield<14> fm;
+ Bitfield<15> mxe;
+ EndBitUnion(MXC)
+ MXC mxc;
+
+ BitUnion32(MTAB)
+ Bitfield<31,3> to;
+ Bitfield<2,0> tbir;
+ EndBitUnion(MTAB)
+ MTAB mtab;
+
+ BitUnion32(MPBA)
+ Bitfield<2,0> pbir;
+ Bitfield<31,3> pbao;
+ EndBitUnion(MPBA)
+ MPBA mpba;
+};
+
+union MSIXTable {
+ struct {
+ uint32_t addr_lo;
+ uint32_t addr_hi;
+ uint32_t msg_data;
+ uint32_t vec_ctrl;
+ } fields;
+ uint32_t data[4];
+};
+
+#define MSIXVECS_PER_PBA 64
+struct MSIXPbaEntry {
+ uint64_t bits;
+};
+
+/** @struct PXCAP
+ * Defines the PCI Express capability register and its associated bitfields
+ * for a PCIe device.
+ */
+struct PXCAP {
+ BitUnion16(PXID)
+ Bitfield<7,0> cid;
+ Bitfield<15,8> next;
+ EndBitUnion(PXID)
+ PXID pxid;
+
+ BitUnion16(_PXCAP)
+ Bitfield<3,0> ver;
+ Bitfield<7,4> dpt;
+ Bitfield<8> si;
+ Bitfield<13,9> imn;
+ Bitfield<15,14> reserved;
+ EndBitUnion(_PXCAP)
+ _PXCAP pxcap;
+
+ BitUnion32(PXDCAP)
+ Bitfield<2,0> mps;
+ Bitfield<4,3> pfs;
+ Bitfield<5> etfs;
+ Bitfield<8,6> l0sl;
+ Bitfield<11,9> l1l;
+ Bitfield<14,12> reserved0;
+ Bitfield<15> rer;
+ Bitfield<17,16> reserved1;
+ Bitfield<25,18> csplv;
+ Bitfield<27,26> cspls;
+ Bitfield<28> flrc;
+ Bitfield<31,29> reserved2;
+ EndBitUnion(PXDCAP)
+ PXDCAP pxdcap;
+
+ BitUnion16(PXDC)
+ Bitfield<0> cere;
+ Bitfield<1> nfere;
+ Bitfield<2> fere;
+ Bitfield<3> urre;
+ Bitfield<4> ero;
+ Bitfield<7,5> mps;
+ Bitfield<8> ete;
+ Bitfield<9> pfe;
+ Bitfield<10> appme;
+ Bitfield<11> ens;
+ Bitfield<14,12> mrrs;
+ Bitfield<15> func_reset;
+ EndBitUnion(PXDC)
+ PXDC pxdc;
+
+ BitUnion16(PXDS)
+ Bitfield<0> ced;
+ Bitfield<1> nfed;
+ Bitfield<2> fed;
+ Bitfield<3> urd;
+ Bitfield<4> apd;
+ Bitfield<5> tp;
+ Bitfield<15,6> reserved;
+ EndBitUnion(PXDS)
+ PXDS pxds;
+
+ BitUnion32(PXLCAP)
+ Bitfield<3,0> sls;
+ Bitfield<9,4> mlw;
+ Bitfield<11,10> aspms;
+ Bitfield<14,12> l0sel;
+ Bitfield<17,15> l1el;
+ Bitfield<18> cpm;
+ Bitfield<19> sderc;
+ Bitfield<20> dllla;
+ Bitfield<21> lbnc;
+ Bitfield<23,22> reserved;
+ Bitfield<31,24> pn;
+ EndBitUnion(PXLCAP)
+ PXLCAP pxlcap;
+
+ BitUnion16(PXLC)
+ Bitfield<1,0> aspmc;
+ Bitfield<2> reserved0;
+ Bitfield<3> rcb;
+ Bitfield<5,4> reserved1;
+ Bitfield<6> ccc;
+ Bitfield<7> es;
+ Bitfield<8> ecpm;
+ Bitfield<9> hawd;
+ Bitfield<15,10> reserved2;
+ EndBitUnion(PXLC)
+ PXLC pxlc;
+
+ BitUnion16(PXLS)
+ Bitfield<3,0> cls;
+ Bitfield<9,4> nlw;
+ Bitfield<11,10> reserved0;
+ Bitfield<12> slot_clk_config;
+ Bitfield<15,13> reserved1;
+ EndBitUnion(PXLS)
+ PXLS pxls;
+
+ BitUnion32(PXDCAP2)
+ Bitfield<3,0> ctrs;
+ Bitfield<4> ctds;
+ Bitfield<5> arifs;
+ Bitfield<6> aors;
+ Bitfield<7> aocs32;
+ Bitfield<8> aocs64;
+ Bitfield<9> ccs128;
+ Bitfield<10> nprpr;
+ Bitfield<11> ltrs;
+ Bitfield<13,12> tphcs;
+ Bitfield<17,14> reserved0;
+ Bitfield<19,18> obffs;
+ Bitfield<20> effs;
+ Bitfield<21> eetps;
+ Bitfield<23,22> meetp;
+ Bitfield<31,24> reserved1;
+ EndBitUnion(PXDCAP2)
+ PXDCAP2 pxdcap2;
+
+ BitUnion32(PXDC2)
+ Bitfield<3,0> ctv;
+ Bitfield<4> ctd;
+ Bitfield<9,5> reserved0;
+ Bitfield<10> ltrme;
+ Bitfield<12,11> reserved1;
+ Bitfield<14,13> obffe;
+ Bitfield<31,15> reserved2;
+ EndBitUnion(PXDC2)
+ PXDC2 pxdc2;
+};
#endif // __PCIREG_H__