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.
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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)")
|
||||
|
||||
|
||||
@@ -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 §ion)
|
||||
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);
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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 §ion)
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
317
src/dev/pcireg.h
317
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__
|
||||
|
||||
Reference in New Issue
Block a user