Add default responder to bus

Update configuration for new default responder on bus
Update to devices to handle their own pci config space without pciconfigall
Remove most of pciconfigall, it now is a dumbdevice which gets it's address based on the bus it's supposed to respond for
Remove need for pci config space from platform, add registerPciDevice function to prevent more than one device from having same
bus:dev:func and interrupt
Remove pciconfigspace from pci devices, and py files
Add calcConfigAddr that returns address for config space based on bus/dev/function + offset

configs/test/fs.py:
    Update configuration for new default responder on bus
src/dev/ide_ctrl.cc:
src/dev/ide_ctrl.hh:
src/dev/ns_gige.cc:
src/dev/ns_gige.hh:
src/dev/pcidev.cc:
src/dev/pcidev.hh:
    Update to handle it's own pci config space without pciconfigall
src/dev/io_device.cc:
src/dev/io_device.hh:
    change naming for pio port
    break out recvTiming into two functions to reuse code
src/dev/pciconfigall.cc:
src/dev/pciconfigall.hh:
    removing most of pciconfigall, it now is a dumbdevice which gets it's address based on the bus it's supposed to respond for
src/dev/pcireg.h:
    add a max size for PCI config space (per PCI spec)
src/dev/platform.cc:
src/dev/platform.hh:
    remove need for pci config space from platform, add registerPciDevice function to prevent more than one device from having same
    bus:dev:func and interrupt
src/dev/sinic.cc:
    remove pciconfigspace as it's no longer a needed parameter
src/dev/tsunami.cc:
src/dev/tsunami.hh:
src/dev/tsunami_pchip.cc:
src/dev/tsunami_pchip.hh:
    add calcConfigAddr that returns address for config space based on bus/dev/function + offset (per PCI spec)
src/mem/bus.cc:
src/mem/bus.hh:
src/python/m5/objects/Bus.py:
    add idea of default responder to bus
src/python/m5/objects/Pci.py:
    add config port for pci devices
    add latency, bus and size parameters for pci config all (min is 8MB, max is 256MB see pci spec)

--HG--
extra : convert_revision : 99db43b0a3a077f86611d6eaff6664a3885da7c9
This commit is contained in:
Ali Saidi 2006-07-06 14:41:01 -04:00
parent 4201ec84b2
commit 93839380e7
23 changed files with 615 additions and 568 deletions

View file

@ -1,6 +1,6 @@
import m5
from m5.objects import *
import os
import os,optparse,sys
from SysPaths import *
parser = optparse.OptionParser(option_list=m5.standardOptions)
@ -98,7 +98,7 @@ class SpecwebFilesetDisk(IdeDisk):
class BaseTsunami(Tsunami):
cchip = TsunamiCChip(pio_addr=0x801a0000000)
pchip = TsunamiPChip(pio_addr=0x80180000000)
pciconfig = PciConfigAll(pio_addr=0x801fe000000)
pciconfig = PciConfigAll()
fake_sm_chip = IsaFake(pio_addr=0x801fc000370)
fake_uart1 = IsaFake(pio_addr=0x801fc0002f8)
@ -151,16 +151,18 @@ class MyLinuxAlphaSystem(LinuxAlphaSystem):
tsunami = LinuxTsunami()
tsunami.cchip.pio = magicbus.port
tsunami.pchip.pio = magicbus.port
tsunami.pciconfig.pio = magicbus.port
tsunami.pciconfig.pio = magicbus.default
tsunami.fake_sm_chip.pio = magicbus.port
tsunami.ethernet.pio = magicbus.port
tsunami.ethernet.dma = magicbus.port
tsunami.ethernet.config = magicbus.port
tsunami.fake_uart1.pio = magicbus.port
tsunami.fake_uart2.pio = magicbus.port
tsunami.fake_uart3.pio = magicbus.port
tsunami.fake_uart4.pio = magicbus.port
tsunami.ide.pio = magicbus.port
tsunami.ide.dma = magicbus.port
tsunami.ide.config = magicbus.port
tsunami.fake_ppc.pio = magicbus.port
tsunami.fake_OROM.pio = magicbus.port
tsunami.fake_pnp_addr.pio = magicbus.port

View file

