summaryrefslogtreecommitdiff
path: root/src/dev/pci
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev/pci')
-rw-r--r--src/dev/pci/PciDevice.py154
-rw-r--r--src/dev/pci/SConscript13
-rw-r--r--src/dev/pci/device.cc581
-rw-r--r--src/dev/pci/device.hh227
-rw-r--r--src/dev/pci/host.cc2
-rw-r--r--src/dev/pci/pcireg.h409
6 files changed, 1383 insertions, 3 deletions
diff --git a/src/dev/pci/PciDevice.py b/src/dev/pci/PciDevice.py
new file mode 100644
index 000000000..21e6edf62
--- /dev/null
+++ b/src/dev/pci/PciDevice.py
@@ -0,0 +1,154 @@
+# 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.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Nathan Binkert
+
+from m5.SimObject import SimObject
+from m5.params import *
+from m5.proxy import *
+from Device import DmaDevice
+from PciHost import PciHost
+
+class PciDevice(DmaDevice):
+ type = 'PciDevice'
+ cxx_class = 'PciDevice'
+ cxx_header = "dev/pci/device.hh"
+ abstract = True
+
+ host = Param.PciHost(Parent.any, "PCI host")
+ pci_bus = Param.Int("PCI bus")
+ pci_dev = Param.Int("PCI device number")
+ pci_func = Param.Int("PCI function code")
+
+ pio_latency = Param.Latency('30ns', "Programmed IO latency")
+ config_latency = Param.Latency('20ns', "Config read or write latency")
+
+ VendorID = Param.UInt16("Vendor ID")
+ DeviceID = Param.UInt16("Device ID")
+ Command = Param.UInt16(0, "Command")
+ Status = Param.UInt16(0, "Status")
+ Revision = Param.UInt8(0, "Device")
+ ProgIF = Param.UInt8(0, "Programming Interface")
+ SubClassCode = Param.UInt8(0, "Sub-Class Code")
+ ClassCode = Param.UInt8(0, "Class Code")
+ CacheLineSize = Param.UInt8(0, "System Cacheline Size")
+ LatencyTimer = Param.UInt8(0, "PCI Latency Timer")
+ HeaderType = Param.UInt8(0, "PCI Header Type")
+ BIST = Param.UInt8(0, "Built In Self Test")
+
+ BAR0 = Param.UInt32(0x00, "Base Address Register 0")
+ BAR1 = Param.UInt32(0x00, "Base Address Register 1")
+ BAR2 = Param.UInt32(0x00, "Base Address Register 2")
+ BAR3 = Param.UInt32(0x00, "Base Address Register 3")
+ BAR4 = Param.UInt32(0x00, "Base Address Register 4")
+ BAR5 = Param.UInt32(0x00, "Base Address Register 5")
+ BAR0Size = Param.MemorySize32('0B', "Base Address Register 0 Size")
+ BAR1Size = Param.MemorySize32('0B', "Base Address Register 1 Size")
+ BAR2Size = Param.MemorySize32('0B', "Base Address Register 2 Size")
+ BAR3Size = Param.MemorySize32('0B', "Base Address Register 3 Size")
+ BAR4Size = Param.MemorySize32('0B', "Base Address Register 4 Size")
+ BAR5Size = Param.MemorySize32('0B', "Base Address Register 5 Size")
+ BAR0LegacyIO = Param.Bool(False, "Whether BAR0 is hardwired legacy IO")
+ BAR1LegacyIO = Param.Bool(False, "Whether BAR1 is hardwired legacy IO")
+ BAR2LegacyIO = Param.Bool(False, "Whether BAR2 is hardwired legacy IO")
+ BAR3LegacyIO = Param.Bool(False, "Whether BAR3 is hardwired legacy IO")
+ BAR4LegacyIO = Param.Bool(False, "Whether BAR4 is hardwired legacy IO")
+ BAR5LegacyIO = Param.Bool(False, "Whether BAR5 is hardwired legacy IO")
+ LegacyIOBase = Param.Addr(0x0, "Base Address for Legacy IO")
+
+ CardbusCIS = Param.UInt32(0x00, "Cardbus Card Information Structure")
+ 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/pci/SConscript b/src/dev/pci/SConscript
index b892a2905..14214424b 100644
--- a/src/dev/pci/SConscript
+++ b/src/dev/pci/SConscript
@@ -12,6 +12,9 @@
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
+# Copyright (c) 2006 The Regents of The University of Michigan
+# All rights reserved.
+#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
@@ -35,14 +38,20 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
-# Authors: Andreas Sandberg
+# Authors: Steve Reinhardt
+# Gabe Black
+# Andreas Sandberg
Import('*')
if env['TARGET_ISA'] == 'null':
Return()
+SimObject('PciDevice.py')
+Source('device.cc')
+DebugFlag('PciDevice')
+
SimObject('PciHost.py')
Source('host.cc')
-
DebugFlag('PciHost')
+
diff --git a/src/dev/pci/device.cc b/src/dev/pci/device.cc
new file mode 100644
index 000000000..916cd8422
--- /dev/null
+++ b/src/dev/pci/device.cc
@@ -0,0 +1,581 @@
+/*
+ * Copyright (c) 2013, 2015 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ * Andrew Schultz
+ * Miguel Serrano
+ */
+
+/* @file
+ * A single PCI device configuration space entry.
+ */
+
+#include "dev/pci/device.hh"
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/inifile.hh"
+#include "base/intmath.hh"
+#include "base/misc.hh"
+#include "base/str.hh"
+#include "base/trace.hh"
+#include "debug/PciDevice.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "sim/byteswap.hh"
+#include "sim/core.hh"
+
+
+PciDevice::PciDevice(const PciDeviceParams *p)
+ : DmaDevice(p),
+ _busAddr(p->pci_bus, p->pci_dev, p->pci_func),
+ 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),
+
+ hostInterface(p->host->registerDevice(this, _busAddr,
+ (PciIntPin)p->InterruptPin)),
+ pioDelay(p->pio_latency),
+ configDelay(p->config_latency)
+{
+ fatal_if(p->InterruptPin >= 5,
+ "Invalid PCI interrupt '%i' specified.", p->InterruptPin);
+
+ config.vendor = htole(p->VendorID);
+ config.device = htole(p->DeviceID);
+ config.command = htole(p->Command);
+ config.status = htole(p->Status);
+ config.revision = htole(p->Revision);
+ config.progIF = htole(p->ProgIF);
+ config.subClassCode = htole(p->SubClassCode);
+ config.classCode = htole(p->ClassCode);
+ config.cacheLineSize = htole(p->CacheLineSize);
+ config.latencyTimer = htole(p->LatencyTimer);
+ config.headerType = htole(p->HeaderType);
+ config.bist = htole(p->BIST);
+
+ config.baseAddr[0] = htole(p->BAR0);
+ config.baseAddr[1] = htole(p->BAR1);
+ config.baseAddr[2] = htole(p->BAR2);
+ config.baseAddr[3] = htole(p->BAR3);
+ config.baseAddr[4] = htole(p->BAR4);
+ config.baseAddr[5] = htole(p->BAR5);
+ config.cardbusCIS = htole(p->CardbusCIS);
+ config.subsystemVendorID = htole(p->SubsystemVendorID);
+ config.subsystemID = htole(p->SubsystemID);
+ config.expansionROM = htole(p->ExpansionROM);
+ 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 = (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 = (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;
+ msicap.md = p->MSICAPMsgData;
+ msicap.mmask = p->MSICAPMaskBits;
+ msicap.mpend = p->MSICAPPendingBits;
+
+ // MSIXCAP
+ 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;
+
+ // 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
+ uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff;
+ 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);
+ }
+ 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 = (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;
+ 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;
+ BARSize[3] = p->BAR3Size;
+ BARSize[4] = p->BAR4Size;
+ BARSize[5] = p->BAR5Size;
+
+ legacyIO[0] = p->BAR0LegacyIO;
+ legacyIO[1] = p->BAR1LegacyIO;
+ legacyIO[2] = p->BAR2LegacyIO;
+ legacyIO[3] = p->BAR3LegacyIO;
+ legacyIO[4] = p->BAR4LegacyIO;
+ legacyIO[5] = p->BAR5LegacyIO;
+
+ for (int i = 0; i < 6; ++i) {
+ if (legacyIO[i]) {
+ BARAddrs[i] = p->LegacyIOBase + letoh(config.baseAddr[i]);
+ config.baseAddr[i] = 0;
+ } else {
+ BARAddrs[i] = 0;
+ uint32_t barsize = BARSize[i];
+ if (barsize != 0 && !isPowerOf2(barsize)) {
+ fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]);
+ }
+ }
+ }
+}
+
+Tick
+PciDevice::readConfig(PacketPtr pkt)
+{
+ int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
+
+ /* 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");
+ }
+
+ switch (pkt->getSize()) {
+ case sizeof(uint8_t):
+ pkt->set<uint8_t>(config.data[offset]);
+ DPRINTF(PciDevice,
+ "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
+ _busAddr.dev, _busAddr.func, offset,
+ (uint32_t)pkt->get<uint8_t>());
+ break;
+ case sizeof(uint16_t):
+ pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]);
+ DPRINTF(PciDevice,
+ "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
+ _busAddr.dev, _busAddr.func, offset,
+ (uint32_t)pkt->get<uint16_t>());
+ break;
+ case sizeof(uint32_t):
+ pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]);
+ DPRINTF(PciDevice,
+ "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
+ _busAddr.dev, _busAddr.func, offset,
+ (uint32_t)pkt->get<uint32_t>());
+ break;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ pkt->makeAtomicResponse();
+ return configDelay;
+
+}
+
+AddrRangeList
+PciDevice::getAddrRanges() const
+{
+ AddrRangeList ranges;
+ int x = 0;
+ for (x = 0; x < 6; x++)
+ if (BARAddrs[x] != 0)
+ ranges.push_back(RangeSize(BARAddrs[x],BARSize[x]));
+ return ranges;
+}
+
+Tick
+PciDevice::writeConfig(PacketPtr pkt)
+{
+ int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
+
+ /* 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):
+ switch (offset) {
+ case PCI0_INTERRUPT_LINE:
+ config.interruptLine = pkt->get<uint8_t>();
+ break;
+ case PCI_CACHE_LINE_SIZE:
+ config.cacheLineSize = pkt->get<uint8_t>();
+ break;
+ case PCI_LATENCY_TIMER:
+ config.latencyTimer = pkt->get<uint8_t>();
+ break;
+ /* Do nothing for these read-only registers */
+ case PCI0_INTERRUPT_PIN:
+ case PCI0_MINIMUM_GRANT:
+ case PCI0_MAXIMUM_LATENCY:
+ case PCI_CLASS_CODE:
+ case PCI_REVISION_ID:
+ break;
+ default:
+ panic("writing to a read only register");
+ }
+ DPRINTF(PciDevice,
+ "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
+ _busAddr.dev, _busAddr.func, offset,
+ (uint32_t)pkt->get<uint8_t>());
+ break;
+ case sizeof(uint16_t):
+ switch (offset) {
+ case PCI_COMMAND:
+ config.command = pkt->get<uint8_t>();
+ break;
+ case PCI_STATUS:
+ config.status = pkt->get<uint8_t>();
+ break;
+ case PCI_CACHE_LINE_SIZE:
+ config.cacheLineSize = pkt->get<uint8_t>();
+ break;
+ default:
+ panic("writing to a read only register");
+ }
+ DPRINTF(PciDevice,
+ "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
+ _busAddr.dev, _busAddr.func, offset,
+ (uint32_t)pkt->get<uint16_t>());
+ break;
+ case sizeof(uint32_t):
+ switch (offset) {
+ case PCI0_BASE_ADDR0:
+ case PCI0_BASE_ADDR1:
+ case PCI0_BASE_ADDR2:
+ case PCI0_BASE_ADDR3:
+ case PCI0_BASE_ADDR4:
+ case PCI0_BASE_ADDR5:
+ {
+ int barnum = BAR_NUMBER(offset);
+
+ if (!legacyIO[barnum]) {
+ // convert BAR values to host endianness
+ uint32_t he_old_bar = letoh(config.baseAddr[barnum]);
+ uint32_t he_new_bar = letoh(pkt->get<uint32_t>());
+
+ uint32_t bar_mask =
+ BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK;
+
+ // Writing 0xffffffff to a BAR tells the card to set the
+ // value of the bar to a bitmask indicating the size of
+ // memory it needs
+ if (he_new_bar == 0xffffffff) {
+ he_new_bar = ~(BARSize[barnum] - 1);
+ } else {
+ // does it mean something special to write 0 to a BAR?
+ he_new_bar &= ~bar_mask;
+ if (he_new_bar) {
+ BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ?
+ hostInterface.pioAddr(he_new_bar) :
+ hostInterface.memAddr(he_new_bar);
+ pioPort.sendRangeChange();
+ }
+ }
+ config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) |
+ (he_old_bar & bar_mask));
+ }
+ }
+ break;
+
+ case PCI0_ROM_BASE_ADDR:
+ if (letoh(pkt->get<uint32_t>()) == 0xfffffffe)
+ config.expansionROM = htole((uint32_t)0xffffffff);
+ else
+ config.expansionROM = pkt->get<uint32_t>();
+ break;
+
+ case PCI_COMMAND:
+ // This could also clear some of the error bits in the Status
+ // register. However they should never get set, so lets ignore
+ // it for now
+ config.command = pkt->get<uint32_t>();
+ break;
+
+ default:
+ DPRINTF(PciDevice, "Writing to a read only register");
+ }
+ DPRINTF(PciDevice,
+ "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
+ _busAddr.dev, _busAddr.func, offset,
+ (uint32_t)pkt->get<uint32_t>());
+ break;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ pkt->makeAtomicResponse();
+ return configDelay;
+}
+
+void
+PciDevice::serialize(CheckpointOut &cp) const
+{
+ 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(cp, csprintf("pmcap.pid"), uint16_t(pmcap.pid));
+ paramOut(cp, csprintf("pmcap.pc"), uint16_t(pmcap.pc));
+ paramOut(cp, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs));
+
+ paramOut(cp, csprintf("msicap.mid"), uint16_t(msicap.mid));
+ paramOut(cp, csprintf("msicap.mc"), uint16_t(msicap.mc));
+ paramOut(cp, csprintf("msicap.ma"), uint32_t(msicap.ma));
+ SERIALIZE_SCALAR(msicap.mua);
+ paramOut(cp, csprintf("msicap.md"), uint16_t(msicap.md));
+ SERIALIZE_SCALAR(msicap.mmask);
+ SERIALIZE_SCALAR(msicap.mpend);
+
+ paramOut(cp, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid));
+ paramOut(cp, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc));
+ paramOut(cp, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab));
+ paramOut(cp, csprintf("msixcap.mpba"), uint32_t(msixcap.mpba));
+
+ // Only serialize if we have a non-zero base address
+ if (MSIXCAP_BASE != 0x0) {
+ 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++;
+ }
+
+ SERIALIZE_SCALAR(msix_array_size);
+ SERIALIZE_SCALAR(pba_array_size);
+
+ for (int i = 0; i < msix_array_size; i++) {
+ paramOut(cp, csprintf("msix_table[%d].addr_lo", i),
+ msix_table[i].fields.addr_lo);
+ paramOut(cp, csprintf("msix_table[%d].addr_hi", i),
+ msix_table[i].fields.addr_hi);
+ paramOut(cp, csprintf("msix_table[%d].msg_data", i),
+ msix_table[i].fields.msg_data);
+ paramOut(cp, csprintf("msix_table[%d].vec_ctrl", i),
+ msix_table[i].fields.vec_ctrl);
+ }
+ for (int i = 0; i < pba_array_size; i++) {
+ paramOut(cp, csprintf("msix_pba[%d].bits", i),
+ msix_pba[i].bits);
+ }
+ }
+
+ paramOut(cp, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid));
+ paramOut(cp, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap));
+ paramOut(cp, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap));
+ paramOut(cp, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc));
+ paramOut(cp, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds));
+ paramOut(cp, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap));
+ paramOut(cp, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc));
+ paramOut(cp, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls));
+ paramOut(cp, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2));
+ paramOut(cp, csprintf("pxcap.pxdc2"), uint32_t(pxcap.pxdc2));
+}
+
+void
+PciDevice::unserialize(CheckpointIn &cp)
+{
+ UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0]));
+ UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
+ UNSERIALIZE_ARRAY(config.data,
+ sizeof(config.data) / sizeof(config.data[0]));
+
+ // unserialize the capability list registers
+ uint16_t tmp16;
+ uint32_t tmp32;
+ paramIn(cp, csprintf("pmcap.pid"), tmp16);
+ pmcap.pid = tmp16;
+ paramIn(cp, csprintf("pmcap.pc"), tmp16);
+ pmcap.pc = tmp16;
+ paramIn(cp, csprintf("pmcap.pmcs"), tmp16);
+ pmcap.pmcs = tmp16;
+
+ paramIn(cp, csprintf("msicap.mid"), tmp16);
+ msicap.mid = tmp16;
+ paramIn(cp, csprintf("msicap.mc"), tmp16);
+ msicap.mc = tmp16;
+ paramIn(cp, csprintf("msicap.ma"), tmp32);
+ msicap.ma = tmp32;
+ UNSERIALIZE_SCALAR(msicap.mua);
+ paramIn(cp, csprintf("msicap.md"), tmp16);;
+ msicap.md = tmp16;
+ UNSERIALIZE_SCALAR(msicap.mmask);
+ UNSERIALIZE_SCALAR(msicap.mpend);
+
+ paramIn(cp, csprintf("msixcap.mxid"), tmp16);
+ msixcap.mxid = tmp16;
+ paramIn(cp, csprintf("msixcap.mxc"), tmp16);
+ msixcap.mxc = tmp16;
+ paramIn(cp, csprintf("msixcap.mtab"), tmp32);
+ msixcap.mtab = tmp32;
+ paramIn(cp, 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, csprintf("msix_table[%d].addr_lo", i),
+ msix_table[i].fields.addr_lo);
+ paramIn(cp, csprintf("msix_table[%d].addr_hi", i),
+ msix_table[i].fields.addr_hi);
+ paramIn(cp, csprintf("msix_table[%d].msg_data", i),
+ msix_table[i].fields.msg_data);
+ paramIn(cp, csprintf("msix_table[%d].vec_ctrl", i),
+ msix_table[i].fields.vec_ctrl);
+ }
+ for (int i = 0; i < pba_array_size; i++) {
+ paramIn(cp, csprintf("msix_pba[%d].bits", i),
+ msix_pba[i].bits);
+ }
+ }
+
+ paramIn(cp, csprintf("pxcap.pxid"), tmp16);
+ pxcap.pxid = tmp16;
+ paramIn(cp, csprintf("pxcap.pxcap"), tmp16);
+ pxcap.pxcap = tmp16;
+ paramIn(cp, csprintf("pxcap.pxdcap"), tmp32);
+ pxcap.pxdcap = tmp32;
+ paramIn(cp, csprintf("pxcap.pxdc"), tmp16);
+ pxcap.pxdc = tmp16;
+ paramIn(cp, csprintf("pxcap.pxds"), tmp16);
+ pxcap.pxds = tmp16;
+ paramIn(cp, csprintf("pxcap.pxlcap"), tmp32);
+ pxcap.pxlcap = tmp32;
+ paramIn(cp, csprintf("pxcap.pxlc"), tmp16);
+ pxcap.pxlc = tmp16;
+ paramIn(cp, csprintf("pxcap.pxls"), tmp16);
+ pxcap.pxls = tmp16;
+ paramIn(cp, csprintf("pxcap.pxdcap2"), tmp32);
+ pxcap.pxdcap2 = tmp32;
+ paramIn(cp, csprintf("pxcap.pxdc2"), tmp32);
+ pxcap.pxdc2 = tmp32;
+ pioPort.sendRangeChange();
+}
+
diff --git a/src/dev/pci/device.hh b/src/dev/pci/device.hh
new file mode 100644
index 000000000..ba783a6b1
--- /dev/null
+++ b/src/dev/pci/device.hh
@@ -0,0 +1,227 @@
+/*
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ * Andrew Schultz
+ * Nathan Binkert
+ */
+
+/* @file
+ * Interface for devices using PCI configuration
+ */
+
+#ifndef __DEV_PCI_DEVICE_HH__
+#define __DEV_PCI_DEVICE_HH__
+
+#include <cstring>
+#include <vector>
+
+#include "dev/dma_device.hh"
+#include "dev/pci/host.hh"
+#include "dev/pci/pcireg.h"
+#include "params/PciDevice.hh"
+#include "sim/byteswap.hh"
+
+#define BAR_IO_MASK 0x3
+#define BAR_MEM_MASK 0xF
+#define BAR_IO_SPACE_BIT 0x1
+#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT)
+#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2);
+
+/**
+ * PCI device, base implementation is only config space.
+ */
+class PciDevice : public DmaDevice
+{
+ protected:
+ const PciBusAddr _busAddr;
+
+ /** The current config space. */
+ PCIConfig config;
+
+ /** The capability list structures and base addresses
+ * @{
+ */
+ const int PMCAP_BASE;
+ const int PMCAP_ID_OFFSET;
+ const int PMCAP_PC_OFFSET;
+ const int PMCAP_PMCS_OFFSET;
+ PMCAP pmcap;
+
+ const int MSICAP_BASE;
+ MSICAP msicap;
+
+ const int MSIXCAP_BASE;
+ const int MSIXCAP_ID_OFFSET;
+ const int MSIXCAP_MXC_OFFSET;
+ const int MSIXCAP_MTAB_OFFSET;
+ const int MSIXCAP_MPBA_OFFSET;
+ int MSIX_TABLE_OFFSET;
+ int MSIX_TABLE_END;
+ int MSIX_PBA_OFFSET;
+ int MSIX_PBA_END;
+ 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];
+
+ /** The current address mapping of the BARs */
+ Addr BARAddrs[6];
+
+ /** Whether the BARs are really hardwired legacy IO locations. */
+ bool legacyIO[6];
+
+ /**
+ * Does the given address lie within the space mapped by the given
+ * base address register?
+ */
+ bool
+ isBAR(Addr addr, int bar) const
+ {
+ assert(bar >= 0 && bar < 6);
+ return BARAddrs[bar] <= addr && addr < BARAddrs[bar] + BARSize[bar];
+ }
+
+ /**
+ * Which base address register (if any) maps the given address?
+ * @return The BAR number (0-5 inclusive), or -1 if none.
+ */
+ int
+ getBAR(Addr addr)
+ {
+ for (int i = 0; i <= 5; ++i)
+ if (isBAR(addr, i))
+ return i;
+
+ return -1;
+ }
+
+ /**
+ * Which base address register (if any) maps the given address?
+ * @param addr The address to check.
+ * @retval bar The BAR number (0-5 inclusive),
+ * only valid if return value is true.
+ * @retval offs The offset from the base address,
+ * only valid if return value is true.
+ * @return True iff address maps to a base address register's region.
+ */
+ bool
+ getBAR(Addr addr, int &bar, Addr &offs)
+ {
+ int b = getBAR(addr);
+ if (b < 0)
+ return false;
+
+ offs = addr - BARAddrs[b];
+ bar = b;
+ return true;
+ }
+
+ public: // Host configuration interface
+ /**
+ * Write to the PCI config space data that is stored locally. This may be
+ * overridden by the device but at some point it will eventually call this
+ * for normal operations that it does not need to override.
+ * @param pkt packet containing the write the offset into config space
+ */
+ virtual Tick writeConfig(PacketPtr pkt);
+
+
+ /**
+ * Read from the PCI config space data that is stored locally. This may be
+ * overridden by the device but at some point it will eventually call this
+ * for normal operations that it does not need to override.
+ * @param pkt packet containing the write the offset into config space
+ */
+ virtual Tick readConfig(PacketPtr pkt);
+
+ protected:
+ PciHost::DeviceInterface hostInterface;
+
+ Tick pioDelay;
+ Tick configDelay;
+
+ public:
+ Addr pciToDma(Addr pci_addr) const {
+ return hostInterface.dmaAddr(pci_addr);
+ }
+
+ void intrPost() { hostInterface.postInt(); }
+ void intrClear() { hostInterface.clearInt(); }
+
+ uint8_t interruptLine() const { return letoh(config.interruptLine); }
+
+ /**
+ * Determine the address ranges that this device responds to.
+ *
+ * @return a list of non-overlapping address ranges
+ */
+ AddrRangeList getAddrRanges() const override;
+
+ /**
+ * Constructor for PCI Dev. This function copies data from the
+ * config file object PCIConfigData and registers the device with
+ * a PciHost object.
+ */
+ PciDevice(const PciDeviceParams *params);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ void serialize(CheckpointOut &cp) const override;
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ void unserialize(CheckpointIn &cp) override;
+
+ const PciBusAddr &busAddr() const { return _busAddr; }
+};
+#endif // __DEV_PCI_DEVICE_HH__
diff --git a/src/dev/pci/host.cc b/src/dev/pci/host.cc
index bcf49df86..3b572f7f4 100644
--- a/src/dev/pci/host.cc
+++ b/src/dev/pci/host.cc
@@ -42,7 +42,7 @@
#include <utility>
#include "debug/PciHost.hh"
-#include "dev/pcidev.hh"
+#include "dev/pci/device.hh"
#include "dev/platform.hh"
#include "params/GenericPciHost.hh"
#include "params/PciHost.hh"
diff --git a/src/dev/pci/pcireg.h b/src/dev/pci/pcireg.h
new file mode 100644
index 000000000..895ea0f68
--- /dev/null
+++ b/src/dev/pci/pcireg.h
@@ -0,0 +1,409 @@
+/*
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Miguel Serrano
+ */
+
+/* @file
+ * Device register definitions for a device's PCI config space
+ */
+
+#ifndef __PCIREG_H__
+#define __PCIREG_H__
+
+#include <sys/types.h>
+
+#include "base/bitfield.hh"
+#include "base/bitunion.hh"
+
+union PCIConfig {
+ uint8_t data[64];
+
+ struct {
+ uint16_t vendor;
+ uint16_t device;
+ uint16_t command;
+ uint16_t status;
+ uint8_t revision;
+ uint8_t progIF;
+ uint8_t subClassCode;
+ uint8_t classCode;
+ uint8_t cacheLineSize;
+ uint8_t latencyTimer;
+ uint8_t headerType;
+ uint8_t bist;
+ uint32_t baseAddr[6];
+ uint32_t cardbusCIS;
+ uint16_t subsystemVendorID;
+ uint16_t subsystemID;
+ uint32_t expansionROM;
+ 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;
+ uint8_t maximumLatency;
+ };
+};
+
+// Common PCI offsets
+#define PCI_VENDOR_ID 0x00 // Vendor ID ro
+#define PCI_DEVICE_ID 0x02 // Device ID ro
+#define PCI_COMMAND 0x04 // Command rw
+#define PCI_STATUS 0x06 // Status rw
+#define PCI_REVISION_ID 0x08 // Revision ID ro
+#define PCI_CLASS_CODE 0x09 // Class Code ro
+#define PCI_SUB_CLASS_CODE 0x0A // Sub Class Code ro
+#define PCI_BASE_CLASS_CODE 0x0B // Base Class Code ro
+#define PCI_CACHE_LINE_SIZE 0x0C // Cache Line Size ro+
+#define PCI_LATENCY_TIMER 0x0D // Latency Timer ro+
+#define PCI_HEADER_TYPE 0x0E // Header Type ro
+#define PCI_BIST 0x0F // Built in self test rw
+
+// some pci command reg bitfields
+#define PCI_CMD_BME 0x04 // Bus master function enable
+#define PCI_CMD_MSE 0x02 // Memory Space Access enable
+#define PCI_CMD_IOSE 0x01 // I/O space enable
+
+// Type 0 PCI offsets
+#define PCI0_BASE_ADDR0 0x10 // Base Address 0 rw
+#define PCI0_BASE_ADDR1 0x14 // Base Address 1 rw
+#define PCI0_BASE_ADDR2 0x18 // Base Address 2 rw
+#define PCI0_BASE_ADDR3 0x1C // Base Address 3 rw
+#define PCI0_BASE_ADDR4 0x20 // Base Address 4 rw
+#define PCI0_BASE_ADDR5 0x24 // Base Address 5 rw
+#define PCI0_CIS 0x28 // CardBus CIS Pointer ro
+#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_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
+#define PCI0_MAXIMUM_LATENCY 0x3F // Maximum Latency ro
+
+// Type 1 PCI offsets
+#define PCI1_BASE_ADDR0 0x10 // Base Address 0 rw
+#define PCI1_BASE_ADDR1 0x14 // Base Address 1 rw
+#define PCI1_PRI_BUS_NUM 0x18 // Primary Bus Number rw
+#define PCI1_SEC_BUS_NUM 0x19 // Secondary Bus Number rw
+#define PCI1_SUB_BUS_NUM 0x1A // Subordinate Bus Number rw
+#define PCI1_SEC_LAT_TIMER 0x1B // Secondary Latency Timer ro+
+#define PCI1_IO_BASE 0x1C // I/O Base rw
+#define PCI1_IO_LIMIT 0x1D // I/O Limit rw
+#define PCI1_SECONDARY_STATUS 0x1E // Secondary Status rw
+#define PCI1_MEM_BASE 0x20 // Memory Base rw
+#define PCI1_MEM_LIMIT 0x22 // Memory Limit rw
+#define PCI1_PRF_MEM_BASE 0x24 // Prefetchable Memory Base rw
+#define PCI1_PRF_MEM_LIMIT 0x26 // Prefetchable Memory Limit rw
+#define PCI1_PRF_BASE_UPPER 0x28 // Prefetchable Base Upper 32 rw
+#define PCI1_PRF_LIMIT_UPPER 0x2C // Prefetchable Limit Upper 32 rw
+#define PCI1_IO_BASE_UPPER 0x30 // I/O Base Upper 16 bits rw
+#define PCI1_IO_LIMIT_UPPER 0x32 // I/O Limit Upper 16 bits rw
+#define PCI1_RESERVED 0x34 // Reserved ro
+#define PCI1_ROM_BASE_ADDR 0x38 // Expansion ROM Base Address rw
+#define PCI1_INTR_LINE 0x3C // Interrupt Line rw
+#define PCI1_INTR_PIN 0x3D // Interrupt Pin ro
+#define PCI1_BRIDGE_CTRL 0x3E // Bridge Control rw
+
+// Device specific offsets
+#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes
+#define PCI_CONFIG_SIZE 0xFF
+
+// Some Vendor IDs
+#define PCI_VENDOR_DEC 0x1011
+#define PCI_VENDOR_NCR 0x101A
+#define PCI_VENDOR_QLOGIC 0x1077
+#define PCI_VENDOR_SIMOS 0x1291
+
+// Some Product IDs
+#define PCI_PRODUCT_DEC_PZA 0x0008
+#define PCI_PRODUCT_NCR_810 0x0001
+#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020
+#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.
+ */
+union PMCAP {
+ uint8_t data[6];
+ struct {
+ uint16_t pid; /* 0:7 cid
+ * 8:15 next
+ */
+ uint16_t pc; /* 0:2 vs
+ * 3 pmec
+ * 4 reserved
+ * 5 dsi
+ * 6:8 auxc
+ * 9 d1s
+ * 10 d2s
+ * 11:15 psup
+ */
+ uint16_t pmcs; /* 0:1 ps
+ * 2 reserved
+ * 3 nsfrst
+ * 4:7 reserved
+ * 8 pmee
+ * 9:12 dse
+ * 13:14 dsc
+ * 15 pmes
+ */
+ };
+};
+
+/** @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.
+ */
+union MSICAP {
+ uint8_t data[24];
+ struct {
+ uint16_t mid; /* 0:7 cid
+ * 8:15 next
+ */
+ uint16_t mc; /* 0 msie;
+ * 1:3 mmc;
+ * 4:6 mme;
+ * 7 c64;
+ * 8 pvm;
+ * 9:15 reserved;
+ */
+ uint32_t ma; /* 0:1 reserved
+ * 2:31 addr
+ */
+ uint32_t mua;
+ uint16_t md;
+ uint32_t mmask;
+ uint32_t mpend;
+ };
+};
+
+/** @struct MSIX
+ * Defines the MSI-X Capability register and its associated bitfields for
+ * a PCIe device.
+ */
+union MSIXCAP {
+ uint8_t data[12];
+ struct {
+ uint16_t mxid; /* 0:7 cid
+ * 8:15 next
+ */
+ uint16_t mxc; /* 0:10 ts;
+ * 11:13 reserved;
+ * 14 fm;
+ * 15 mxe;
+ */
+ uint32_t mtab; /* 0:2 tbir;
+ * 3:31 to;
+ */
+ uint32_t mpba; /* 0:2 pbir;
+ * 3:31> pbao;
+ */
+ };
+};
+
+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 {
+ uint8_t data[48];
+ struct {
+ uint16_t pxid; /* 0:7 cid
+ * 8:15 next
+ */
+ uint16_t pxcap; /* 0:3 ver;
+ * 4:7 dpt;
+ * 8 si;
+ * 9:13 imn;
+ * 14:15 reserved;
+ */
+ uint32_t pxdcap; /* 0:2 mps;
+ * 3:4 pfs;
+ * 5 etfs;
+ * 6:8 l0sl;
+ * 9:11 l1l;
+ * 12:14 reserved;
+ * 15 rer;
+ * 16:17 reserved;
+ * 18:25 csplv;
+ * 26:27 cspls;
+ * 28 flrc;
+ * 29:31 reserved;
+ */
+ uint16_t pxdc; /* 0 cere;
+ * 1 nfere;
+ * 2 fere;
+ * 3 urre;
+ * 4 ero;
+ * 5:7 mps;
+ * 8 ete;
+ * 9 pfe;
+ * 10 appme;
+ * 11 ens;
+ * 12:14 mrrs;
+ * 15 func_reset;
+ */
+ uint16_t pxds; /* 0 ced;
+ * 1 nfed;
+ * 2 fed;
+ * 3 urd;
+ * 4 apd;
+ * 5 tp;
+ * 6:15 reserved;
+ */
+ uint32_t pxlcap; /* 0:3 sls;
+ * 4:9 mlw;
+ * 10:11 aspms;
+ * 12:14 l0sel;
+ * 15:17 l1el;
+ * 18 cpm;
+ * 19 sderc;
+ * 20 dllla;
+ * 21 lbnc;
+ * 22:23 reserved;
+ * 24:31 pn;
+ */
+ uint16_t pxlc; /* 0:1 aspmc;
+ * 2 reserved;
+ * 3 rcb;
+ * 4:5 reserved;
+ * 6 ccc;
+ * 7 es;
+ * 8 ecpm;
+ * 9 hawd;
+ * 10:15 reserved;
+ */
+ uint16_t pxls; /* 0:3 cls;
+ * 4:9 nlw;
+ * 10:11 reserved;
+ * 12 slot_clk_config;
+ * 13:15 reserved;
+ */
+ uint8_t reserved[20];
+ uint32_t pxdcap2; /* 0:3 ctrs;
+ * 4 ctds;
+ * 5 arifs;
+ * 6 aors;
+ * 7 aocs32;
+ * 8 aocs64;
+ * 9 ccs128;
+ * 10 nprpr;
+ * 11 ltrs;
+ * 12:13 tphcs;
+ * 14:17 reserved;
+ * 18:19 obffs;
+ * 20 effs;
+ * 21 eetps;
+ * 22:23 meetp;
+ * 24:31 reserved;
+ */
+ uint32_t pxdc2; /* 0:3 ctv;
+ * 4 ctd;
+ * 5:9 reserved;
+ * 10 ltrme;
+ * 11:12 reserved;
+ * 13:14 obffe;
+ * 15:31 reserved;
+ */
+ };
+};
+#endif // __PCIREG_H__