self.tsunami.attachIO(self.iobus)
self.tsunami.ide.pio = self.iobus.master
- self.tsunami.ide.config = self.iobus.master
self.tsunami.ethernet.pio = self.iobus.master
- self.tsunami.ethernet.config = self.iobus.master
if ruby:
# Store the dma devices for later connection to dma ruby ports.
self.malta = BaseMalta()
self.malta.attachIO(self.iobus)
self.malta.ide.pio = self.iobus.master
- self.malta.ide.config = self.iobus.master
self.malta.ide.dma = self.iobus.slave
self.malta.ethernet.pio = self.iobus.master
- self.malta.ethernet.config = self.iobus.master
self.malta.ethernet.dma = self.iobus.slave
self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(),
read_only = True))
from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
-from Device import BasicPioDevice, DmaDevice, PioDevice
-
-class PciConfigAll(BasicPioDevice):
- type = 'PciConfigAll'
- cxx_header = "dev/pciconfigall.hh"
- platform = Param.Platform(Parent.any, "Platform this device is part of.")
- bus = Param.UInt8(0x00, "PCI bus to act as config space for")
- size = Param.MemorySize32('16MB', "Size of config space")
-
- pio_latency = '30ns'
- pio_addr = 0 # will be overridden by platform-based calculation
-
+from Device import DmaDevice
+from PciHost import PciHost
class PciDevice(DmaDevice):
type = 'PciDevice'
cxx_class = 'PciDevice'
cxx_header = "dev/pcidev.hh"
abstract = True
- platform = Param.Platform(Parent.any, "Platform this device is part of.")
- config = SlavePort("PCI configuration space port")
+
+ 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")
Source('intel_8254_timer.cc')
Source('mc146818.cc')
Source('ns_gige.cc')
-Source('pciconfigall.cc')
Source('pcidev.cc')
Source('pixelpump.cc')
Source('pktfifo.cc')
DebugFlag('Intel8254Timer')
DebugFlag('MC146818')
DebugFlag('PCIDEV')
-DebugFlag('PciConfigAll')
DebugFlag('SimpleDisk')
DebugFlag('SimpleDiskData')
DebugFlag('Terminal')
from BadDevice import BadDevice
from AlphaBackdoor import AlphaBackdoor
from Device import BasicPioDevice, IsaFake, BadAddr
-from Pci import PciConfigAll
+from PciHost import GenericPciHost
from Platform import Platform
from Uart import Uart8250
tsunami = Param.Tsunami(Parent.any, "Tsunami")
frequency = Param.Frequency('1024Hz', "frequency of interrupts")
-class TsunamiPChip(BasicPioDevice):
+class TsunamiPChip(GenericPciHost):
type = 'TsunamiPChip'
cxx_header = "dev/alpha/tsunami_pchip.hh"
+
+ conf_base = 0x801fe000000
+ conf_size = "16MB"
+
+ pci_pio_base = 0x801fc000000
+ pci_mem_base = 0x80000000000
+
+ pio_addr = Param.Addr("Device Address")
+ pio_latency = Param.Latency('100ns', "Programmed IO latency")
+
tsunami = Param.Tsunami(Parent.any, "Tsunami")
class Tsunami(Platform):
cchip = TsunamiCChip(pio_addr=0x801a0000000)
pchip = TsunamiPChip(pio_addr=0x80180000000)
- pciconfig = PciConfigAll()
fake_sm_chip = IsaFake(pio_addr=0x801fc000370)
fake_uart1 = IsaFake(pio_addr=0x801fc0002f8)
def attachIO(self, bus):
self.cchip.pio = bus.master
self.pchip.pio = bus.master
- self.pciconfig.pio = bus.default
- bus.use_default_range = True
self.fake_sm_chip.pio = bus.master
self.fake_uart1.pio = bus.master
self.fake_uart2.pio = bus.master
cchip->clearDRIR(line);
}
-Addr
-Tsunami::pciToDma(Addr pciAddr) const
-{
- return pchip->translatePciToDma(pciAddr);
-}
-
-
-Addr
-Tsunami::calcPciConfigAddr(int bus, int dev, int func)
-{
- return pchip->calcConfigAddr(bus, dev, func);
-}
-
-Addr
-Tsunami::calcPciIOAddr(Addr addr)
-{
- return pchip->calcIOAddr(addr);
-}
-
-Addr
-Tsunami::calcPciMemAddr(Addr addr)
-{
- return pchip->calcMemAddr(addr);
-}
-
void
Tsunami::serialize(CheckpointOut &cp) const
{
typedef TsunamiParams Params;
Tsunami(const Params *p);
- /**
- * Cause the cpu to post a serial interrupt to the CPU.
- */
- void postConsoleInt() override;
+ void serialize(CheckpointOut &cp) const override;
+ void unserialize(CheckpointIn &cp) override;
- /**
- * Clear a posted CPU interrupt (id=55)
- */
+ public: // Public Platform interfaces
+ void postConsoleInt() override;
void clearConsoleInt() override;
- /**
- * Cause the chipset to post a cpi interrupt to the CPU.
- */
void postPciInt(int line) override;
-
- /**
- * Clear a posted PCI->CPU interrupt
- */
void clearPciInt(int line) override;
-
-
- Addr pciToDma(Addr pciAddr) const override;
-
- /**
- * Calculate the configuration address given a bus/dev/func.
- */
- Addr calcPciConfigAddr(int bus, int dev, int func) override;
-
- /**
- * Calculate the address for an IO location on the PCI bus.
- */
- Addr calcPciIOAddr(Addr addr) override;
-
- /**
- * Calculate the address for a memory location on the PCI bus.
- */
- Addr calcPciMemAddr(Addr addr) override;
-
- void serialize(CheckpointOut &cp) const override;
- void unserialize(CheckpointIn &cp) override;
};
#endif // __DEV_TSUNAMI_HH__
/** @file
* Tsunami PChip (pci)
*/
+#include "dev/alpha/tsunami_pchip.hh"
#include <deque>
#include <string>
#include "config/the_isa.hh"
#include "debug/Tsunami.hh"
#include "dev/alpha/tsunami.hh"
-#include "dev/alpha/tsunami_pchip.hh"
+#include "dev/alpha/tsunami_cchip.hh"
#include "dev/alpha/tsunamireg.h"
+#include "dev/pcidev.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "sim/system.hh"
using namespace TheISA;
TsunamiPChip::TsunamiPChip(const Params *p)
- : BasicPioDevice(p, 0x1000)
+ : GenericPciHost(p),
+ pioRange(RangeSize(p->pio_addr, 0x1000)),
+ pioDelay(p->pio_latency)
{
for (int i = 0; i < 4; i++) {
wsba[i] = 0;
Tick
TsunamiPChip::read(PacketPtr pkt)
{
- assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
+ // We only need to handle our own configuration registers, pass
+ // unknown addresses to the generic code.
+ if (!pioRange.contains(pkt->getAddr()))
+ return GenericPciHost::read(pkt);
- Addr daddr = (pkt->getAddr() - pioAddr) >> 6;;
+ Addr daddr = (pkt->getAddr() - pioRange.start()) >> 6;;
assert(pkt->getSize() == sizeof(uint64_t));
default:
panic("Default in PChip Read reached reading 0x%x\n", daddr);
}
+
pkt->makeAtomicResponse();
return pioDelay;
Tick
TsunamiPChip::write(PacketPtr pkt)
{
- assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
- Addr daddr = (pkt->getAddr() - pioAddr) >> 6;
+ // We only need to handle our own configuration registers, pass
+ // unknown addresses to the generic code.
+ if (!pioRange.contains(pkt->getAddr()))
+ return GenericPciHost::write(pkt);
+
+ Addr daddr = (pkt->getAddr() - pioRange.start()) >> 6;
assert(pkt->getSize() == sizeof(uint64_t));
return pioDelay;
}
+
+AddrRangeList
+TsunamiPChip::getAddrRanges() const
+{
+ return AddrRangeList({
+ RangeSize(confBase, confSize),
+ pioRange
+ });
+}
+
+
#define DMA_ADDR_MASK ULL(0x3ffffffff)
Addr
-TsunamiPChip::translatePciToDma(Addr busAddr)
+TsunamiPChip::dmaAddr(const PciBusAddr &dev, Addr busAddr) const
{
// compare the address to the window base registers
uint64_t tbaMask = 0;
return busAddr;
}
-Addr
-TsunamiPChip::calcConfigAddr(int bus, int dev, int func)
-{
- assert(func < 8);
- assert(dev < 32);
- assert(bus == 0);
-
- return TsunamiPciBus0Config | (func << 8) | (dev << 11);
-}
-
-Addr
-TsunamiPChip::calcIOAddr(Addr addr)
-{
- return TSUNAMI_PCI0_IO + addr;
-}
-
-Addr
-TsunamiPChip::calcMemAddr(Addr addr)
-{
- return TSUNAMI_PCI0_MEMORY + addr;
-}
-
void
TsunamiPChip::serialize(CheckpointOut &cp) const
{
#define __TSUNAMI_PCHIP_HH__
#include "dev/alpha/tsunami.hh"
-#include "dev/io_device.hh"
+#include "dev/pci/host.hh"
#include "params/TsunamiPChip.hh"
/**
* A very simple implementation of the Tsunami PCI interface chips.
*/
-class TsunamiPChip : public BasicPioDevice
+class TsunamiPChip : public GenericPciHost
{
protected:
- static const Addr TsunamiPciBus0Config = ULL(0x801fe000000);
-
/** Pchip control register */
uint64_t pctl;
return dynamic_cast<const Params *>(_params);
}
+
+ void serialize(CheckpointOut &cp) const override;
+ void unserialize(CheckpointIn &cp) override;
+
+ public:
+ Tick read(PacketPtr pkt) override;
+ Tick write(PacketPtr pkt) override;
+
+ AddrRangeList getAddrRanges() const override;
+
/**
* Translate a PCI bus address to a memory address for DMA.
* @todo Andrew says this needs to be fixed. What's wrong with it?
- * @param busAddr PCI address to translate.
+ * @param pci_addr PCI address to translate.
* @return memory system address
*/
- Addr translatePciToDma(Addr busAddr);
-
- Addr calcConfigAddr(int bus, int dev, int func);
- Addr calcIOAddr(Addr addr);
- Addr calcMemAddr(Addr addr);
-
- Tick read(PacketPtr pkt) override;
- Tick write(PacketPtr pkt) override;
+ Addr dmaAddr(const PciBusAddr &addr, Addr pci_addr) const override;
- void serialize(CheckpointOut &cp) const override;
- void unserialize(CheckpointIn &cp) override;
+ protected:
+ const AddrRange pioRange;
+ const Tick pioDelay;
};
#endif // __TSUNAMI_PCHIP_HH__
from ClockDomain import ClockDomain
from VoltageDomain import VoltageDomain
from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr, DmaDevice
-from Pci import PciConfigAll
+from PciHost import *
from Ethernet import NSGigE, IGbE_igb, IGbE_e1000
from Ide import *
from Platform import Platform
type = 'RealView'
cxx_header = "dev/arm/realview.hh"
system = Param.System(Parent.any, "system")
- pci_io_base = Param.Addr(0, "Base address of PCI IO Space")
- pci_cfg_base = Param.Addr(0, "Base address of PCI Configuraiton Space")
- pci_cfg_gen_offsets = Param.Bool(False, "Should the offsets used for PCI cfg access"
- " be compatible with the pci-generic-host or the legacy host bridge?")
_mem_regions = [(Addr(0), Addr('256MB'))]
def attachPciDevices(self):
mcc = VExpressMCC()
dcc = CoreTile2A15DCC()
gic = Pl390()
+ pci_host = GenericPciHost(
+ conf_base=0x30000000, conf_size='256MB', conf_device_bits=16,
+ pci_pio_base=0)
timer0 = Sp804(int_num0=36, int_num1=36, pio_addr=0x10011000)
timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000)
local_cpu_timer = CpuLocalTimer(int_num_timer=29, int_num_watchdog=30, pio_addr=0x1f000600)
def attachIO(self, bus):
self.uart.pio = bus.master
self.realview_io.pio = bus.master
+ self.pci_host.pio = bus.master
self.timer0.pio = bus.master
self.timer1.pio = bus.master
self.clcd.pio = bus.master
self.kmi0.pio = bus.master
self.kmi1.pio = bus.master
self.cf_ctrl.pio = bus.master
- self.cf_ctrl.config = bus.master
self.cf_ctrl.dma = bus.slave
self.dmac_fake.pio = bus.master
self.uart1_fake.pio = bus.master
def attachIO(self, bus):
self.uart.pio = bus.master
self.realview_io.pio = bus.master
+ self.pci_host.pio = bus.master
self.timer0.pio = bus.master
self.timer1.pio = bus.master
self.clcd.pio = bus.master
class VExpress_EMM(RealView):
_mem_regions = [(Addr('2GB'), Addr('2GB'))]
- pci_cfg_base = 0x30000000
uart = Pl011(pio_addr=0x1c090000, int_num=37)
realview_io = RealViewCtrl(
proc_id0=0x14000000, proc_id1=0x14000000,
mcc = VExpressMCC()
dcc = CoreTile2A15DCC()
gic = Pl390(dist_addr=0x2C001000, cpu_addr=0x2C002000)
+ pci_host = GenericPciHost(
+ conf_base=0x30000000, conf_size='256MB', conf_device_bits=16,
+ pci_pio_base=0)
local_cpu_timer = CpuLocalTimer(int_num_timer=29, int_num_watchdog=30, pio_addr=0x2C080000)
generic_timer = GenericTimer(int_phys=29, int_virt=27)
timer0 = Sp804(int_num0=34, int_num1=34, pio_addr=0x1C110000, clock0='1MHz', clock1='1MHz')
BAR1 = 0x1C1A0100, BAR1Size = '4096B',
BAR0LegacyIO = True, BAR1LegacyIO = True)
- pciconfig = PciConfigAll(size='256MB')
vram = SimpleMemory(range = AddrRange(0x18000000, size='32MB'),
conf_table_reported = False)
rtc = PL031(pio_addr=0x1C170000, int_num=36)
def attachIO(self, bus):
self.uart.pio = bus.master
self.realview_io.pio = bus.master
+ self.pci_host.pio = bus.master
self.timer0.pio = bus.master
self.timer1.pio = bus.master
self.clcd.pio = bus.master
self.kmi1.pio = bus.master
self.cf_ctrl.pio = bus.master
self.cf_ctrl.dma = bus.slave
- self.cf_ctrl.config = bus.master
self.rtc.pio = bus.master
- bus.use_default_range = True
self.vram.port = bus.master
- self.pciconfig.pio = bus.default
self.l2x0_fake.pio = bus.master
self.uart1_fake.pio = bus.master
# Try to attach the I/O if it exists
try:
self.ide.pio = bus.master
- self.ide.config = bus.master
self.ide.dma = bus.slave
self.ethernet.pio = bus.master
- self.ethernet.config = bus.master
self.ethernet.dma = bus.slave
except:
pass
self.cf_ctrl.clk_domain = clkdomain
self.rtc.clk_domain = clkdomain
self.vram.clk_domain = clkdomain
- self.pciconfig.clk_domain = clkdomain
self.l2x0_fake.clk_domain = clkdomain
self.uart1_fake.clk_domain = clkdomain
self.energy_ctrl.clk_domain = clkdomain
class VExpress_EMM64(VExpress_EMM):
- pci_io_base = 0x2f000000
- pci_cfg_gen_offsets = True
# Three memory regions are specified totalling 512GB
_mem_regions = [(Addr('2GB'), Addr('2GB')), (Addr('34GB'), Addr('30GB')),
(Addr('512GB'), Addr('480GB'))]
+ pci_host = GenericPciHost(
+ conf_base=0x30000000, conf_size='256MB', conf_device_bits=12,
+ pci_pio_base=0x2f000000)
+
def setupBootLoader(self, mem_bus, cur_sys, loc):
self.nvmem = SimpleMemory(range = AddrRange(0, size = '64MB'))
self.nvmem.port = mem_bus.master
using namespace std;
using namespace TheISA;
+
RealView::RealView(const Params *p)
: Platform(p), system(p->system), gic(nullptr)
{}
-void
-RealView::initState()
-{
- Addr junk;
- bool has_gen_pci_host;
- has_gen_pci_host = system->kernelSymtab->findAddress("gen_pci_setup", junk);
-
- if (has_gen_pci_host && !params()->pci_cfg_gen_offsets)
- warn("Kernel supports generic PCI host but PCI Config offsets "
- "configured for legacy. Set pci_cfg_gen_offsets to True");
- if (has_gen_pci_host && !params()->pci_io_base)
- warn("Kernel supports generic PCI host but PCI IO base is set "
- "to 0. Set pci_io_base to the start of PCI IO space");
-}
-
void
RealView::postConsoleInt()
{
gic->clearInt(line);
}
-Addr
-RealView::pciToDma(Addr pciAddr) const
-{
- return pciAddr;
-}
-
-
-Addr
-RealView::calcPciConfigAddr(int bus, int dev, int func)
-{
- if (bus != 0)
- return ULL(-1);
-
- Addr cfg_offset = 0;
- if (params()->pci_cfg_gen_offsets)
- cfg_offset |= ((func & 7) << 12) | ((dev & 0x1f) << 15);
- else
- cfg_offset |= ((func & 7) << 16) | ((dev & 0x1f) << 19);
- return params()->pci_cfg_base | cfg_offset;
-}
-
-Addr
-RealView::calcPciIOAddr(Addr addr)
-{
- return params()->pci_io_base + addr;
-}
-
-Addr
-RealView::calcPciMemAddr(Addr addr)
-{
- return addr;
-}
-
RealView *
RealViewParams::create()
{
*/
RealView(const Params *p);
- /** In init do some checks to help verify we're setup correctly */
- virtual void initState();
-
/** Give platform a pointer to interrupt controller */
void setGic(BaseGic *_gic) { gic = _gic; }
- /**
- * Cause the cpu to post a serial interrupt to the CPU.
- */
- virtual void postConsoleInt();
-
- /**
- * Clear a posted CPU interrupt
- */
- virtual void clearConsoleInt();
-
- /**
- * Cause the chipset to post a cpi interrupt to the CPU.
- */
- virtual void postPciInt(int line);
-
- /**
- * Clear a posted PCI->CPU interrupt
- */
- virtual void clearPciInt(int line);
-
-
- virtual Addr pciToDma(Addr pciAddr) const;
-
- /**
- * Calculate the configuration address given a bus/dev/func.
- */
- virtual Addr calcPciConfigAddr(int bus, int dev, int func);
+ public: // Public Platform interfaces
+ void postConsoleInt() override;
+ void clearConsoleInt() override;
- /**
- * Calculate the address for an IO location on the PCI bus.
- */
- virtual Addr calcPciIOAddr(Addr addr);
-
- /**
- * Calculate the address for a memory location on the PCI bus.
- */
- virtual Addr calcPciMemAddr(Addr addr);
+ void postPciInt(int line) override;
+ void clearPciInt(int line) override;
};
#endif // __DEV_ARM_RealView_HH__
--- /dev/null
+# Copyright (c) 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.
+#
+# 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: Andreas Sandberg
+
+from m5.SimObject import SimObject
+from m5.params import *
+from m5.proxy import *
+from Device import PioDevice
+from Platform import Platform
+
+class PciHost(PioDevice):
+ type = 'PciHost'
+ cxx_class = 'PciHost'
+ cxx_header = "dev/pci/host.hh"
+ abstract = True
+
+class GenericPciHost(PciHost):
+ type = 'GenericPciHost'
+ cxx_class = 'GenericPciHost'
+ cxx_header = "dev/pci/host.hh"
+
+ platform = Param.Platform(Parent.any, "Platform to use for interrupts")
+
+ conf_base = Param.Addr("Config space base address")
+ conf_size = Param.Addr("Config space base address")
+ conf_device_bits = Param.UInt8(8, "Number of bits used to as an "
+ "offset a devices address space")
+
+ pci_pio_base = Param.Addr(0, "Base address for PCI IO accesses")
+ pci_mem_base = Param.Addr(0, "Base address for PCI memory accesses")
+ pci_dma_base = Param.Addr(0, "Base address for DMA memory accesses")
--- /dev/null
+# -*- mode:python -*-
+
+# Copyright (c) 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.
+#
+# 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: Andreas Sandberg
+
+Import('*')
+
+if env['TARGET_ISA'] == 'null':
+ Return()
+
+SimObject('PciHost.py')
+Source('host.cc')
+
+DebugFlag('PciHost')
--- /dev/null
+/*
+ * Copyright (c) 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.
+ *
+ * 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: Andreas Sandberg
+ */
+
+#include "dev/pci/host.hh"
+
+#include <utility>
+
+#include "debug/PciHost.hh"
+#include "dev/pcidev.hh"
+#include "dev/platform.hh"
+#include "params/GenericPciHost.hh"
+#include "params/PciHost.hh"
+
+
+PciHost::PciHost(const PciHostParams *p)
+ : PioDevice(p)
+{
+}
+
+PciHost::~PciHost()
+{
+}
+
+PciHost::DeviceInterface
+PciHost::registerDevice(PciDevice *device, PciBusAddr bus_addr, PciIntPin pin)
+{
+ auto map_entry = devices.emplace(bus_addr, device);
+
+ DPRINTF(PciHost, "%02x:%02x.%i: Registering device\n",
+ bus_addr.bus, bus_addr.dev, bus_addr.func);
+
+ fatal_if(!map_entry.second,
+ "%02x:%02x.%i: PCI bus ID collision\n",
+ bus_addr.bus, bus_addr.dev, bus_addr.func);
+
+ return DeviceInterface(*this, bus_addr, pin);
+}
+
+PciDevice *
+PciHost::getDevice(const PciBusAddr &addr)
+{
+ auto device = devices.find(addr);
+ return device != devices.end() ? device->second : nullptr;
+}
+
+const PciDevice *
+PciHost::getDevice(const PciBusAddr &addr) const
+{
+ auto device = devices.find(addr);
+ return device != devices.end() ? device->second : nullptr;
+}
+
+PciHost::DeviceInterface::DeviceInterface(
+ PciHost &_host,
+ PciBusAddr &bus_addr, PciIntPin interrupt_pin)
+ : host(_host),
+ busAddr(bus_addr), interruptPin(interrupt_pin)
+{
+}
+
+const std::string
+PciHost::DeviceInterface::name() const
+{
+ return csprintf("%s.interface[%02x:%02x.%i]",
+ host.name(), busAddr.bus, busAddr.dev, busAddr.func);
+}
+
+void
+PciHost::DeviceInterface::postInt()
+{
+ DPRINTF(PciHost, "postInt\n");
+
+ host.postInt(busAddr, interruptPin);
+}
+
+void
+PciHost::DeviceInterface::clearInt()
+{
+ DPRINTF(PciHost, "clearInt\n");
+
+ host.clearInt(busAddr, interruptPin);
+}
+
+
+GenericPciHost::GenericPciHost(const GenericPciHostParams *p)
+ : PciHost(p),
+ platform(*p->platform),
+ confBase(p->conf_base), confSize(p->conf_size),
+ confDeviceBits(p->conf_device_bits),
+ pciPioBase(p->pci_pio_base), pciMemBase(p->pci_mem_base),
+ pciDmaBase(p->pci_dma_base)
+{
+}
+
+GenericPciHost::~GenericPciHost()
+{
+}
+
+
+Tick
+GenericPciHost::read(PacketPtr pkt)
+{
+ const auto dev_addr(decodeAddress(pkt->getAddr() - confBase));
+ const Addr size(pkt->getSize());
+
+ DPRINTF(PciHost, "%02x:%02x.%i: read: offset=0x%x, size=0x%x\n",
+ dev_addr.first.bus, dev_addr.first.dev, dev_addr.first.func,
+ dev_addr.second,
+ size);
+
+ PciDevice *const pci_dev(getDevice(dev_addr.first));
+ if (pci_dev) {
+ // @todo Remove this after testing
+ pkt->headerDelay = pkt->payloadDelay = 0;
+ return pci_dev->readConfig(pkt);
+ } else {
+ uint8_t *pkt_data(pkt->getPtr<uint8_t>());
+ std::fill(pkt_data, pkt_data + size, 0xFF);
+ pkt->makeAtomicResponse();
+ return 0;
+ }
+}
+
+Tick
+GenericPciHost::write(PacketPtr pkt)
+{
+ const auto dev_addr(decodeAddress(pkt->getAddr() - confBase));
+
+ DPRINTF(PciHost, "%02x:%02x.%i: write: offset=0x%x, size=0x%x\n",
+ dev_addr.first.bus, dev_addr.first.dev, dev_addr.first.func,
+ dev_addr.second,
+ pkt->getSize());
+
+ PciDevice *const pci_dev(getDevice(dev_addr.first));
+ panic_if(!pci_dev,
+ "%02x:%02x.%i: Write to config space on non-existent PCI device\n",
+ dev_addr.first.bus, dev_addr.first.dev, dev_addr.first.func);
+
+ // @todo Remove this after testing
+ pkt->headerDelay = pkt->payloadDelay = 0;
+
+ return pci_dev->writeConfig(pkt);
+}
+
+AddrRangeList
+GenericPciHost::getAddrRanges() const
+{
+ return AddrRangeList({ RangeSize(confBase, confSize) });
+}
+
+std::pair<PciBusAddr, Addr>
+GenericPciHost::decodeAddress(Addr addr)
+{
+ const Addr offset(addr & mask(confDeviceBits));
+ const Addr bus_addr(addr >> confDeviceBits);
+
+ return std::make_pair(
+ PciBusAddr(bits(bus_addr, 15, 8),
+ bits(bus_addr, 7, 3),
+ bits(bus_addr, 2, 0)),
+ offset);
+}
+
+
+void
+GenericPciHost::postInt(const PciBusAddr &addr, PciIntPin pin)
+{
+ platform.postPciInt(mapPciInterrupt(addr, pin));
+}
+
+void
+GenericPciHost::clearInt(const PciBusAddr &addr, PciIntPin pin)
+{
+ platform.clearPciInt(mapPciInterrupt(addr, pin));
+}
+
+
+uint32_t
+GenericPciHost::mapPciInterrupt(const PciBusAddr &addr, PciIntPin pin) const
+{
+ const PciDevice *dev(getDevice(addr));
+ assert(dev);
+
+ return dev->interruptLine();
+}
+
+
+GenericPciHost *
+GenericPciHostParams::create()
+{
+ return new GenericPciHost(this);
+}
--- /dev/null
+/*
+ * Copyright (c) 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.
+ *
+ * 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: Andreas Sandberg
+ */
+
+#ifndef __DEV_PCI_HOST_HH__
+#define __DEV_PCI_HOST_HH__
+
+#include "dev/io_device.hh"
+#include "dev/pci/types.hh"
+
+struct PciHostParams;
+struct GenericPciHostParams;
+
+class PciDevice;
+class Platform;
+
+/**
+ * The PCI host describes the interface between PCI devices and a
+ * simulated system.
+ *
+ * The PCI host controller has three main responsibilities:
+ * <ol>
+ * <li>Expose a configuration memory space that allows devices to
+ * be discovered and configured.
+ * <li>Map and deliver interrupts to the CPU.
+ * <li>Map memory addresses from the PCI bus's various memory
+ * spaces (Legacy IO, non-prefetchable memory, and
+ * prefetchable memory) to physical memory.
+ * </ol>
+ *
+ * PCI devices need to register themselves with a PCI host using the
+ * PciHost::registerDevice() call. This call returns a
+ * PciHost::DeviceInterface that provides for common functionality
+ * such as interrupt delivery and memory mapping.
+ *
+ * The PciHost class itself provides very little functionality. Simple
+ * PciHost functionality is implemented by the GenericPciHost class.
+ */
+class PciHost : public PioDevice
+{
+ public:
+ PciHost(const PciHostParams *p);
+ virtual ~PciHost();
+
+ public:
+ /**
+ * @{
+ * @name Device interface
+ */
+
+ /**
+ * Callback interface from PCI devices to the host.
+ *
+ * Devices get an instance of this object when they register
+ * themselves with the host using the PciHost::registerDevice()
+ * call.
+ */
+ class DeviceInterface
+ {
+ friend class ::PciHost;
+
+ protected:
+ /**
+ * Instantiate a device interface
+ *
+ * @param host PCI host that this device belongs to.
+ * @param bus_addr The device's position on the PCI bus
+ * @param pin Interrupt pin
+ */
+ DeviceInterface(PciHost &host, PciBusAddr &bus_addr, PciIntPin pin);
+
+ public:
+ DeviceInterface() = delete;
+ void operator=(const DeviceInterface &) = delete;
+
+ const std::string name() const;
+
+ /**
+ * Post a PCI interrupt to the CPU.
+ */
+ void postInt();
+
+ /**
+ * Clear a posted PCI interrupt
+ */
+ void clearInt();
+
+ /**
+ * Calculate the physical address of an IO location on the PCI
+ * bus.
+ *
+ * @param addr Address in the PCI IO address space
+ * @return Address in the system's physical address space.
+ */
+ Addr pioAddr(Addr addr) const { return host.pioAddr(busAddr, addr); }
+
+ /**
+ * Calculate the physical address of a non-prefetchable memory
+ * location in the PCI address space.
+ *
+ * @param addr Address in the PCI memory address space
+ * @return Address in the system's physical address space.
+ */
+ Addr memAddr(Addr addr) const { return host.memAddr(busAddr, addr); }
+
+ /**
+ * Calculate the physical address of a prefetchable memory
+ * location in the PCI address space.
+ *
+ * @param addr Address in the PCI DMA memory address space
+ * @return Address in the system's physical address space.
+ */
+ Addr dmaAddr(Addr addr) const { return host.dmaAddr(busAddr, addr); }
+
+ protected:
+ PciHost &host;
+
+ const PciBusAddr busAddr;
+ const PciIntPin interruptPin;
+ };
+
+ /**
+ * Register a PCI device with the host.
+ *
+ * @param device Device to register
+ * @param bus_addr The device's position on the PCI bus
+ * @param pin Interrupt pin
+ * @return A device-specific DeviceInterface instance.
+ */
+ virtual DeviceInterface registerDevice(PciDevice *device,
+ PciBusAddr bus_addr, PciIntPin pin);
+
+ /** @} */
+
+ protected:
+ /**
+ * @{
+ * @name PciHost controller interface
+ */
+
+ /**
+ * Post an interrupt to the CPU.
+ *
+ * @param bus_addr The device's position on the PCI bus
+ * @param pin PCI interrupt pin
+ */
+ virtual void postInt(const PciBusAddr &bus_addr, PciIntPin pin) = 0;
+
+ /**
+ * Post an interrupt to the CPU.
+ *
+ * @param bus_addr The device's position on the PCI bus
+ * @param pin PCI interrupt pin
+ */
+ virtual void clearInt(const PciBusAddr &bus_addr, PciIntPin pin) = 0;
+
+ /**
+ * Calculate the physical address of an IO location on the PCI
+ * bus.
+ *
+ * @param bus_addr The device's position on the PCI bus
+ * @param pci_addr Address in the PCI IO address space
+ * @return Address in the system's physical address space.
+ */
+ virtual Addr pioAddr(const PciBusAddr &bus_addr, Addr pci_addr) const = 0;
+
+ /**
+ * Calculate the physical address of a non-prefetchable memory
+ * location in the PCI address space.
+ *
+ * @param bus_addr The device's position on the PCI bus
+ * @param pci_addr Address in the PCI memory address space
+ * @return Address in the system's physical address space.
+ */
+ virtual Addr memAddr(const PciBusAddr &bus_addr, Addr pci_addr) const = 0;
+
+
+ /**
+ * Calculate the physical address of a prefetchable memory
+ * location in the PCI address space.
+ *
+ * @param bus_addr The device's position on the PCI bus
+ * @param pci_addr Address in the PCI DMA memory address space
+ * @return Address in the system's physical address space.
+ */
+ virtual Addr dmaAddr(const PciBusAddr &bus_addr, Addr pci_addr) const = 0;
+
+ /** @} */
+
+ protected:
+ /**
+ * Retrieve a PCI device from its bus address.
+ *
+ * @return Pointer to a PciDevice instance or nullptr if the
+ * device doesn't exist.
+ */
+ PciDevice *getDevice(const PciBusAddr &addr);
+
+ /**
+ * Retrieve a PCI device from its bus address.
+ *
+ * @return Pointer to a constant PciDevice instance or nullptr if
+ * the device doesn't exist.
+ */
+ const PciDevice *getDevice(const PciBusAddr &addr) const;
+
+ private:
+ /** Currently registered PCI devices */
+ std::map<PciBusAddr, PciDevice *> devices;
+};
+
+/**
+ * Configurable generic PCI host interface
+ *
+ * The GenericPciHost provides a configurable generic PCI host
+ * implementation.
+ *
+ * The generic controller binds to one range of physical addresses to
+ * implement the PCI subsystem's configuraiton space. The base
+ * address, size and mapping between memory addresses and PCI devices
+ * are all configurable as simulation parameters. The basic
+ * implementation supports both the Configuration Access Mechanism
+ * (CAM) and Enhanced Configuration Access Mechanism (ECAM)
+ * configuration space layout. The layouts can be configured by
+ * changing the number of bits allocated to each device in the
+ * configuration space. ECAM uses 12 bits per device, while CAM uses 8
+ * bits per device.
+ *
+ * Interrupts are delivered via the Platform::postInt() and
+ * Platform::clearInt() calls. Interrupt numbers are mapped statically
+ * using the interrupt line (PciDevice::interruptLine()) returned from
+ * the device. Implementations may override mapPciInterrupt() to
+ * dynamically map a PciBusAddr and PciIntPin to a platform-specific
+ * interrupt.
+ *
+ * All PCI memory spaces (IO, prefetchable, and non-prefetchable)
+ * support a simple base+offset mapping that can be configured using
+ * simulation parameters. The base defaults to 0 for all of them.
+ */
+class GenericPciHost : public PciHost
+{
+ public:
+ GenericPciHost(const GenericPciHostParams *p);
+ virtual ~GenericPciHost();
+
+ public: // PioDevice
+ Tick read(PacketPtr pkt) override;
+ Tick write(PacketPtr pkt) override;
+
+ AddrRangeList getAddrRanges() const override;
+
+ protected: // PciHost
+ Addr pioAddr(const PciBusAddr &bus_addr, Addr pci_addr) const override {
+ return pciPioBase + pci_addr;
+ }
+
+ Addr memAddr(const PciBusAddr &bus_addr, Addr pci_addr) const override {
+ return pciMemBase + pci_addr;
+ }
+
+ Addr dmaAddr(const PciBusAddr &bus_addr, Addr pci_addr) const override {
+ return pciDmaBase + pci_addr;
+ }
+
+ protected: // Configuration address space handling
+ /**
+ * Decode a configuration space address.
+ *
+ *
+ * @param addr Offset into the configuration space
+ * @return Tuple containing the PCI bus address and an offset into
+ * the device's configuration space.
+ */
+ virtual std::pair<PciBusAddr, Addr> decodeAddress(Addr address);
+
+ protected: // Interrupt handling
+ void postInt(const PciBusAddr &addr, PciIntPin pin) override;
+ void clearInt(const PciBusAddr &addr, PciIntPin pin) override;
+
+ virtual uint32_t mapPciInterrupt(const PciBusAddr &bus_addr,
+ PciIntPin pin) const;
+
+ protected:
+ Platform &platform;
+
+ const Addr confBase;
+ const Addr confSize;
+ const uint8_t confDeviceBits;
+
+ const Addr pciPioBase;
+ const Addr pciMemBase;
+ const Addr pciDmaBase;
+};
+
+#endif // __DEV_PCI_HOST_HH__
--- /dev/null
+/*
+ * Copyright (c) 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.
+ *
+ * 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: Andreas Sandberg
+ */
+
+#ifndef __DEV_PCI_TYPES_HH__
+#define __DEV_PCI_TYPES_HH__
+
+struct PciBusAddr
+{
+ public:
+ PciBusAddr() = delete;
+
+ constexpr PciBusAddr(uint8_t _bus, uint8_t _dev, uint8_t _func)
+ : bus(_bus), dev(_dev), func(_func) {}
+
+ constexpr bool operator<(const PciBusAddr &rhs) const {
+ return sortValue() < rhs.sortValue();
+ }
+
+ uint8_t bus;
+ uint8_t dev;
+ uint8_t func;
+
+ protected:
+ constexpr uint32_t sortValue() const {
+ return (bus << 16) | (dev << 8) | func;
+ }
+};
+
+enum class PciIntPin : uint8_t
+{
+ NO_INT=0,
+ INTA,
+ INTB,
+ INTC,
+ INTD
+};
+
+#endif // __DEV_PCI_TYPES_HH__
+++ /dev/null
-/*
- * 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: Andrew Schultz
- * Ali Saidi
- */
-
-/* @file
- * PCI Configspace implementation
- */
-
-#include "base/trace.hh"
-#include "debug/PciConfigAll.hh"
-#include "dev/pciconfigall.hh"
-#include "dev/pcireg.h"
-#include "dev/platform.hh"
-#include "mem/packet.hh"
-#include "mem/packet_access.hh"
-#include "params/PciConfigAll.hh"
-#include "sim/system.hh"
-
-PciConfigAll::PciConfigAll(const Params *p)
- : BasicPioDevice(p, p->size)
-{
- // the pio_addr Python parameter is ignored, and overridden by
- // this caluclated value
- pioAddr = p->platform->calcPciConfigAddr(params()->bus,0,0);
-}
-
-
-Tick
-PciConfigAll::read(PacketPtr pkt)
-{
- DPRINTF(PciConfigAll, "read va=%#x size=%d\n", pkt->getAddr(),
- pkt->getSize());
-
- switch (pkt->getSize()) {
- case sizeof(uint32_t):
- pkt->set<uint32_t>(0xFFFFFFFF);
- break;
- case sizeof(uint16_t):
- pkt->set<uint16_t>(0xFFFF);
- break;
- case sizeof(uint8_t):
- pkt->set<uint8_t>(0xFF);
- break;
- default:
- panic("invalid access size(?) for PCI configspace!\n");
- }
- pkt->makeAtomicResponse();
- return pioDelay;
-}
-
-Tick
-PciConfigAll::write(PacketPtr pkt)
-{
- panic("Attempting to write to config space on non-existent device\n");
- M5_DUMMY_RETURN
-}
-
-
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
-
-PciConfigAll *
-PciConfigAllParams::create()
-{
- return new PciConfigAll(this);
-}
-
-#endif // DOXYGEN_SHOULD_SKIP_THIS
+++ /dev/null
-/*
- * 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: Andrew Schultz
- * Ali Saidi
- */
-
-/*
- * @file
- * PCI Config space implementation.
- */
-
-#ifndef __PCICONFIGALL_HH__
-#define __PCICONFIGALL_HH__
-
-#include "dev/io_device.hh"
-#include "dev/pcireg.h"
-#include "params/PciConfigAll.hh"
-
-/**
- * PCI Config Space
- * All of PCI config space needs to return -1 on Tsunami, except
- * the devices that exist. This device maps the entire bus config
- * space and passes the requests on to TsunamiPCIDevice devices as
- * appropriate.
- */
-class PciConfigAll : public BasicPioDevice
-{
- public:
- typedef PciConfigAllParams Params;
- const Params *params() const { return (const Params *)_params; }
-
- /**
- * Constructor for PCIConfigAll
- * @param p parameters structure
- */
- PciConfigAll(const Params *p);
-
- /**
- * Read something in PCI config space. If the device does not exist
- * -1 is returned, if the device does exist its PciDevice::ReadConfig
- * (or the virtual function that overrides) it is called.
- * @param pkt Contains information about the read operation
- * @return Amount of time to do the read
- */
- virtual Tick read(PacketPtr pkt);
-
- /**
- * Write to PCI config spcae. If the device does not exit the simulator
- * panics. If it does it is passed on the PciDevice::WriteConfig (or
- * the virtual function that overrides it).
- * @param pkt Contains information about the write operation
- * @return Amount of time to do the read
- */
-
- virtual Tick write(PacketPtr pkt);
-};
-
-#endif // __PCICONFIGALL_HH__
#include "sim/core.hh"
-PciDevice::PciConfigPort::PciConfigPort(PciDevice *dev, int busid, int devid,
- int funcid, Platform *p)
- : SimpleTimingPort(dev->name() + "-pciconf", dev), device(dev),
- platform(p), busId(busid), deviceId(devid), functionId(funcid)
-{
- configAddr = platform->calcPciConfigAddr(busId, deviceId, functionId);
-}
-
-
-Tick
-PciDevice::PciConfigPort::recvAtomic(PacketPtr pkt)
-{
- assert(pkt->getAddr() >= configAddr &&
- pkt->getAddr() < configAddr + PCI_CONFIG_SIZE);
-
- // technically the packet only reaches us after the header delay,
- // and typically we also need to deserialise any payload
- Tick receive_delay = pkt->headerDelay + pkt->payloadDelay;
- pkt->headerDelay = pkt->payloadDelay = 0;
-
- const Tick delay(pkt->isRead() ? device->readConfig(pkt) :
- device->writeConfig(pkt));
- return delay + receive_delay;
-}
-
-AddrRangeList
-PciDevice::PciConfigPort::getAddrRanges() const
-{
- AddrRangeList ranges;
- if (configAddr != ULL(-1))
- ranges.push_back(RangeSize(configAddr, PCI_CONFIG_SIZE+1));
- return ranges;
-}
-
-
-PciDevice::PciDevice(const Params *p)
+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),
MSIXCAP_MTAB_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MTAB),
MSIXCAP_MPBA_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MPBA),
PXCAP_BASE(p->PXCAPBaseOffset),
- platform(p->platform),
+
+ hostInterface(p->host->registerDevice(this, _busAddr,
+ (PciIntPin)p->InterruptPin)),
pioDelay(p->pio_latency),
- configDelay(p->config_latency),
- configPort(this, params()->pci_bus, params()->pci_dev,
- params()->pci_func, params()->platform)
+ 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);
}
}
}
-
- platform->registerPciDevice(p->pci_bus, p->pci_dev, p->pci_func,
- letoh(config.interruptLine));
-}
-
-void
-PciDevice::init()
-{
- if (!configPort.isConnected())
- panic("PCI config port on %s not connected to anything!\n", name());
- configPort.sendRangeChange();
- DmaDevice::init();
}
Tick
pkt->set<uint8_t>(config.data[offset]);
DPRINTF(PCIDEV,
"readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
- params()->pci_dev, params()->pci_func, offset,
+ _busAddr.dev, _busAddr.func, offset,
(uint32_t)pkt->get<uint8_t>());
break;
case sizeof(uint16_t):
pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]);
DPRINTF(PCIDEV,
"readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
- params()->pci_dev, params()->pci_func, offset,
+ _busAddr.dev, _busAddr.func, offset,
(uint32_t)pkt->get<uint16_t>());
break;
case sizeof(uint32_t):
pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]);
DPRINTF(PCIDEV,
"readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
- params()->pci_dev, params()->pci_func, offset,
+ _busAddr.dev, _busAddr.func, offset,
(uint32_t)pkt->get<uint32_t>());
break;
default:
}
DPRINTF(PCIDEV,
"writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
- params()->pci_dev, params()->pci_func, offset,
+ _busAddr.dev, _busAddr.func, offset,
(uint32_t)pkt->get<uint8_t>());
break;
case sizeof(uint16_t):
}
DPRINTF(PCIDEV,
"writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
- params()->pci_dev, params()->pci_func, offset,
+ _busAddr.dev, _busAddr.func, offset,
(uint32_t)pkt->get<uint16_t>());
break;
case sizeof(uint32_t):
he_new_bar &= ~bar_mask;
if (he_new_bar) {
BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ?
- platform->calcPciIOAddr(he_new_bar) :
- platform->calcPciMemAddr(he_new_bar);
+ hostInterface.pioAddr(he_new_bar) :
+ hostInterface.memAddr(he_new_bar);
pioPort.sendRangeChange();
}
}
}
DPRINTF(PCIDEV,
"writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
- params()->pci_dev, params()->pci_func, offset,
+ _busAddr.dev, _busAddr.func, offset,
(uint32_t)pkt->get<uint32_t>());
break;
default:
#include "dev/dma_device.hh"
#include "dev/pcireg.h"
-#include "dev/platform.hh"
+#include "dev/pci/host.hh"
#include "params/PciDevice.hh"
#include "sim/byteswap.hh"
#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
{
- class PciConfigPort : public SimpleTimingPort
- {
- protected:
- PciDevice *device;
-
- Tick recvAtomic(PacketPtr pkt) override;
-
- AddrRangeList getAddrRanges() const override;
-
- Platform *platform;
-
- int busId;
- int deviceId;
- int functionId;
-
- Addr configAddr;
-
- public:
- PciConfigPort(PciDevice *dev, int busid, int devid, int funcid,
- Platform *p);
- };
-
- public:
- typedef PciDeviceParams Params;
- const Params *
- params() const
- {
- return dynamic_cast<const Params *>(_params);
- }
-
protected:
+ const PciBusAddr _busAddr;
+
/** The current config space. */
PCIConfig config;
+
/** The capability list structures and base addresses
* @{
*/
return true;
}
- private:
- Platform *platform;
-
- protected:
- Tick pioDelay;
- Tick configDelay;
- PciConfigPort configPort;
-
+ 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
*/
virtual Tick readConfig(PacketPtr pkt);
- public:
- Addr pciToDma(Addr pciAddr) const
- { return platform->pciToDma(pciAddr); }
+ protected:
+ PciHost::DeviceInterface hostInterface;
+
+ Tick pioDelay;
+ Tick configDelay;
- void
- intrPost()
- { platform->postPciInt(letoh(config.interruptLine)); }
+ public:
+ Addr pciToDma(Addr pci_addr) const {
+ return hostInterface.dmaAddr(pci_addr);
+ }
- void
- intrClear()
- { platform->clearPciInt(letoh(config.interruptLine)); }
+ void intrPost() { hostInterface.postInt(); }
+ void intrClear() { hostInterface.clearInt(); }
- uint8_t
- interruptLine()
- { return letoh(config.interruptLine); }
+ uint8_t interruptLine() const { return letoh(config.interruptLine); }
/**
* Determine the address ranges that this device responds to.
/**
* Constructor for PCI Dev. This function copies data from the
* config file object PCIConfigData and registers the device with
- * a PciConfigAll object.
+ * a PciHost object.
*/
- PciDevice(const Params *params);
-
- void init() override;
+ PciDevice(const PciDeviceParams *params);
/**
* Serialize this object to the given output stream.
*/
void unserialize(CheckpointIn &cp) override;
-
- BaseSlavePort &getSlavePort(const std::string &if_name,
- PortID idx = InvalidPortID) override
- {
- if (if_name == "config") {
- return configPort;
- }
- return DmaDevice::getSlavePort(if_name, idx);
- }
-
+ const PciBusAddr &busAddr() const { return _busAddr; }
};
#endif // __DEV_PCIDEV_HH__
{
panic("No PCI interrupt support in platform.");
}
-
-Addr
-Platform::pciToDma(Addr pciAddr) const
-{
- panic("No PCI dma support in platform.");
- M5_DUMMY_RETURN
-}
-
-void
-Platform::registerPciDevice(uint8_t bus, uint8_t dev, uint8_t func, uint8_t intr)
-{
- uint32_t bdf = bus << 16 | dev << 8 | func << 0;
- if (pciDevices.find(bdf) != pciDevices.end())
- fatal("Two PCI devices have same bus:device:function\n");
-
- if (intLines.test(intr))
- fatal("Two PCI devices have same interrupt line: %d\n", intr);
-
- pciDevices.insert(bdf);
-
- intLines.set(intr);
-}
#include "params/Platform.hh"
#include "sim/sim_object.hh"
-class PciConfigAll;
class IntrControl;
class Terminal;
class Uart;
class System;
+
class Platform : public SimObject
{
public:
typedef PlatformParams Params;
Platform(const Params *p);
virtual ~Platform();
+
+ /**
+ * Cause the cpu to post a serial interrupt to the CPU.
+ */
virtual void postConsoleInt() = 0;
+
+ /**
+ * Clear a posted CPU interrupt
+ */
virtual void clearConsoleInt() = 0;
- virtual void postPciInt(int line);
- virtual void clearPciInt(int line);
- virtual Addr pciToDma(Addr pciAddr) const;
- virtual Addr calcPciConfigAddr(int bus, int dev, int func) = 0;
- virtual Addr calcPciIOAddr(Addr addr) = 0;
- virtual Addr calcPciMemAddr(Addr addr) = 0;
- virtual void registerPciDevice(uint8_t bus, uint8_t dev, uint8_t func,
- uint8_t intr);
- private:
- std::bitset<256> intLines;
- std::set<uint32_t> pciDevices;
+ /**
+ * Cause the chipset to post a cpi interrupt to the CPU.
+ */
+ virtual void postPciInt(int line);
+
+ /**
+ * Clear a posted PCI->CPU interrupt
+ */
+ virtual void clearPciInt(int line);
};
#endif // __DEV_PLATFORM_HH__
from m5.proxy import *
from Device import IsaFake
-from Pci import PciConfigAll
from Platform import Platform
from SouthBridge import SouthBridge
from Terminal import Terminal
from Uart import Uart8250
+from PciHost import GenericPciHost
def x86IOAddress(port):
IO_address_space_base = 0x8000000000000000
return IO_address_space_base + port;
+class PcPciHost(GenericPciHost):
+ conf_base = 0xC000000000000000
+ conf_size = "16MB"
+
+ pci_pio_base = 0x8000000000000000
+
class Pc(Platform):
type = 'Pc'
cxx_header = "dev/x86/pc.hh"
system = Param.System(Parent.any, "system")
- pciconfig = PciConfigAll()
-
south_bridge = SouthBridge()
+ pci_host = PcPciHost()
# "Non-existant" ports used for timing purposes by the linux kernel
i_dont_exist1 = IsaFake(pio_addr=x86IOAddress(0x80), pio_size=1)
self.fake_com_3.pio = bus.master
self.fake_com_4.pio = bus.master
self.fake_floppy.pio = bus.master
- self.pciconfig.pio = bus.default
+ self.pci_host.pio = bus.default
self.cmos.pio = bus.master
self.dma1.pio = bus.master
self.ide.pio = bus.master
- self.ide.config = bus.master
if dma_ports.count(self.ide.dma) == 0:
self.ide.dma = bus.slave
self.keyboard.pio = bus.master
warn_once("Tried to clear PCI interrupt %d\n", line);
}
-Addr
-Pc::pciToDma(Addr pciAddr) const
-{
- return pciAddr;
-}
-
-Addr
-Pc::calcPciConfigAddr(int bus, int dev, int func)
-{
- assert(func < 8);
- assert(dev < 32);
- assert(bus == 0);
- return (PhysAddrPrefixPciConfig | (func << 8) | (dev << 11));
-}
-
-Addr
-Pc::calcPciIOAddr(Addr addr)
-{
- return PhysAddrPrefixIO + addr;
-}
-
-Addr
-Pc::calcPciMemAddr(Addr addr)
-{
- return addr;
-}
-
Pc *
PcParams::create()
{
Pc(const Params *p);
- /**
- * Cause the cpu to post a serial interrupt to the CPU.
- */
- virtual void postConsoleInt();
-
- /**
- * Clear a posted CPU interrupt
- */
- virtual void clearConsoleInt();
-
- /**
- * Cause the chipset to post a pci interrupt to the CPU.
- */
- virtual void postPciInt(int line);
-
- /**
- * Clear a posted PCI->CPU interrupt
- */
- virtual void clearPciInt(int line);
-
-
- virtual Addr pciToDma(Addr pciAddr) const;
-
- /**
- * Calculate the configuration address given a bus/dev/func.
- */
- virtual Addr calcPciConfigAddr(int bus, int dev, int func);
-
- /**
- * Calculate the address for an IO location on the PCI bus.
- */
- virtual Addr calcPciIOAddr(Addr addr);
+ public:
+ void postConsoleInt() override;
+ void clearConsoleInt() override;
- /**
- * Calculate the address for a memory location on the PCI bus.
- */
- virtual Addr calcPciMemAddr(Addr addr);
+ void postPciInt(int line) override;
+ void clearPciInt(int line) override;
};
#endif // __DEV_PC_HH__