@ -227,177 +227,143 @@ IdeController::setDmaComplete(IdeDisk *disk)
// Read and write handling
////
void
IdeController::readConfig(int offset, uint8_t *data)
Tick
IdeController::readConfig(Packet *pkt)
{
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::readConfig(offset, data);
} else if (offset >= IDE_CTRL_CONF_START &&
(offset + 1) <= IDE_CTRL_CONF_END) {
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
if (offset < PCI_DEVICE_SPECIFIC)
return PciDev::readConfig(pkt);
assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
pkt->allocate();
switch (pkt->getSize()) {
case sizeof(uint8_t):
switch (offset) {
case IDE_CTRL_CONF_DEV_TIMING:
*data = config_regs.sidetim;
pkt->set<uint8_t>(config_regs.sidetim);
break;
case IDE_CTRL_CONF_UDMA_CNTRL:
*data = config_regs.udmactl;
pkt->set<uint8_t>(config_regs.udmactl);
break;
case IDE_CTRL_CONF_PRIM_TIMING+1:
*data = htole(config_regs.idetim0) >> 8;
pkt->set<uint8_t>(htole(config_regs.idetim0) >> 8);
break;
case IDE_CTRL_CONF_SEC_TIMING+1:
*data = htole(config_regs.idetim1) >> 8;
pkt->set<uint8_t>(htole(config_regs.idetim1) >> 8);
break;
case IDE_CTRL_CONF_IDE_CONFIG:
*data = htole(config_regs.ideconfig) & 0xFF;
pkt->set<uint8_t>(htole(config_regs.ideconfig) & 0xFF);
break;
case IDE_CTRL_CONF_IDE_CONFIG+1:
*data = htole(config_regs.ideconfig) >> 8;
pkt->set<uint8_t>(htole(config_regs.ideconfig) >> 8);
break;
default:
panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
offset);
}
} else {
panic("Read of unimplemented PCI config. register: %x\n", offset);
}
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n",
offset, (uint32_t)*data);
}
void
IdeController::readConfig(int offset, uint16_t *data)
{
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::readConfig(offset, data);
} else if (offset >= IDE_CTRL_CONF_START &&
(offset + 2) <= IDE_CTRL_CONF_END) {
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
(uint32_t)pkt->get<uint8_t>());
break;
case sizeof(uint16_t):
switch (offset) {
case IDE_CTRL_CONF_PRIM_TIMING:
*data = config_regs.idetim0;
pkt->set<uint16_t>(config_regs.idetim0);
break;
case IDE_CTRL_CONF_SEC_TIMING:
*data = config_regs.idetim1;
pkt->set<uint16_t>(config_regs.idetim1);
break;
case IDE_CTRL_CONF_UDMA_TIMING:
*data = config_regs.udmatim;
pkt->set<uint16_t>(config_regs.udmatim);
break;
case IDE_CTRL_CONF_IDE_CONFIG:
*data = config_regs.ideconfig;
pkt->set<uint16_t>(config_regs.ideconfig);
break;
default:
panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
offset);
}
} else {
panic("Read of unimplemented PCI config. register: %x\n", offset);
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
(uint32_t)pkt->get<uint16_t>());
break;
case sizeof(uint32_t):
panic("No 32bit reads implemented for this device.");
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
(uint32_t)pkt->get<uint32_t>());
break;
default:
panic("invalid access size(?) for PCI configspace!\n");
}
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset, *data);
pkt->result = Packet::Success;
return configDelay;
}
void
IdeController::readConfig(int offset, uint32_t *data)
{
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::readConfig(offset, data);
} else {
panic("Read of unimplemented PCI config. register: %x\n", offset);
}
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset, *data);
}
void
IdeController::writeConfig(int offset, const uint8_t data)
{
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::writeConfig(offset, data);
} else if (offset >= IDE_CTRL_CONF_START &&
(offset + 1) <= IDE_CTRL_CONF_END) {
switch (offset) {
case IDE_CTRL_CONF_DEV_TIMING:
config_regs.sidetim = data;
Tick
IdeController::writeConfig(Packet *pkt)
{
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::writeConfig(pkt);
} else {
assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
switch (pkt->getSize()) {
case sizeof(uint8_t):
switch (offset) {
case IDE_CTRL_CONF_DEV_TIMING:
config_regs.sidetim = pkt->get<uint8_t>();
break;
case IDE_CTRL_CONF_UDMA_CNTRL:
config_regs.udmactl = pkt->get<uint8_t>();
break;
case IDE_CTRL_CONF_IDE_CONFIG:
config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) |
(pkt->get<uint8_t>());
break;
case IDE_CTRL_CONF_IDE_CONFIG+1:
config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) |
pkt->get<uint8_t>() << 8;
break;
default:
panic("Invalid PCI configuration write for size 1 offset: %#x!\n",
offset);
}
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
offset, (uint32_t)pkt->get<uint8_t>());
break;
case IDE_CTRL_CONF_UDMA_CNTRL:
config_regs.udmactl = data;
case sizeof(uint16_t):
switch (offset) {
case IDE_CTRL_CONF_PRIM_TIMING:
config_regs.idetim0 = pkt->get<uint16_t>();
break;
case IDE_CTRL_CONF_SEC_TIMING:
config_regs.idetim1 = pkt->get<uint16_t>();
break;
case IDE_CTRL_CONF_UDMA_TIMING:
config_regs.udmatim = pkt->get<uint16_t>();
break;
case IDE_CTRL_CONF_IDE_CONFIG:
config_regs.ideconfig = pkt->get<uint16_t>();
break;
default:
panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
offset);
}
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
offset, (uint32_t)pkt->get<uint16_t>());
break;
case IDE_CTRL_CONF_IDE_CONFIG:
config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) | (data);
break;
case IDE_CTRL_CONF_IDE_CONFIG+1:
config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) | data << 8;
case sizeof(uint32_t):
panic("Write of unimplemented PCI config. register: %x\n", offset);
break;
default:
panic("Invalid PCI configuration write for size 1 offset: %#x!\n",
offset);
panic("invalid access size(?) for PCI configspace!\n");
}
} else {
panic("Read of unimplemented PCI config. register: %x\n", offset);
}
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
offset, (uint32_t)data);
}
void
IdeController::writeConfig(int offset, const uint16_t data)
{
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::writeConfig(offset, data);
} else if (offset >= IDE_CTRL_CONF_START &&
(offset + 2) <= IDE_CTRL_CONF_END) {
switch (offset) {
case IDE_CTRL_CONF_PRIM_TIMING:
config_regs.idetim0 = data;
break;
case IDE_CTRL_CONF_SEC_TIMING:
config_regs.idetim1 = data;
break;
case IDE_CTRL_CONF_UDMA_TIMING:
config_regs.udmatim = data;
break;
case IDE_CTRL_CONF_IDE_CONFIG:
config_regs.ideconfig = data;
break;
default:
panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
offset);
}
} else {
panic("Write of unimplemented PCI config. register: %x\n", offset);
}
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", offset, data);
/* Trap command register writes and enable IO/BM as appropriate. */
if (offset == PCI_COMMAND) {
if (letoh(config.command) & PCI_CMD_IOSE)
io_enabled = true;
else
io_enabled = false;
if (letoh(config.command) & PCI_CMD_BME)
bm_enabled = true;
else
bm_enabled = false;
}
}
void
IdeController::writeConfig(int offset, const uint32_t data)
{
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::writeConfig(offset, data);
} else {
panic("Read of unimplemented PCI config. register: %x\n", offset);
}
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 4 data: %#x\n", offset, data);
/* Trap command register writes and enable IO/BM as appropriate as well as
* BARs. */
switch(offset) {
case PCI0_BASE_ADDR0:
if (BARAddrs[0] != 0)
@ -423,9 +389,24 @@ IdeController::writeConfig(int offset, const uint32_t data)
if (BARAddrs[4] != 0)
bmi_addr = BARAddrs[4];
break;
case PCI_COMMAND:
if (letoh(config.command) & PCI_CMD_IOSE)
io_enabled = true;
else
io_enabled = false;
if (letoh(config.command) & PCI_CMD_BME)
bm_enabled = true;
else
bm_enabled = false;
break;
}
pkt->result = Packet::Success;
return configDelay;
}
Tick
IdeController::read(Packet *pkt)
{
@ -770,7 +751,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
SimObjectParam<System *> system;
SimObjectParam<Platform *> platform;
SimObjectParam<PciConfigAll *> configspace;
SimObjectParam<PciConfigData *> configdata;
Param<uint32_t> pci_bus;
Param<uint32_t> pci_dev;
@ -784,7 +764,6 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
INIT_PARAM(system, "System pointer"),
INIT_PARAM(platform, "Platform pointer"),
INIT_PARAM(configspace, "PCI Configspace"),
INIT_PARAM(configdata, "PCI Config data"),
INIT_PARAM(pci_bus, "PCI bus ID"),
INIT_PARAM(pci_dev, "PCI device number"),
@ -800,7 +779,6 @@ CREATE_SIM_OBJECT(IdeController)
params->name = getInstanceName();
params->platform = platform;
params->system = system;
params->configSpace = configspace;
params->configData = configdata;
params->busNum = pci_bus;
params->deviceNum = pci_dev;

View file

@ -204,12 +204,8 @@ class IdeController : public PciDev
IdeController(Params *p);
~IdeController();
virtual void writeConfig(int offset, const uint8_t data);
virtual void writeConfig(int offset, const uint16_t data);
virtual void writeConfig(int offset, const uint32_t data);
virtual void readConfig(int offset, uint8_t *data);
virtual void readConfig(int offset, uint16_t *data);
virtual void readConfig(int offset, uint32_t *data);
virtual Tick writeConfig(Packet *pkt);
virtual Tick readConfig(Packet *pkt);
void setDmaComplete(IdeDisk *disk);

View file

@ -34,8 +34,8 @@
#include "sim/builder.hh"
PioPort::PioPort(PioDevice *dev, Platform *p)
: Port(dev->name() + "-pioport"), device(dev), platform(p)
PioPort::PioPort(PioDevice *dev, Platform *p, std::string pname)
: Port(dev->name() + pname), device(dev), platform(p)
{ }
@ -79,19 +79,23 @@ PioPort::SendEvent::process()
port->transmitList.push_back(packet);
}
void
PioPort::resendNacked(Packet *pkt) {
pkt->reinitNacked();
if (transmitList.size()) {
transmitList.push_front(pkt);
} else {
if (!Port::sendTiming(pkt))
transmitList.push_front(pkt);
}
};
bool
PioPort::recvTiming(Packet *pkt)
{
if (pkt->result == Packet::Nacked) {
pkt->reinitNacked();
if (transmitList.size()) {
transmitList.push_front(pkt);
} else {
if (!Port::sendTiming(pkt))
transmitList.push_front(pkt);
}
resendNacked(pkt);
} else {
Tick latency = device->recvAtomic(pkt);
// turn packet around to go back to requester

View file

@ -82,6 +82,8 @@ class PioPort : public Port
virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
void resendNacked(Packet *pkt);
/**
* This class is used to implemented sendTiming() with a delay. When a delay
* is requested a new event is created. When the event time expires it
@ -113,7 +115,7 @@ class PioPort : public Port
virtual void recvRetry();
public:
PioPort(PioDevice *dev, Platform *p);
PioPort(PioDevice *dev, Platform *p, std::string pname = "-pioport");
friend class PioPort::SendEvent;
};

View file

@ -465,11 +465,12 @@ NSGigE::regStats()
/**
* This is to write to the PCI general configuration registers
*/
void
NSGigE::writeConfig(int offset, const uint16_t data)
Tick
NSGigE::writeConfig(Packet *pkt)
{
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
if (offset < PCI_DEVICE_SPECIFIC)
PciDev::writeConfig(offset, data);
PciDev::writeConfig(pkt);
else
panic("Device specific PCI config space not implemented!\n");
@ -484,6 +485,8 @@ NSGigE::writeConfig(int offset, const uint16_t data)
ioEnable = false;
break;
}
pkt->result = Packet::Success;
return configDelay;
}
/**
@ -508,14 +511,7 @@ NSGigE::read(Packet *pkt)
if (daddr > LAST && daddr <= RESERVED) {
panic("Accessing reserved register");
} else if (daddr > RESERVED && daddr <= 0x3FC) {
if (pkt->getSize() == sizeof(uint8_t))
readConfig(daddr & 0xff, pkt->getPtr<uint8_t>());
if (pkt->getSize() == sizeof(uint16_t))
readConfig(daddr & 0xff, pkt->getPtr<uint16_t>());
if (pkt->getSize() == sizeof(uint32_t))
readConfig(daddr & 0xff, pkt->getPtr<uint32_t>());
pkt->result = Packet::Success;
return pioDelay;
return readConfig(pkt);
} else if (daddr >= MIB_START && daddr <= MIB_END) {
// don't implement all the MIB's. hopefully the kernel
// doesn't actually DEPEND upon their values
@ -733,14 +729,7 @@ NSGigE::write(Packet *pkt)
if (daddr > LAST && daddr <= RESERVED) {
panic("Accessing reserved register");
} else if (daddr > RESERVED && daddr <= 0x3FC) {
if (pkt->getSize() == sizeof(uint8_t))
writeConfig(daddr & 0xff, pkt->get<uint8_t>());
if (pkt->getSize() == sizeof(uint16_t))
writeConfig(daddr & 0xff, pkt->get<uint16_t>());
if (pkt->getSize() == sizeof(uint32_t))
writeConfig(daddr & 0xff, pkt->get<uint32_t>());
pkt->result = Packet::Success;
return pioDelay;
return writeConfig(pkt);
} else if (daddr > 0x3FC)
panic("Something is messed up!\n");
@ -2807,7 +2796,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
SimObjectParam<System *> system;
SimObjectParam<Platform *> platform;
SimObjectParam<PciConfigAll *> configspace;
SimObjectParam<PciConfigData *> configdata;
Param<uint32_t> pci_bus;
Param<uint32_t> pci_dev;
@ -2841,7 +2829,6 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
INIT_PARAM(system, "System pointer"),
INIT_PARAM(platform, "Platform pointer"),
INIT_PARAM(configspace, "PCI Configspace"),
INIT_PARAM(configdata, "PCI Config data"),
INIT_PARAM(pci_bus, "PCI bus ID"),
INIT_PARAM(pci_dev, "PCI device number"),
@ -2879,7 +2866,6 @@ CREATE_SIM_OBJECT(NSGigE)
params->name = getInstanceName();
params->platform = platform;
params->system = system;
params->configSpace = configspace;
params->configData = configdata;
params->busNum = pci_bus;
params->deviceNum = pci_dev;

View file

@ -114,7 +114,6 @@ struct dp_rom {
class NSGigEInt;
class Packet;
class PciConfigAll;
/**
* NS DP83820 Ethernet device model
@ -376,7 +375,7 @@ class NSGigE : public PciDev
~NSGigE();
const Params *params() const { return (const Params *)_params; }
virtual void writeConfig(int offset, const uint16_t data);
virtual Tick writeConfig(Packet *pkt);
virtual Tick read(Packet *pkt);
virtual Tick write(Packet *pkt);

View file

@ -33,14 +33,8 @@
* PCI Configspace implementation
*/
#include <deque>
#include <string>
#include <vector>
#include <bitset>
#include "base/trace.hh"
#include "dev/pciconfigall.hh"
#include "dev/pcidev.hh"
#include "dev/pcireg.h"
#include "dev/platform.hh"
#include "mem/packet.hh"
@ -50,151 +44,61 @@
using namespace std;
PciConfigAll::PciConfigAll(Params *p)
: BasicPioDevice(p)
: PioDevice(p)
{
pioSize = 0xffffff;
// Set backpointer for pci config. Really the config stuff should be able to
// automagically do this
p->platform->pciconfig = this;
// Make all the pointers to devices null
for(int x=0; x < MAX_PCI_DEV; x++)
for(int y=0; y < MAX_PCI_FUNC; y++)
devices[x][y] = NULL;
pioAddr = p->platform->calcConfigAddr(params()->bus,0,0);
}
// If two interrupts share the same line largely bad things will happen.
// Since we don't track how many times an interrupt was set and correspondingly
// cleared two devices on the same interrupt line and assert and deassert each
// others interrupt "line". Interrupts will not work correctly.
void
PciConfigAll::startup()
{
bitset<256> intLines;
PciDev *tempDev;
uint8_t intline;
for (int x = 0; x < MAX_PCI_DEV; x++) {
for (int y = 0; y < MAX_PCI_FUNC; y++) {
if (devices[x][y] != NULL) {
tempDev = devices[x][y];
intline = tempDev->interruptLine();
if (intLines.test(intline))
warn("Interrupt line %#X is used multiple times"
"(You probably want to fix this).\n", (uint32_t)intline);
else
intLines.set(intline);
} // devices != NULL
} // PCI_FUNC
} // PCI_DEV
}
Tick
PciConfigAll::read(Packet *pkt)
{
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
int device = (daddr >> 11) & 0x1F;
int func = (daddr >> 8) & 0x7;
int reg = daddr & 0xFF;
pkt->allocate();
DPRINTF(PciConfigAll, "read va=%#x da=%#x size=%d\n", pkt->getAddr(), daddr,
DPRINTF(PciConfigAll, "read va=%#x size=%d\n", pkt->getAddr(),
pkt->getSize());
switch (pkt->getSize()) {
case sizeof(uint32_t):
if (devices[device][func] == NULL)
pkt->set<uint32_t>(0xFFFFFFFF);
else
devices[device][func]->readConfig(reg, pkt->getPtr<uint32_t>());
pkt->set<uint32_t>(0xFFFFFFFF);
break;
case sizeof(uint16_t):
if (devices[device][func] == NULL)
pkt->set<uint16_t>(0xFFFF);
else
devices[device][func]->readConfig(reg, pkt->getPtr<uint16_t>());
pkt->set<uint16_t>(0xFFFF);
break;
case sizeof(uint8_t):
if (devices[device][func] == NULL)
pkt->set<uint8_t>(0xFF);
else
devices[device][func]->readConfig(reg, pkt->getPtr<uint8_t>());
pkt->set<uint8_t>(0xFF);
break;
default:
panic("invalid access size(?) for PCI configspace!\n");
}
pkt->result = Packet::Success;
return pioDelay;
return params()->pio_delay;
}
Tick
PciConfigAll::write(Packet *pkt)
{
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == sizeof(uint8_t) || pkt->getSize() == sizeof(uint16_t) ||
pkt->getSize() == sizeof(uint32_t));
Addr daddr = pkt->getAddr() - pioAddr;
int device = (daddr >> 11) & 0x1F;
int func = (daddr >> 8) & 0x7;
int reg = daddr & 0xFF;
if (devices[device][func] == NULL)
panic("Attempting to write to config space on non-existant device\n");
DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n",
pkt->getAddr(), pkt->getSize(), pkt->get<uint32_t>());
switch (pkt->getSize()) {
case sizeof(uint8_t):
devices[device][func]->writeConfig(reg, pkt->get<uint8_t>());
break;
case sizeof(uint16_t):
devices[device][func]->writeConfig(reg, pkt->get<uint16_t>());
break;
case sizeof(uint32_t):
devices[device][func]->writeConfig(reg, pkt->get<uint32_t>());
break;
default:
panic("invalid pci config write size\n");
}
pkt->result = Packet::Success;
return pioDelay;
panic("Attempting to write to config space on non-existant device\n");
}
void
PciConfigAll::serialize(std::ostream &os)
PciConfigAll::addressRanges(AddrRangeList &range_list)
{
/*
* There is no state associated with this object that requires
* serialization. The only real state are the device pointers
* which are all setup by the constructor of the PciDev class
*/
range_list.clear();
range_list.push_back(RangeSize(pioAddr, params()->size));
}
void
PciConfigAll::unserialize(Checkpoint *cp, const std::string &section)
{
/*
* There is no state associated with this object that requires
* serialization. The only real state are the device pointers
* which are all setup by the constructor of the PciDev class
*/
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
Param<Addr> pio_addr;
Param<Tick> pio_latency;
Param<int> bus;
Param<Addr> size;
SimObjectParam<Platform *> platform;
SimObjectParam<System *> system;
@ -202,8 +106,9 @@ END_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
INIT_PARAM(pio_addr, "Device Address"),
INIT_PARAM(pio_latency, "Programmed IO latency"),
INIT_PARAM(bus, "Bus that this object handles config space for"),
INIT_PARAM(size, "The size of config space"),
INIT_PARAM(platform, "platform"),
INIT_PARAM(system, "system object")
@ -211,11 +116,13 @@ END_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
CREATE_SIM_OBJECT(PciConfigAll)
{
BasicPioDevice::Params *p = new BasicPioDevice::Params;
p->pio_addr = pio_addr;
PciConfigAll::Params *p = new PciConfigAll::Params;
p->pio_delay = pio_latency;
p->platform = platform;
p->system = system;
p->bus = bus;
p->size = size;
return new PciConfigAll(p);
}

View file

@ -42,11 +42,6 @@
#include "dev/io_device.hh"
static const uint32_t MAX_PCI_DEV = 32;
static const uint32_t MAX_PCI_FUNC = 8;
class PciDev;
/**
* PCI Config Space
* All of PCI config space needs to return -1 on Tsunami, except
@ -54,45 +49,28 @@ class PciDev;
* space and passes the requests on to TsunamiPCIDev devices as
* appropriate.
*/
class PciConfigAll : public BasicPioDevice
class PciConfigAll : public PioDevice
{
private:
/**
* Pointers to all the devices that are registered with this
* particular config space.
*/
PciDev* devices[MAX_PCI_DEV][MAX_PCI_FUNC];
public:
struct Params : public PioDevice::Params
{
Tick pio_delay;
Addr size;
int bus;
};
const Params *params() const { return (const Params *)_params; }
/**
* Constructor for PCIConfigAll
* @param p parameters structure
*/
PciConfigAll(Params *p);
/**
* Check if a device exists.
* @param pcidev PCI device to check
* @param pcifunc PCI function to check
* @return true if device exists, false otherwise
*/
bool deviceExists(uint32_t pcidev, uint32_t pcifunc)
{ return devices[pcidev][pcifunc] != NULL ? true : false; }
/**
* Registers a device with the config space object.
* @param pcidev PCI device to register
* @param pcifunc PCI function to register
* @param device device to register
*/
void registerDevice(uint8_t pcidev, uint8_t pcifunc, PciDev *device)
{ devices[pcidev][pcifunc] = device; }
/**
* Read something in PCI config space. If the device does not exist
* -1 is returned, if the device does exist its PciDev::ReadConfig (or the
* virtual function that overrides) it is called.
* @param pkt Contains the address of the field to read.
* @param pkt Contains information about the read operation
* @return Amount of time to do the read
*/
virtual Tick read(Packet *pkt);
@ -101,31 +79,17 @@ class PciConfigAll : public BasicPioDevice
* Write to PCI config spcae. If the device does not exit the simulator
* panics. If it does it is passed on the PciDev::WriteConfig (or the virtual
* function that overrides it).
* @param req Contains the address to write to.
* @param data The data to write.
* @return The fault condition of the access.
* @param pkt Contains information about the write operation
* @return Amount of time to do the read
*/
virtual Tick write(Packet *pkt);
/**
* Start up function to check if more than one person is using an interrupt line
* and print a warning if such a case exists
*/
virtual void startup();
void addressRanges(AddrRangeList &range_list);
/**
* Serialize this object to the given output stream.
* @param os The stream to serialize to.
*/
virtual void serialize(std::ostream &os);
private:
Addr pioAddr;
/**
* Reconstruct the state of this object from a checkpoint.
* @param cp The checkpoint use.
* @param section The section name of this object
*/
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __PCICONFIGALL_HH__

View file

@ -53,9 +53,63 @@
using namespace std;
PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid,
int funcid, Platform *p)
: PioPort(dev,p,"-pciconf"), device(dev), busId(busid), deviceId(devid),
functionId(funcid)
{
configAddr = platform->calcConfigAddr(busId, deviceId, functionId);
}
Tick
PciDev::PciConfigPort::recvAtomic(Packet *pkt)
{
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= configAddr && pkt->getAddr() < configAddr +
PCI_CONFIG_SIZE);
return device->recvConfig(pkt);
}
void
PciDev::PciConfigPort::recvFunctional(Packet *pkt)
{
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= configAddr && pkt->getAddr() < configAddr +
PCI_CONFIG_SIZE);
device->recvConfig(pkt);
}
void
PciDev::PciConfigPort::getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
{
snoop.clear();
resp.push_back(RangeSize(configAddr, PCI_CONFIG_SIZE+1));
}
bool
PciDev::PciConfigPort::recvTiming(Packet *pkt)
{
if (pkt->result == Packet::Nacked) {
resendNacked(pkt);
} else {
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= configAddr && pkt->getAddr() < configAddr +
PCI_CONFIG_SIZE);
Tick latency = device->recvConfig(pkt);
// turn packet around to go back to requester
pkt->makeTimingResponse();
sendTiming(pkt, latency);
}
return true;
}
PciDev::PciDev(Params *p)
: DmaDevice(p), plat(p->platform), configData(p->configData),
pioDelay(p->pio_delay)
pioDelay(p->pio_delay), configDelay(p->config_delay),
configPort(NULL)
{
// copy the config data from the PciConfigData object
if (configData) {
@ -65,25 +119,56 @@ PciDev::PciDev(Params *p)
} else
panic("NULL pointer to configuration data");
// Setup pointer in config space to point to this entry
if (p->configSpace->deviceExists(p->deviceNum, p->functionNum))
panic("Two PCI devices occuping same dev: %#x func: %#x",
p->deviceNum, p->functionNum);
else
p->configSpace->registerDevice(p->deviceNum, p->functionNum, this);
plat->registerPciDevice(0, p->deviceNum, p->functionNum,
letoh(configData->config.interruptLine));
}
void
PciDev::readConfig(int offset, uint8_t *data)
PciDev::init()
{
if (!configPort)
panic("pci config port not connected to anything!");
configPort->sendStatusChange(Port::RangeChange);
PioDevice::init();
}
Tick
PciDev::readConfig(Packet *pkt)
{
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
if (offset >= PCI_DEVICE_SPECIFIC)
panic("Device specific PCI config space not implemented!\n");
*data = config.data[offset];
pkt->allocate();
DPRINTF(PCIDEV,
switch (pkt->getSize()) {
case sizeof(uint8_t):
pkt->set<uint8_t>(config.data[offset]);
DPRINTF(PCIDEV,
"read device: %#x function: %#x register: %#x 1 bytes: data: %#x\n",
params()->deviceNum, params()->functionNum, offset, *data);
params()->deviceNum, params()->functionNum, offset,
(uint32_t)pkt->get<uint8_t>());
break;
case sizeof(uint16_t):
pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]);
DPRINTF(PCIDEV,
"read device: %#x function: %#x register: %#x 2 bytes: data: %#x\n",
params()->deviceNum, params()->functionNum, offset,
(uint32_t)pkt->get<uint16_t>());
break;
case sizeof(uint32_t):
pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]);
DPRINTF(PCIDEV,
"read device: %#x function: %#x register: %#x 4 bytes: data: %#x\n",
params()->deviceNum, params()->functionNum, offset,
(uint32_t)pkt->get<uint32_t>());
break;
default:
panic("invalid access size(?) for PCI configspace!\n");
}
pkt->result = Packet::Success;
return configDelay;
}
void
@ -96,158 +181,128 @@ PciDev::addressRanges(AddrRangeList &range_list)
range_list.push_back(RangeSize(BARAddrs[x],BARSize[x]));
}
void
PciDev::readConfig(int offset, uint16_t *data)
Tick
PciDev::writeConfig(Packet *pkt)
{
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
if (offset >= PCI_DEVICE_SPECIFIC)
panic("Device specific PCI config space not implemented!\n");
*data = *(uint16_t*)&config.data[offset];
DPRINTF(PCIDEV,
"read device: %#x function: %#x register: %#x 2 bytes: data: %#x\n",
params()->deviceNum, params()->functionNum, offset, *data);
}
void
PciDev::readConfig(int offset, uint32_t *data)
{
if (offset >= PCI_DEVICE_SPECIFIC)
panic("Device specific PCI config space not implemented!\n");
*data = *(uint32_t*)&config.data[offset];
DPRINTF(PCIDEV,
"read device: %#x function: %#x register: %#x 4 bytes: data: %#x\n",
params()->deviceNum, params()->functionNum, offset, *data);
}
void
PciDev::writeConfig(int offset, const uint8_t data)
{
if (offset >= PCI_DEVICE_SPECIFIC)
panic("Device specific PCI config space not implemented!\n");
DPRINTF(PCIDEV,
"write device: %#x function: %#x reg: %#x size: 1 data: %#x\n",
params()->deviceNum, params()->functionNum, offset, data);
switch (offset) {
case PCI0_INTERRUPT_LINE:
config.interruptLine = data;
case PCI_CACHE_LINE_SIZE:
config.cacheLineSize = data;
case PCI_LATENCY_TIMER:
config.latencyTimer = data;
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");
}
}
void
PciDev::writeConfig(int offset, const uint16_t data)
{
if (offset >= PCI_DEVICE_SPECIFIC)
panic("Device specific PCI config space not implemented!\n");
DPRINTF(PCIDEV,
"write device: %#x function: %#x reg: %#x size: 2 data: %#x\n",
params()->deviceNum, params()->functionNum, offset, data);
switch (offset) {
case PCI_COMMAND:
config.command = data;
case PCI_STATUS:
config.status = data;
case PCI_CACHE_LINE_SIZE:
config.cacheLineSize = data;
break;
default:
panic("writing to a read only register");
}
}
void
PciDev::writeConfig(int offset, const uint32_t data)
{
if (offset >= PCI_DEVICE_SPECIFIC)
panic("Device specific PCI config space not implemented!\n");
DPRINTF(PCIDEV,
"write device: %#x function: %#x reg: %#x size: 4 data: %#x\n",
params()->deviceNum, params()->functionNum, offset, data);
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:
uint32_t barnum, bar_mask;
Addr base_addr, base_size, space_base;
barnum = BAR_NUMBER(offset);
if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) {
bar_mask = BAR_IO_MASK;
space_base = TSUNAMI_PCI0_IO;
} else {
bar_mask = BAR_MEM_MASK;
space_base = TSUNAMI_PCI0_MEMORY;
switch (pkt->getSize()) {
case sizeof(uint8_t):
switch (offset) {
case PCI0_INTERRUPT_LINE:
config.interruptLine = pkt->get<uint8_t>();
case PCI_CACHE_LINE_SIZE:
config.cacheLineSize = pkt->get<uint8_t>();
case PCI_LATENCY_TIMER:
config.latencyTimer = pkt->get<uint8_t>();
break;
/* Do nothing for these read-only registers */
case PCI0_INTERRUPT_PIN:
case PCI0_MINIMUM_GRANT:
case PCI0_MAXIMUM_LATENCY:
case PCI_CLASS_CODE:
case PCI_REVISION_ID:
break;
default:
panic("writing to a read only register");
}
DPRINTF(PCIDEV,
"write device: %#x function: %#x register: %#x 1 bytes: data: %#x\n",
params()->deviceNum, params()->functionNum, offset,
(uint32_t)pkt->get<uint8_t>());
break;
case sizeof(uint16_t):
switch (offset) {
case PCI_COMMAND:
config.command = pkt->get<uint8_t>();
case PCI_STATUS:
config.status = pkt->get<uint8_t>();
case PCI_CACHE_LINE_SIZE:
config.cacheLineSize = pkt->get<uint8_t>();
break;
default:
panic("writing to a read only register");
}
DPRINTF(PCIDEV,
"write device: %#x function: %#x register: %#x 2 bytes: data: %#x\n",
params()->deviceNum, params()->functionNum, offset,
(uint32_t)pkt->get<uint16_t>());
break;
case sizeof(uint32_t):
switch (offset) {
case PCI0_BASE_ADDR0:
case PCI0_BASE_ADDR1:
case PCI0_BASE_ADDR2:
case PCI0_BASE_ADDR3:
case PCI0_BASE_ADDR4:
case PCI0_BASE_ADDR5:
// Writing 0xffffffff to a BAR tells the card to set the
// value of the bar to size of memory it needs
if (letoh(data) == 0xffffffff) {
// This is I/O Space, bottom two bits are read only
uint32_t barnum, bar_mask;
Addr base_addr, base_size, space_base;
config.baseAddr[barnum] = letoh(
(~(BARSize[barnum] - 1) & ~bar_mask) |
(letoh(config.baseAddr[barnum]) & bar_mask));
} else {
config.baseAddr[barnum] = letoh(
(letoh(data) & ~bar_mask) |
(letoh(config.baseAddr[barnum]) & bar_mask));
barnum = BAR_NUMBER(offset);
if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
base_addr = (letoh(data) & ~bar_mask) + space_base;
base_size = BARSize[barnum];
BARAddrs[barnum] = base_addr;
pioPort->sendStatusChange(Port::RangeChange);
if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) {
bar_mask = BAR_IO_MASK;
space_base = TSUNAMI_PCI0_IO;
} else {
bar_mask = BAR_MEM_MASK;
space_base = TSUNAMI_PCI0_MEMORY;
}
// Writing 0xffffffff to a BAR tells the card to set the
// value of the bar to size of memory it needs
if (letoh(pkt->get<uint32_t>()) == 0xffffffff) {
// This is I/O Space, bottom two bits are read only
config.baseAddr[barnum] = letoh(
(~(BARSize[barnum] - 1) & ~bar_mask) |
(letoh(config.baseAddr[barnum]) & bar_mask));
} else {
config.baseAddr[barnum] = letoh(
(letoh(pkt->get<uint32_t>()) & ~bar_mask) |
(letoh(config.baseAddr[barnum]) & bar_mask));
if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
base_addr = (letoh(pkt->get<uint32_t>()) & ~bar_mask) + space_base;
base_size = BARSize[barnum];
BARAddrs[barnum] = base_addr;
pioPort->sendStatusChange(Port::RangeChange);
}
}
break;
case PCI0_ROM_BASE_ADDR:
if (letoh(pkt->get<uint32_t>()) == 0xfffffffe)
config.expansionROM = htole((uint32_t)0xffffffff);
else
config.expansionROM = pkt->get<uint32_t>();
break;
case PCI_COMMAND:
// This could also clear some of the error bits in the Status
// register. However they should never get set, so lets ignore
// it for now
config.command = pkt->get<uint32_t>();
break;
default:
DPRINTF(PCIDEV, "Writing to a read only register");
}
DPRINTF(PCIDEV,
"write device: %#x function: %#x register: %#x 4 bytes: data: %#x\n",
params()->deviceNum, params()->functionNum, offset,
(uint32_t)pkt->get<uint32_t>());
break;
case PCI0_ROM_BASE_ADDR:
if (letoh(data) == 0xfffffffe)
config.expansionROM = htole((uint32_t)0xffffffff);
else
config.expansionROM = data;
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 = data;
break;
default:
DPRINTF(PCIDEV, "Writing to a read only register");
panic("invalid access size(?) for PCI configspace!\n");
}
pkt->result = Packet::Success;
return configDelay;
}
void

