From: Andreas Sandberg Date: Thu, 10 Dec 2015 10:35:15 +0000 (+0000) Subject: dev: Move existing PCI device functionality to src/dev/pci X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=139c97c9772be38577eaa52af5d1ef3607da4bcb;p=gem5.git dev: Move existing PCI device functionality to src/dev/pci Move pcidev.(hh|cc) to src/dev/pci/device.(hh|cc) and update existing devices to use the new header location. This also renames the PCIDEV debug flag to have a capitalization that is consistent with the PCI host and other devices. --HG-- rename : src/dev/Pci.py => src/dev/pci/PciDevice.py rename : src/dev/pcidev.cc => src/dev/pci/device.cc rename : src/dev/pcidev.hh => src/dev/pci/device.hh rename : src/dev/pcireg.h => src/dev/pci/pcireg.h --- diff --git a/src/dev/CopyEngine.py b/src/dev/CopyEngine.py index d56294d66..2db9746d1 100644 --- a/src/dev/CopyEngine.py +++ b/src/dev/CopyEngine.py @@ -29,7 +29,7 @@ from m5.SimObject import SimObject from m5.params import * from m5.proxy import * -from Pci import PciDevice +from PciDevice import PciDevice class CopyEngine(PciDevice): type = 'CopyEngine' diff --git a/src/dev/Ethernet.py b/src/dev/Ethernet.py index 84fa0ae00..89d1bad89 100644 --- a/src/dev/Ethernet.py +++ b/src/dev/Ethernet.py @@ -41,7 +41,7 @@ from m5.SimObject import SimObject from m5.params import * from m5.proxy import * -from Pci import PciDevice +from PciDevice import PciDevice class EtherObject(SimObject): type = 'EtherObject' diff --git a/src/dev/Ide.py b/src/dev/Ide.py index c5eef9f54..4d3da1971 100644 --- a/src/dev/Ide.py +++ b/src/dev/Ide.py @@ -28,7 +28,7 @@ from m5.SimObject import SimObject from m5.params import * -from Pci import PciDevice +from PciDevice import PciDevice class IdeID(Enum): vals = ['master', 'slave'] diff --git a/src/dev/Pci.py b/src/dev/Pci.py deleted file mode 100644 index 4fbe56fd0..000000000 --- a/src/dev/Pci.py +++ /dev/null @@ -1,154 +0,0 @@ -# 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/pcidev.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/SConscript b/src/dev/SConscript index f2a172287..923417078 100644 --- a/src/dev/SConscript +++ b/src/dev/SConscript @@ -45,7 +45,6 @@ SimObject('DiskImage.py') SimObject('Ethernet.py') SimObject('I2C.py') SimObject('Ide.py') -SimObject('Pci.py') SimObject('Platform.py') SimObject('SimpleDisk.py') SimObject('Terminal.py') @@ -73,7 +72,6 @@ Source('ide_disk.cc') Source('intel_8254_timer.cc') Source('mc146818.cc') Source('ns_gige.cc') -Source('pcidev.cc') Source('pixelpump.cc') Source('pktfifo.cc') Source('platform.cc') @@ -103,7 +101,6 @@ DebugFlag('IdeCtrl') DebugFlag('IdeDisk') DebugFlag('Intel8254Timer') DebugFlag('MC146818') -DebugFlag('PCIDEV') DebugFlag('SimpleDisk') DebugFlag('SimpleDiskData') DebugFlag('Terminal') diff --git a/src/dev/alpha/tsunami_pchip.cc b/src/dev/alpha/tsunami_pchip.cc index fa3d9d395..3edb1e71b 100644 --- a/src/dev/alpha/tsunami_pchip.cc +++ b/src/dev/alpha/tsunami_pchip.cc @@ -44,7 +44,7 @@ #include "dev/alpha/tsunami.hh" #include "dev/alpha/tsunami_cchip.hh" #include "dev/alpha/tsunamireg.h" -#include "dev/pcidev.hh" +#include "dev/pci/device.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" #include "sim/system.hh" diff --git a/src/dev/copy_engine.hh b/src/dev/copy_engine.hh index 797311be5..754ea5e15 100644 --- a/src/dev/copy_engine.hh +++ b/src/dev/copy_engine.hh @@ -53,7 +53,7 @@ #include "base/cp_annotate.hh" #include "base/statistics.hh" #include "dev/copy_engine_defs.hh" -#include "dev/pcidev.hh" +#include "dev/pci/device.hh" #include "params/CopyEngine.hh" #include "sim/drain.hh" #include "sim/eventq.hh" diff --git a/src/dev/etherdevice.hh b/src/dev/etherdevice.hh index ace600a4e..45df2a2df 100644 --- a/src/dev/etherdevice.hh +++ b/src/dev/etherdevice.hh @@ -37,7 +37,7 @@ #define __DEV_ETHERDEVICE_HH__ #include "base/statistics.hh" -#include "dev/pcidev.hh" +#include "dev/pci/device.hh" #include "params/EtherDevice.hh" #include "params/EtherDevBase.hh" #include "sim/sim_object.hh" diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh index f46bf51d3..700f49fbf 100644 --- a/src/dev/i8254xGBe.hh +++ b/src/dev/i8254xGBe.hh @@ -46,7 +46,7 @@ #include "dev/etherint.hh" #include "dev/etherpkt.hh" #include "dev/i8254xGBe_defs.hh" -#include "dev/pcidev.hh" +#include "dev/pci/device.hh" #include "dev/pktfifo.hh" #include "params/IGbE.hh" #include "sim/eventq.hh" diff --git a/src/dev/ide_ctrl.hh b/src/dev/ide_ctrl.hh index 0afa60e4a..c6c4beecc 100644 --- a/src/dev/ide_ctrl.hh +++ b/src/dev/ide_ctrl.hh @@ -39,8 +39,7 @@ #include "base/bitunion.hh" #include "dev/io_device.hh" -#include "dev/pcidev.hh" -#include "dev/pcireg.h" +#include "dev/pci/device.hh" #include "params/IdeController.hh" class IdeDisk; 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 +#include +#include + +#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(0); + break; + case sizeof(uint16_t): + pkt->set(0); + break; + case sizeof(uint32_t): + pkt->set(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(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()); + break; + case sizeof(uint16_t): + pkt->set(*(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()); + break; + case sizeof(uint32_t): + pkt->set(*(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()); + 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(); + break; + case PCI_CACHE_LINE_SIZE: + config.cacheLineSize = pkt->get(); + break; + case PCI_LATENCY_TIMER: + config.latencyTimer = pkt->get(); + 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()); + break; + case sizeof(uint16_t): + switch (offset) { + case PCI_COMMAND: + config.command = pkt->get(); + break; + case PCI_STATUS: + config.status = pkt->get(); + break; + case PCI_CACHE_LINE_SIZE: + config.cacheLineSize = pkt->get(); + 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()); + 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 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()) == 0xfffffffe) + config.expansionROM = htole((uint32_t)0xffffffff); + else + config.expansionROM = pkt->get(); + 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(); + 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()); + 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 +#include + +#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 msix_table; + std::vector 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 #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 + +#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__ diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc deleted file mode 100644 index 5e7c09415..000000000 --- a/src/dev/pcidev.cc +++ /dev/null @@ -1,580 +0,0 @@ -/* - * 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 -#include -#include - -#include "base/inifile.hh" -#include "base/intmath.hh" -#include "base/misc.hh" -#include "base/str.hh" -#include "base/trace.hh" -#include "debug/PCIDEV.hh" -#include "dev/pcidev.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(0); - break; - case sizeof(uint16_t): - pkt->set(0); - break; - case sizeof(uint32_t): - pkt->set(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(config.data[offset]); - DPRINTF(PCIDEV, - "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", - _busAddr.dev, _busAddr.func, offset, - (uint32_t)pkt->get()); - break; - case sizeof(uint16_t): - pkt->set(*(uint16_t*)&config.data[offset]); - DPRINTF(PCIDEV, - "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", - _busAddr.dev, _busAddr.func, offset, - (uint32_t)pkt->get()); - break; - case sizeof(uint32_t): - pkt->set(*(uint32_t*)&config.data[offset]); - DPRINTF(PCIDEV, - "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", - _busAddr.dev, _busAddr.func, offset, - (uint32_t)pkt->get()); - 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(); - break; - case PCI_CACHE_LINE_SIZE: - config.cacheLineSize = pkt->get(); - break; - case PCI_LATENCY_TIMER: - config.latencyTimer = pkt->get(); - 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(PCIDEV, - "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", - _busAddr.dev, _busAddr.func, offset, - (uint32_t)pkt->get()); - break; - case sizeof(uint16_t): - switch (offset) { - case PCI_COMMAND: - config.command = pkt->get(); - break; - case PCI_STATUS: - config.status = pkt->get(); - break; - case PCI_CACHE_LINE_SIZE: - config.cacheLineSize = pkt->get(); - break; - default: - panic("writing to a read only register"); - } - DPRINTF(PCIDEV, - "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", - _busAddr.dev, _busAddr.func, offset, - (uint32_t)pkt->get()); - 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 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()) == 0xfffffffe) - config.expansionROM = htole((uint32_t)0xffffffff); - else - config.expansionROM = pkt->get(); - 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(); - break; - - default: - DPRINTF(PCIDEV, "Writing to a read only register"); - } - DPRINTF(PCIDEV, - "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", - _busAddr.dev, _busAddr.func, offset, - (uint32_t)pkt->get()); - 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/pcidev.hh b/src/dev/pcidev.hh deleted file mode 100644 index a7a2137b0..000000000 --- a/src/dev/pcidev.hh +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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_PCIDEV_HH__ -#define __DEV_PCIDEV_HH__ - -#include -#include - -#include "dev/dma_device.hh" -#include "dev/pcireg.h" -#include "dev/pci/host.hh" -#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 msix_table; - std::vector 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_PCIDEV_HH__ diff --git a/src/dev/pcireg.h b/src/dev/pcireg.h deleted file mode 100644 index 895ea0f68..000000000 --- a/src/dev/pcireg.h +++ /dev/null @@ -1,409 +0,0 @@ -/* - * 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 - -#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__ diff --git a/src/dev/sinic.hh b/src/dev/sinic.hh index 7dfc8b204..dc1947f03 100644 --- a/src/dev/sinic.hh +++ b/src/dev/sinic.hh @@ -37,7 +37,7 @@ #include "dev/etherint.hh" #include "dev/etherpkt.hh" #include "dev/io_device.hh" -#include "dev/pcidev.hh" +#include "dev/pci/device.hh" #include "dev/pktfifo.hh" #include "dev/sinicreg.hh" #include "params/Sinic.hh" diff --git a/src/dev/virtio/VirtIO.py b/src/dev/virtio/VirtIO.py index 13479a383..81bf6e3b8 100644 --- a/src/dev/virtio/VirtIO.py +++ b/src/dev/virtio/VirtIO.py @@ -41,7 +41,7 @@ from m5.SimObject import SimObject from m5.params import * from m5.proxy import * from Device import PioDevice -from Pci import PciDevice +from PciDevice import PciDevice class VirtIODeviceBase(SimObject): diff --git a/src/dev/virtio/pci.hh b/src/dev/virtio/pci.hh index be5a140e2..dcac7c592 100644 --- a/src/dev/virtio/pci.hh +++ b/src/dev/virtio/pci.hh @@ -42,7 +42,7 @@ #include "base/statistics.hh" #include "dev/virtio/base.hh" -#include "dev/pcidev.hh" +#include "dev/pci/device.hh" struct PciVirtIOParams;