summaryrefslogtreecommitdiff
path: root/src/dev/pcidev.cc
diff options
context:
space:
mode:
authorAli Saidi <saidi@eecs.umich.edu>2006-07-06 14:41:01 -0400
committerAli Saidi <saidi@eecs.umich.edu>2006-07-06 14:41:01 -0400
commit93839380e7dc4799d234843d10329c03d38487fa (patch)
tree329e2bec6de1adb82ab5d756fded897363b998dc /src/dev/pcidev.cc
parent4201ec84b2dd7d96148bf661124dd7b5d0e7204b (diff)
downloadgem5-93839380e7dc4799d234843d10329c03d38487fa.tar.xz
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
Diffstat (limited to 'src/dev/pcidev.cc')
-rw-r--r--src/dev/pcidev.cc347
1 files changed, 201 insertions, 146 deletions
diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc
index f8db2efbc..62a7324ad 100644
--- a/src/dev/pcidev.cc
+++ b/src/dev/pcidev.cc
@@ -53,201 +53,256 @@
using namespace std;
-PciDev::PciDev(Params *p)
- : DmaDevice(p), plat(p->platform), configData(p->configData),
- pioDelay(p->pio_delay)
-{
- // copy the config data from the PciConfigData object
- if (configData) {
- memcpy(config.data, configData->config.data, sizeof(config.data));
- memcpy(BARSize, configData->BARSize, sizeof(BARSize));
- memcpy(BARAddrs, configData->BARAddrs, sizeof(BARAddrs));
- } 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);
-}
-
-void
-PciDev::readConfig(int offset, uint8_t *data)
+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)
{
- if (offset >= PCI_DEVICE_SPECIFIC)
- panic("Device specific PCI config space not implemented!\n");
+ configAddr = platform->calcConfigAddr(busId, deviceId, functionId);
+}
- *data = config.data[offset];
- DPRINTF(PCIDEV,
- "read device: %#x function: %#x register: %#x 1 bytes: data: %#x\n",
- params()->deviceNum, params()->functionNum, offset, *data);
+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::addressRanges(AddrRangeList &range_list)
+PciDev::PciConfigPort::recvFunctional(Packet *pkt)
{
- int x = 0;
- range_list.clear();
- for (x = 0; x < 6; x++)
- if (BARAddrs[x] != 0)
- range_list.push_back(RangeSize(BARAddrs[x],BARSize[x]));
+ assert(pkt->result == Packet::Unknown);
+ assert(pkt->getAddr() >= configAddr && pkt->getAddr() < configAddr +
+ PCI_CONFIG_SIZE);
+ device->recvConfig(pkt);
}
void
-PciDev::readConfig(int offset, uint16_t *data)
+PciDev::PciConfigPort::getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
{
- if (offset >= PCI_DEVICE_SPECIFIC)
- panic("Device specific PCI config space not implemented!\n");
+ snoop.clear();
+ resp.push_back(RangeSize(configAddr, PCI_CONFIG_SIZE+1));
+}
- *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);
+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;
}
-void
-PciDev::readConfig(int offset, uint32_t *data)
+PciDev::PciDev(Params *p)
+ : DmaDevice(p), plat(p->platform), configData(p->configData),
+ pioDelay(p->pio_delay), configDelay(p->config_delay),
+ configPort(NULL)
{
- if (offset >= PCI_DEVICE_SPECIFIC)
- panic("Device specific PCI config space not implemented!\n");
-
- *data = *(uint32_t*)&config.data[offset];
+ // copy the config data from the PciConfigData object
+ if (configData) {
+ memcpy(config.data, configData->config.data, sizeof(config.data));
+ memcpy(BARSize, configData->BARSize, sizeof(BARSize));
+ memcpy(BARAddrs, configData->BARAddrs, sizeof(BARAddrs));
+ } else
+ panic("NULL pointer to configuration data");
- DPRINTF(PCIDEV,
- "read device: %#x function: %#x register: %#x 4 bytes: data: %#x\n",
- params()->deviceNum, params()->functionNum, offset, *data);
+ plat->registerPciDevice(0, p->deviceNum, p->functionNum,
+ letoh(configData->config.interruptLine));
}
-
void
-PciDev::writeConfig(int offset, const 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");
- 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;
+ pkt->allocate();
+
+ 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,
+ (uint32_t)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:
+ 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("writing to a read only register");
+ panic("invalid access size(?) for PCI configspace!\n");
}
+ pkt->result = Packet::Success;
+ return configDelay;
+
}
void
-PciDev::writeConfig(int offset, const uint16_t data)
+PciDev::addressRanges(AddrRangeList &range_list)
{
- 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");
- }
+ int x = 0;
+ range_list.clear();
+ for (x = 0; x < 6; x++)
+ if (BARAddrs[x] != 0)
+ range_list.push_back(RangeSize(BARAddrs[x],BARSize[x]));
}
-
-void
-PciDev::writeConfig(int offset, const uint32_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");
- 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:
+
+ 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;
+ }
- // 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
-
- config.baseAddr[barnum] = letoh(
- (~(BARSize[barnum] - 1) & ~bar_mask) |
+ // 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));
- } else {
- config.baseAddr[barnum] = letoh(
- (letoh(data) & ~bar_mask) |
- (letoh(config.baseAddr[barnum]) & bar_mask));
- if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
- base_addr = (letoh(data) & ~bar_mask) + space_base;
- base_size = BARSize[barnum];
- BARAddrs[barnum] = base_addr;
+ 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);
+ 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