View file

@ -47,8 +47,6 @@
#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT)
#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2);
class PciConfigAll;
/**
* This class encapulates the first 64 bytes of a singles PCI
@ -78,24 +76,41 @@ class PciConfigData : public SimObject
Addr BARAddrs[6];
};
/**
* PCI device, base implemnation is only config space.
* Each device is connected to a PCIConfigSpace device
* which returns -1 for everything but the pcidevs that
* register with it. This object registers with the PCIConfig space
* object.
*/
class PciDev : public DmaDevice
{
public:
struct Params : public ::PioDevice::Params
class PciConfigPort : public PioPort
{
/**
* A pointer to the configspace all object that calls us when
* a read comes to this particular device/function.
*/
PciConfigAll *configSpace;
protected:
PciDev *device;
virtual bool recvTiming(Packet *pkt);
virtual Tick recvAtomic(Packet *pkt);
virtual void recvFunctional(Packet *pkt) ;
virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
int busId;
int deviceId;
int functionId;
Addr configAddr;
public:
PciConfigPort(PciDev *dev, int busid, int devid, int funcid,
Platform *p);
friend class PioPort::SendEvent;
};
public:
struct Params : public PioDevice::Params
{
/**
* A pointer to the object that contains the first 64 bytes of
* config space
@ -113,6 +128,9 @@ class PciDev : public DmaDevice
/** The latency for pio accesses. */
Tick pio_delay;
/** The latency for a config access. */
Tick config_delay;
};
public:
@ -164,6 +182,25 @@ class PciDev : public DmaDevice
Platform *plat;
PciConfigData *configData;
Tick pioDelay;
Tick configDelay;
PciConfigPort *configPort;
/**
* 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(Packet *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(Packet *pkt);
public:
Addr pciToDma(Addr pciAddr) const
@ -171,21 +208,25 @@ class PciDev : public DmaDevice
void
intrPost()
{ plat->postPciInt(configData->config.interruptLine); }
{ plat->postPciInt(letoh(configData->config.interruptLine)); }
void
intrClear()
{ plat->clearPciInt(configData->config.interruptLine); }
{ plat->clearPciInt(letoh(configData->config.interruptLine)); }
uint8_t
interruptLine()
{ return configData->config.interruptLine; }
{ return letoh(configData->config.interruptLine); }
/** return the address ranges that this device responds to.
* @params range_list range list to populate with ranges
*/
void addressRanges(AddrRangeList &range_list);
/** Do a PCI Configspace memory access. */
Tick recvConfig(Packet *pkt)
{ return pkt->isRead() ? readConfig(pkt) : writeConfig(pkt); }
/**
* Constructor for PCI Dev. This function copies data from the
* config file object PCIConfigData and registers the device with
@ -193,30 +234,7 @@ class PciDev : public DmaDevice
*/
PciDev(Params *params);
/**
* 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 offset the offset into config space
* @param size the size of the write
* @param data the data to write
*/
virtual void writeConfig(int offset, const uint8_t data);
virtual void writeConfig(int offset, const uint16_t data);
virtual void writeConfig(int offset, const uint32_t data);
/**
* 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 offset the offset into config space
* @param size the size of the read
* @param data pointer to the location where the read value should be stored
*/
virtual void readConfig(int offset, uint8_t *data);
virtual void readConfig(int offset, uint16_t *data);
virtual void readConfig(int offset, uint32_t *data);
virtual void init();
/**
* Serialize this object to the given output stream.
@ -230,5 +248,19 @@ class PciDev : public DmaDevice
* @param section The section name of this object
*/
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual Port *getPort(const std::string &if_name, int idx = -1)
{
if (if_name == "config") {
if (configPort != NULL)
panic("pciconfig port already connected to.");
configPort = new PciConfigPort(this, params()->busNum,
params()->deviceNum, params()->functionNum,
params()->platform);
return configPort;
}
return DmaDevice::getPort(if_name, idx);
}
};
#endif // __DEV_PCIDEV_HH__

