/* * 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. */ /* @file * PCI Configspace implementation */ #include #include #include #include #include "base/trace.hh" #include "dev/pciconfigall.hh" #include "dev/pcidev.hh" #include "dev/pcireg.h" #include "mem/bus/bus.hh" #include "mem/bus/pio_interface.hh" #include "mem/bus/pio_interface_impl.hh" #include "mem/functional/memory_control.hh" #include "sim/builder.hh" #include "sim/system.hh" using namespace std; PciConfigAll::PciConfigAll(const string &name, Addr a, MemoryController *mmu, HierParams *hier, Bus *bus, Tick pio_latency) : PioDevice(name, NULL), addr(a) { mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &PciConfigAll::cacheAccess); pioInterface->addAddrRange(RangeSize(addr, size)); pioLatency = pio_latency * bus->clockRate; } // 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; } // 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 } Fault PciConfigAll::read(MemReqPtr &req, uint8_t *data) { Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); DPRINTF(PciConfigAll, "read va=%#x da=%#x size=%d\n", req->vaddr, daddr, req->size); int device = (daddr >> 11) & 0x1F; int func = (daddr >> 8) & 0x7; int reg = daddr & 0xFF; if (devices[device][func] == NULL) { switch (req->size) { // case sizeof(uint64_t): // *(uint64_t*)data = 0xFFFFFFFFFFFFFFFF; // return No_Fault; case sizeof(uint32_t): *(uint32_t*)data = 0xFFFFFFFF; return No_Fault; case sizeof(uint16_t): *(uint16_t*)data = 0xFFFF; return No_Fault; case sizeof(uint8_t): *(uint8_t*)data = 0xFF; return No_Fault; default: panic("invalid access size(?) for PCI configspace!\n"); } } else { switch (req->size) { case sizeof(uint32_t): case sizeof(uint16_t): case sizeof(uint8_t): devices[device][func]->ReadConfig(reg, req->size, data); return No_Fault; default: panic("invalid access size(?) for PCI configspace!\n"); } } DPRINTFN("PCI Configspace ERROR: read daddr=%#x size=%d\n", daddr, req->size); return No_Fault; } Fault PciConfigAll::write(MemReqPtr &req, const uint8_t *data) { Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); int device = (daddr >> 11) & 0x1F; int func = (daddr >> 8) & 0x7; int reg = daddr & 0xFF; uint32_t word_value = 0; if (devices[device][func] == NULL) panic("Attempting to write to config space on non-existant device\n"); else { switch (req->size) { case sizeof(uint8_t): word_value = *(uint8_t*)data; break; case sizeof(uint16_t): word_value = *(uint16_t*)data; break; case sizeof(uint32_t): word_value = *(uint32_t*)data; break; default: panic("invalid access size(?) for PCI configspace!\n"); } } DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n", req->vaddr, req->size, word_value); devices[device][func]->WriteConfig(reg, req->size, word_value); return No_Fault; } void PciConfigAll::serialize(std::ostream &os) { /* * 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 */ } void PciConfigAll::unserialize(Checkpoint *cp, const std::string §ion) { /* * 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 */ } Tick PciConfigAll::cacheAccess(MemReqPtr &req) { return curTick + pioLatency; } #ifndef DOXYGEN_SHOULD_SKIP_THIS BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll) SimObjectParam mmu; Param addr; Param mask; SimObjectParam io_bus; Param pio_latency; SimObjectParam hier; END_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll) BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigAll) INIT_PARAM(mmu, "Memory Controller"), INIT_PARAM(addr, "Device Address"), INIT_PARAM(mask, "Address Mask"), INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL), INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) END_INIT_SIM_OBJECT_PARAMS(PciConfigAll) CREATE_SIM_OBJECT(PciConfigAll) { return new PciConfigAll(getInstanceName(), addr, mmu, hier, io_bus, pio_latency); } REGISTER_SIM_OBJECT("PciConfigAll", PciConfigAll) #endif // DOXYGEN_SHOULD_SKIP_THIS