diff options
Diffstat (limited to 'src/dev/pci')
-rw-r--r-- | src/dev/pci/PciDevice.py | 154 | ||||
-rw-r--r-- | src/dev/pci/SConscript | 13 | ||||
-rw-r--r-- | src/dev/pci/device.cc | 581 | ||||
-rw-r--r-- | src/dev/pci/device.hh | 227 | ||||
-rw-r--r-- | src/dev/pci/host.cc | 2 | ||||
-rw-r--r-- | src/dev/pci/pcireg.h | 409 |
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__ |