View file

@ -142,6 +142,7 @@ union PCIConfig {
// Device specific offsets
#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes
#define PCI_CONFIG_SIZE 0xFF
// Some Vendor IDs
#define PCI_VENDOR_DEC 0x1011

View file

@ -63,5 +63,21 @@ Platform::pciToDma(Addr pciAddr) const
panic("No PCI dma support in platform.");
}
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);
}
DEFINE_SIM_OBJECT_CLASS_NAME("Platform", Platform)

View file

@ -37,6 +37,9 @@
#ifndef __DEV_PLATFORM_HH__
#define __DEV_PLATFORM_HH__
#include <bitset>
#include <set>
#include "sim/sim_object.hh"
#include "arch/isa_traits.hh"
@ -52,9 +55,6 @@ class Platform : public SimObject
/** Pointer to the interrupt controller */
IntrControl *intrctrl;
/** Pointer to the PCI configuration space */
PciConfigAll *pciconfig;
/** Pointer to the UART, set by the uart */
Uart *uart;
@ -64,13 +64,20 @@ class Platform : public SimObject
public:
Platform(const std::string &name, IntrControl *intctrl);
virtual ~Platform();
virtual void init() { if (pciconfig == NULL) panic("PCI Config not set"); }
virtual void postConsoleInt() = 0;
virtual void clearConsoleInt() = 0;
virtual Tick intrFrequency() = 0;
virtual void postPciInt(int line);
virtual void clearPciInt(int line);
virtual Addr pciToDma(Addr pciAddr) const;
virtual Addr calcConfigAddr(int bus, int dev, int func) = 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;
};
#endif // __DEV_PLATFORM_HH__

