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:
Geoffrey Blake
2013-10-31 13:41:13 -05:00
parent be4aa2b6ba
commit c32fbb7c00
7 changed files with 709 additions and 10 deletions

View File

@@ -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")

View File

@@ -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)")

View File

@@ -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);

View File

@@ -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__

View File

@@ -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();
}

View File

@@ -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];

View File

@@ -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__