View file

@ -37,7 +37,6 @@
#include "cpu/intr_control.hh"
#include "dev/etherlink.hh"
#include "dev/sinic.hh"
#include "dev/pciconfigall.hh"
#include "mem/packet.hh"
#include "sim/builder.hh"
#include "sim/debug.hh"
@ -1623,7 +1622,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
SimObjectParam<System *> system;
SimObjectParam<Platform *> platform;
SimObjectParam<PciConfigAll *> configspace;
SimObjectParam<PciConfigData *> configdata;
Param<uint32_t> pci_bus;
Param<uint32_t> pci_dev;
@ -1666,7 +1664,6 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
INIT_PARAM(system, "System pointer"),
INIT_PARAM(platform, "Platform pointer"),
INIT_PARAM(configspace, "PCI Configspace"),
INIT_PARAM(configdata, "PCI Config data"),
INIT_PARAM(pci_bus, "PCI bus ID"),
INIT_PARAM(pci_dev, "PCI device number"),
@ -1711,7 +1708,6 @@ CREATE_SIM_OBJECT(Device)
params->name = getInstanceName();
params->platform = platform;
params->system = system;
params->configSpace = configspace;
params->configData = configdata;
params->busNum = pci_bus;
params->deviceNum = pci_dev;

View file

@ -95,6 +95,13 @@ Tsunami::pciToDma(Addr pciAddr) const
return pchip->translatePciToDma(pciAddr);
}
Addr
Tsunami::calcConfigAddr(int bus, int dev, int func)
{
return pchip->calcConfigAddr(bus, dev, func);
}
void
Tsunami::serialize(std::ostream &os)
{

View file

@ -113,8 +113,14 @@ class Tsunami : public Platform
*/
virtual void clearPciInt(int line);
virtual Addr pciToDma(Addr pciAddr) const;
/**
* Calculate the configuration address given a bus/dev/func.
*/
virtual Addr calcConfigAddr(int bus, int dev, int func);
/**
* Serialize this object to the given output stream.
* @param os The stream to serialize to.

View file

@ -302,6 +302,17 @@ TsunamiPChip::translatePciToDma(Addr busAddr)
// if no match was found, then return the original address
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);
}
void
TsunamiPChip::serialize(std::ostream &os)

View file

@ -45,6 +45,9 @@
class TsunamiPChip : public BasicPioDevice
{
protected:
static const Addr TsunamiPciBus0Config = 0x801fe000000;
/** Pchip control register */
uint64_t pctl;
@ -80,6 +83,8 @@ class TsunamiPChip : public BasicPioDevice
*/
Addr translatePciToDma(Addr busAddr);
Addr calcConfigAddr(int bus, int dev, int func);
virtual Tick read(Packet *pkt);
virtual Tick write(Packet *pkt);

View file

@ -33,6 +33,7 @@
*/
#include "base/misc.hh"
#include "base/trace.hh"
#include "mem/bus.hh"
#include "sim/builder.hh"
@ -40,6 +41,14 @@
Port *
Bus::getPort(const std::string &if_name, int idx)
{
if (if_name == "default")
if (defaultPort == NULL) {
defaultPort = new BusPort(csprintf("%s-default",name()), this,
defaultId);
return defaultPort;
} else
fatal("Default port already set\n");
// if_name ignored? forced to be empty?
int id = interfaces.size();
BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
@ -47,11 +56,12 @@ Bus::getPort(const std::string &if_name, int idx)
return bp;
}
/** Get the ranges of anyone that we are connected to. */
/** Get the ranges of anyone other buses that we are connected to. */
void
Bus::init()
{
std::vector<Port*>::iterator intIter;
for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
(*intIter)->sendStatusChange(Port::RangeChange);
}
@ -110,6 +120,7 @@ Bus::findPort(Addr addr, int id)
int dest_id = -1;
int i = 0;
bool found = false;
AddrRangeIter iter;
while (i < portList.size() && !found)
{
@ -120,8 +131,18 @@ Bus::findPort(Addr addr, int id)
}
i++;
}
if (dest_id == -1)
// Check if this matches the default range
if (dest_id == -1) {
for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) {
if (*iter == addr) {
DPRINTF(Bus, " found addr 0x%llx on default\n", addr);
return defaultPort;
}
}
panic("Unable to find destination for addr: %llx", addr);
}
// we shouldn't be sending this back to where it came from
assert(dest_id != id);
@ -155,39 +176,52 @@ Bus::recvFunctional(Packet *pkt)
void
Bus::recvStatusChange(Port::Status status, int id)
{
AddrRangeList ranges;
AddrRangeList snoops;
int x;
AddrRangeIter iter;
assert(status == Port::RangeChange &&
"The other statuses need to be implemented.");
DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
assert(id < interfaces.size() && id >= 0);
int x;
Port *port = interfaces[id];
AddrRangeList ranges;
AddrRangeList snoops;
AddrRangeIter iter;
std::vector<DevMap>::iterator portIter;
if (id == defaultId) {
defaultRange.clear();
defaultPort->getPeerAddressRanges(ranges, snoops);
assert(snoops.size() == 0);
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
defaultRange.push_back(*iter);
DPRINTF(BusAddrRanges, "Adding range %llx - %llx for default\n",
iter->start, iter->end);
}
} else {
// Clean out any previously existent ids
for (portIter = portList.begin(); portIter != portList.end(); ) {
if (portIter->portId == id)
portIter = portList.erase(portIter);
else
portIter++;
}
assert((id < interfaces.size() && id >= 0) || id == -1);
Port *port = interfaces[id];
std::vector<DevMap>::iterator portIter;
port->getPeerAddressRanges(ranges, snoops);
// Clean out any previously existent ids
for (portIter = portList.begin(); portIter != portList.end(); ) {
if (portIter->portId == id)
portIter = portList.erase(portIter);
else
portIter++;
}
// not dealing with snooping yet either
assert(snoops.size() == 0);
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
DevMap dm;
dm.portId = id;
dm.range = *iter;
port->getPeerAddressRanges(ranges, snoops);
DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n",
dm.range.start, dm.range.end, id);
portList.push_back(dm);
// not dealing with snooping yet either
assert(snoops.size() == 0);
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
DevMap dm;
dm.portId = id;
dm.range = *iter;
DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n",
dm.range.start, dm.range.end, id);
portList.push_back(dm);
}
}
DPRINTF(MMU, "port list has %d entries\n", portList.size());
@ -196,19 +230,47 @@ Bus::recvStatusChange(Port::Status status, int id)
for (x = 0; x < interfaces.size(); x++)
if (x != id)
interfaces[x]->sendStatusChange(Port::RangeChange);
if (id != defaultId && defaultPort)
defaultPort->sendStatusChange(Port::RangeChange);
}
void
Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
{
std::vector<DevMap>::iterator portIter;
AddrRangeIter dflt_iter;
bool subset;
resp.clear();
snoop.clear();
DPRINTF(BusAddrRanges, "received address range request, returning:\n");
for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
dflt_iter++) {
resp.push_back(*dflt_iter);
DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n",dflt_iter->start,
dflt_iter->end);
}
for (portIter = portList.begin(); portIter != portList.end(); portIter++) {
if (portIter->portId != id) {
subset = false;
for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
dflt_iter++) {
if ((portIter->range.start < dflt_iter->start &&
portIter->range.end >= dflt_iter->start) ||
(portIter->range.start < dflt_iter->end &&
portIter->range.end >= dflt_iter->end))
fatal("Devices can not set ranges that itersect the default set\
but are not a subset of the default set.\n");
if (portIter->range.start >= dflt_iter->start &&
portIter->range.end <= dflt_iter->end) {
subset = true;
DPRINTF(BusAddrRanges, " -- %#llX : %#llX is a SUBSET\n",
portIter->range.start, portIter->range.end);
}
}
if (portIter->portId != id && !subset) {
resp.push_back(portIter->range);
DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n",
portIter->range.start, portIter->range.end);

View file

@ -51,19 +51,22 @@ class Bus : public MemObject
/** a globally unique id for this bus. */
int busId;
static const int defaultId = -1;
struct DevMap {
int portId;
Range<Addr> range;
};
std::vector<DevMap> portList;
AddrRangeList defaultRange;
/** Function called by the port when the bus is recieving a Timing
transaction.*/
transaction.*/
bool recvTiming(Packet *pkt);
/** Function called by the port when the bus is recieving a Atomic
transaction.*/
transaction.*/
Tick recvAtomic(Packet *pkt);
/** Function called by the port when the bus is recieving a Functional
@ -159,6 +162,9 @@ class Bus : public MemObject
* original send failed for whatever reason.*/
std::list<Port*> retryList;
/** Port that handles requests that don't match any of the interfaces.*/
Port *defaultPort;
public:
/** A function used to return the port associated with this bus object. */
@ -167,7 +173,7 @@ class Bus : public MemObject
virtual void init();
Bus(const std::string &n, int bus_id)
: MemObject(n), busId(bus_id) {}
: MemObject(n), busId(bus_id), defaultPort(NULL) {}
};

View file

@ -4,4 +4,5 @@ from MemObject import MemObject
class Bus(MemObject):
type = 'Bus'
port = VectorPort("vector port for connecting devices")
default = Port("Default port for requests that aren't handeled by a device.")
bus_id = Param.Int(0, "blah")

View file

@ -1,5 +1,5 @@
from m5.config import *
from Device import BasicPioDevice, DmaDevice
from Device import BasicPioDevice, DmaDevice, PioDevice
class PciConfigData(SimObject):
type = 'PciConfigData'
@ -38,18 +38,22 @@ class PciConfigData(SimObject):
MaximumLatency = Param.UInt8(0x00, "Maximum Latency")
MinimumGrant = Param.UInt8(0x00, "Minimum Grant")
class PciConfigAll(BasicPioDevice):
class PciConfigAll(PioDevice):
type = 'PciConfigAll'
pio_latency = Param.Tick(1, "Programmed IO latency in simticks")
bus = Param.UInt8(0x00, "PCI bus to act as config space for")
size = Param.MemorySize32('16MB', "Size of config space")
class PciDevice(DmaDevice):
type = 'PciDevice'
abstract = True
config = Port("PCI configuration space port")
pci_bus = Param.Int("PCI bus")
pci_dev = Param.Int("PCI device number")
pci_func = Param.Int("PCI function code")
pio_latency = Param.Tick(1, "Programmed IO latency in simticks")
configdata = Param.PciConfigData(Parent.any, "PCI Config data")
configspace = Param.PciConfigAll(Parent.any, "PCI Configspace")
class PciFake(PciDevice):
type = 'PciFake'