device.cc revision 9957
14166Sgblack@eecs.umich.edu/* 210554Salexandru.dutu@amd.com * Copyright (c) 2013 ARM Limited 37087Snate@binkert.org * All rights reserved 47087Snate@binkert.org * 57087Snate@binkert.org * The license below extends only to copyright in the software and shall 67087Snate@binkert.org * not be construed as granting a license to any other intellectual 77087Snate@binkert.org * property including but not limited to intellectual property relating 87087Snate@binkert.org * to a hardware implementation of the functionality of the software 97087Snate@binkert.org * licensed hereunder. You may use the software subject to the license 107087Snate@binkert.org * terms below provided that you ensure that this notice is replicated 117087Snate@binkert.org * unmodified and in its entirety in all distributions of the software, 127087Snate@binkert.org * modified or unmodified, in source code or in binary form. 137087Snate@binkert.org * 147087Snate@binkert.org * Copyright (c) 2004-2005 The Regents of The University of Michigan 154166Sgblack@eecs.umich.edu * All rights reserved. 164166Sgblack@eecs.umich.edu * 174166Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 184166Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 194166Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 204166Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 214166Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 224166Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 234166Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 244166Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 254166Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 264166Sgblack@eecs.umich.edu * this software without specific prior written permission. 274166Sgblack@eecs.umich.edu * 284166Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 294166Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 304166Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 314166Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 324166Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 334166Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 344166Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 354166Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 364166Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 374166Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 384166Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 394166Sgblack@eecs.umich.edu * 404166Sgblack@eecs.umich.edu * Authors: Ali Saidi 414166Sgblack@eecs.umich.edu * Andrew Schultz 424166Sgblack@eecs.umich.edu * Miguel Serrano 434166Sgblack@eecs.umich.edu */ 444166Sgblack@eecs.umich.edu 4511793Sbrandon.potter@amd.com/* @file 4611793Sbrandon.potter@amd.com * A single PCI device configuration space entry. 4711854Sbrandon.potter@amd.com */ 4811854Sbrandon.potter@amd.com 4911854Sbrandon.potter@amd.com#include <list> 5011793Sbrandon.potter@amd.com#include <string> 518229Snate@binkert.org#include <vector> 528229Snate@binkert.org 5310554Salexandru.dutu@amd.com#include "base/inifile.hh" 544166Sgblack@eecs.umich.edu#include "base/intmath.hh" 558229Snate@binkert.org#include "base/misc.hh" 564166Sgblack@eecs.umich.edu#include "base/str.hh" 5712334Sgabeblack@google.com#include "base/trace.hh" 585004Sgblack@eecs.umich.edu#include "debug/PCIDEV.hh" 594166Sgblack@eecs.umich.edu#include "dev/alpha/tsunamireg.h" 608232Snate@binkert.org#include "dev/pciconfigall.hh" 6110554Salexandru.dutu@amd.com#include "dev/pcidev.hh" 624166Sgblack@eecs.umich.edu#include "mem/packet.hh" 6312431Sgabeblack@google.com#include "mem/packet_access.hh" 6411854Sbrandon.potter@amd.com#include "sim/byteswap.hh" 654434Ssaidi@eecs.umich.edu#include "sim/core.hh" 6611794Sbrandon.potter@amd.com 6711800Sbrandon.potter@amd.com 684166Sgblack@eecs.umich.eduPciDevice::PciConfigPort::PciConfigPort(PciDevice *dev, int busid, int devid, 694166Sgblack@eecs.umich.edu int funcid, Platform *p) 704166Sgblack@eecs.umich.edu : SimpleTimingPort(dev->name() + "-pciconf", dev), device(dev), 714166Sgblack@eecs.umich.edu platform(p), busId(busid), deviceId(devid), functionId(funcid) 724166Sgblack@eecs.umich.edu{ 735958Sgblack@eecs.umich.edu configAddr = platform->calcPciConfigAddr(busId, deviceId, functionId); 745958Sgblack@eecs.umich.edu} 755958Sgblack@eecs.umich.edu 765958Sgblack@eecs.umich.edu 7711906SBrandon.Potter@amd.comTick 785958Sgblack@eecs.umich.eduPciDevice::PciConfigPort::recvAtomic(PacketPtr pkt) 7911906SBrandon.Potter@amd.com{ 805958Sgblack@eecs.umich.edu assert(pkt->getAddr() >= configAddr && 815958Sgblack@eecs.umich.edu pkt->getAddr() < configAddr + PCI_CONFIG_SIZE); 825958Sgblack@eecs.umich.edu // @todo someone should pay for this 8311704Santhony.gutierrez@amd.com pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; 8411704Santhony.gutierrez@amd.com return pkt->isRead() ? device->readConfig(pkt) : device->writeConfig(pkt); 8511704Santhony.gutierrez@amd.com} 8611704Santhony.gutierrez@amd.com 875959Sgblack@eecs.umich.eduAddrRangeList 885959Sgblack@eecs.umich.eduPciDevice::PciConfigPort::getAddrRanges() const 895959Sgblack@eecs.umich.edu{ 905959Sgblack@eecs.umich.edu AddrRangeList ranges; 915959Sgblack@eecs.umich.edu if (configAddr != ULL(-1)) 925959Sgblack@eecs.umich.edu ranges.push_back(RangeSize(configAddr, PCI_CONFIG_SIZE+1)); 9311385Sbrandon.potter@amd.com return ranges; 945959Sgblack@eecs.umich.edu} 9511704Santhony.gutierrez@amd.com 9611704Santhony.gutierrez@amd.com 9711704Santhony.gutierrez@amd.comPciDevice::PciDevice(const Params *p) 984166Sgblack@eecs.umich.edu : DmaDevice(p), 9912460Sgabeblack@google.com PMCAP_BASE(p->PMCAPBaseOffset), 10012460Sgabeblack@google.com MSICAP_BASE(p->MSICAPBaseOffset), 10112460Sgabeblack@google.com MSIXCAP_BASE(p->MSIXCAPBaseOffset), 10212460Sgabeblack@google.com PXCAP_BASE(p->PXCAPBaseOffset), 10312460Sgabeblack@google.com platform(p->platform), 10412460Sgabeblack@google.com pioDelay(p->pio_latency), 10512460Sgabeblack@google.com configDelay(p->config_latency), 10612460Sgabeblack@google.com configPort(this, params()->pci_bus, params()->pci_dev, 10712460Sgabeblack@google.com params()->pci_func, params()->platform) 10812431Sgabeblack@google.com{ 10911851Sbrandon.potter@amd.com config.vendor = htole(p->VendorID); 11012431Sgabeblack@google.com config.device = htole(p->DeviceID); 11112448Sgabeblack@google.com config.command = htole(p->Command); 11212460Sgabeblack@google.com config.status = htole(p->Status); 11312460Sgabeblack@google.com config.revision = htole(p->Revision); 11412448Sgabeblack@google.com config.progIF = htole(p->ProgIF); 11512448Sgabeblack@google.com config.subClassCode = htole(p->SubClassCode); 11612431Sgabeblack@google.com config.classCode = htole(p->ClassCode); 11712431Sgabeblack@google.com config.cacheLineSize = htole(p->CacheLineSize); 1184166Sgblack@eecs.umich.edu config.latencyTimer = htole(p->LatencyTimer); 11911886Sbrandon.potter@amd.com config.headerType = htole(p->HeaderType); 12011886Sbrandon.potter@amd.com config.bist = htole(p->BIST); 12111886Sbrandon.potter@amd.com 12211886Sbrandon.potter@amd.com config.baseAddr[0] = htole(p->BAR0); 12311886Sbrandon.potter@amd.com config.baseAddr[1] = htole(p->BAR1); 12411886Sbrandon.potter@amd.com config.baseAddr[2] = htole(p->BAR2); 12511886Sbrandon.potter@amd.com config.baseAddr[3] = htole(p->BAR3); 12611886Sbrandon.potter@amd.com config.baseAddr[4] = htole(p->BAR4); 1275956Sgblack@eecs.umich.edu config.baseAddr[5] = htole(p->BAR5); 1284166Sgblack@eecs.umich.edu config.cardbusCIS = htole(p->CardbusCIS); 12911851Sbrandon.potter@amd.com config.subsystemVendorID = htole(p->SubsystemVendorID); 13011851Sbrandon.potter@amd.com config.subsystemID = htole(p->SubsystemID); 13111851Sbrandon.potter@amd.com config.expansionROM = htole(p->ExpansionROM); 1325956Sgblack@eecs.umich.edu config.capabilityPtr = htole(p->CapabilityPtr); 1336709Svince@csl.cornell.edu // Zero out the 7 bytes of reserved space in the PCI Config space register. 1346709Svince@csl.cornell.edu bzero(config.reserved, 7*sizeof(uint8_t)); 13510318Sandreas.hansson@arm.com config.interruptLine = htole(p->InterruptLine); 1366709Svince@csl.cornell.edu config.interruptPin = htole(p->InterruptPin); 1379679Smjleven@sandia.gov config.minimumGrant = htole(p->MinimumGrant); 1386709Svince@csl.cornell.edu config.maximumLatency = htole(p->MaximumLatency); 13911905SBrandon.Potter@amd.com 14011905SBrandon.Potter@amd.com // Initialize the capability lists 14111905SBrandon.Potter@amd.com // These structs are bitunions, meaning the data is stored in host 14211905SBrandon.Potter@amd.com // endianess and must be converted to Little Endian when accessed 14311905SBrandon.Potter@amd.com // by the guest 14411905SBrandon.Potter@amd.com // PMCAP 1454166Sgblack@eecs.umich.edu pmcap.pid.cid = p->PMCAPCapId; 14611905SBrandon.Potter@amd.com pmcap.pid.next = p->PMCAPNextCapability; 14711905SBrandon.Potter@amd.com pmcap.pc = p->PMCAPCapabilities; 1484166Sgblack@eecs.umich.edu pmcap.pmcs = p->PMCAPCtrlStatus; 1494166Sgblack@eecs.umich.edu 1505973Sgblack@eecs.umich.edu // MSICAP 15111877Sbrandon.potter@amd.com msicap.mid.cid = p->MSICAPCapId; 1525973Sgblack@eecs.umich.edu msicap.mid.next = p->MSICAPNextCapability; 1537720Sgblack@eecs.umich.edu msicap.mc = p->MSICAPMsgCtrl; 1547720Sgblack@eecs.umich.edu msicap.ma = p->MSICAPMsgAddr; 1555973Sgblack@eecs.umich.edu msicap.mua = p->MSICAPMsgUpperAddr; 1565973Sgblack@eecs.umich.edu msicap.md = p->MSICAPMsgData; 1577720Sgblack@eecs.umich.edu msicap.mmask = p->MSICAPMaskBits; 1587720Sgblack@eecs.umich.edu msicap.mpend = p->MSICAPPendingBits; 1595973Sgblack@eecs.umich.edu 16011877Sbrandon.potter@amd.com // MSIXCAP 1615973Sgblack@eecs.umich.edu msixcap.mxid.cid = p->MSIXCAPCapId; 1625973Sgblack@eecs.umich.edu msixcap.mxid.next = p->MSIXCAPNextCapability; 1635973Sgblack@eecs.umich.edu msixcap.mxc = p->MSIXMsgCtrl; 16411851Sbrandon.potter@amd.com msixcap.mtab = p->MSIXTableOffset; 16511851Sbrandon.potter@amd.com msixcap.mpba = p->MSIXPbaOffset; 16611851Sbrandon.potter@amd.com 1674166Sgblack@eecs.umich.edu // allocate MSIX structures if MSIXCAP_BASE 1689026Sgblack@eecs.umich.edu // indicates the MSIXCAP is being used by having a 16910318Sandreas.hansson@arm.com // non-zero base address. 1705973Sgblack@eecs.umich.edu // The MSIX tables are stored by the guest in 1715973Sgblack@eecs.umich.edu // little endian byte-order as according the 17210318Sandreas.hansson@arm.com // PCIe specification. Make sure to take the proper 1735973Sgblack@eecs.umich.edu // actions when manipulating these tables on the host 1745973Sgblack@eecs.umich.edu if (MSIXCAP_BASE != 0x0) { 1755973Sgblack@eecs.umich.edu int msix_vecs = msixcap.mxc.ts + 1; 17611905SBrandon.Potter@amd.com MSIXTable tmp1 = {{0UL,0UL,0UL,0UL}}; 17711905SBrandon.Potter@amd.com msix_table.resize(msix_vecs, tmp1); 17811905SBrandon.Potter@amd.com 17911905SBrandon.Potter@amd.com MSIXPbaEntry tmp2 = {0}; 18011905SBrandon.Potter@amd.com int pba_size = msix_vecs / MSIXVECS_PER_PBA; 18111905SBrandon.Potter@amd.com if ((msix_vecs % MSIXVECS_PER_PBA) > 0) { 1825956Sgblack@eecs.umich.edu pba_size++; 18311905SBrandon.Potter@amd.com } 18411905SBrandon.Potter@amd.com msix_pba.resize(pba_size, tmp2); 1855956Sgblack@eecs.umich.edu } 1865956Sgblack@eecs.umich.edu 1875956Sgblack@eecs.umich.edu // PXCAP 18811851Sbrandon.potter@amd.com pxcap.pxid.cid = p->PXCAPCapId; 1895956Sgblack@eecs.umich.edu pxcap.pxid.next = p->PXCAPNextCapability; 1905956Sgblack@eecs.umich.edu pxcap.pxcap = p->PXCAPCapabilities; 1915956Sgblack@eecs.umich.edu pxcap.pxdcap = p->PXCAPDevCapabilities; 1925956Sgblack@eecs.umich.edu pxcap.pxdc = p->PXCAPDevCtrl; 1934166Sgblack@eecs.umich.edu pxcap.pxds = p->PXCAPDevStatus; 1944166Sgblack@eecs.umich.edu pxcap.pxlcap = p->PXCAPLinkCap; 1954166Sgblack@eecs.umich.edu pxcap.pxlc = p->PXCAPLinkCtrl; 19611851Sbrandon.potter@amd.com pxcap.pxls = p->PXCAPLinkStatus; 1974166Sgblack@eecs.umich.edu pxcap.pxdcap2 = p->PXCAPDevCap2; 19811851Sbrandon.potter@amd.com pxcap.pxdc2 = p->PXCAPDevCtrl2; 1995183Ssaidi@eecs.umich.edu 20011884Sbrandon.potter@amd.com BARSize[0] = p->BAR0Size; 2015140Sgblack@eecs.umich.edu BARSize[1] = p->BAR1Size; 20211906SBrandon.Potter@amd.com BARSize[2] = p->BAR2Size; 2038601Ssteve.reinhardt@amd.com BARSize[3] = p->BAR3Size; 2046709Svince@csl.cornell.edu BARSize[4] = p->BAR4Size; 2056709Svince@csl.cornell.edu BARSize[5] = p->BAR5Size; 2066709Svince@csl.cornell.edu 2076709Svince@csl.cornell.edu legacyIO[0] = p->BAR0LegacyIO; 2086709Svince@csl.cornell.edu legacyIO[1] = p->BAR1LegacyIO; 2098852Sandreas.hansson@arm.com legacyIO[2] = p->BAR2LegacyIO; 2106709Svince@csl.cornell.edu legacyIO[3] = p->BAR3LegacyIO; 2116709Svince@csl.cornell.edu legacyIO[4] = p->BAR4LegacyIO; 2126709Svince@csl.cornell.edu legacyIO[5] = p->BAR5LegacyIO; 2136709Svince@csl.cornell.edu 2146709Svince@csl.cornell.edu for (int i = 0; i < 6; ++i) { 2156709Svince@csl.cornell.edu if (legacyIO[i]) { 2166709Svince@csl.cornell.edu BARAddrs[i] = platform->calcPciIOAddr(letoh(config.baseAddr[i])); 2178852Sandreas.hansson@arm.com config.baseAddr[i] = 0; 2186709Svince@csl.cornell.edu } else { 2196709Svince@csl.cornell.edu BARAddrs[i] = 0; 22010554Salexandru.dutu@amd.com uint32_t barsize = BARSize[i]; 22110554Salexandru.dutu@amd.com if (barsize != 0 && !isPowerOf2(barsize)) { 2225140Sgblack@eecs.umich.edu fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]); 22312458Sgabeblack@google.com } 22412458Sgabeblack@google.com } 22512458Sgabeblack@google.com } 22612458Sgabeblack@google.com 22712458Sgabeblack@google.com platform->registerPciDevice(p->pci_bus, p->pci_dev, p->pci_func, 22812458Sgabeblack@google.com letoh(config.interruptLine)); 22912458Sgabeblack@google.com} 23010554Salexandru.dutu@amd.com 23110554Salexandru.dutu@amd.comvoid 23210554Salexandru.dutu@amd.comPciDevice::init() 23310554Salexandru.dutu@amd.com{ 23410554Salexandru.dutu@amd.com if (!configPort.isConnected()) 23512458Sgabeblack@google.com panic("PCI config port on %s not connected to anything!\n", name()); 23610554Salexandru.dutu@amd.com configPort.sendRangeChange(); 23710554Salexandru.dutu@amd.com DmaDevice::init(); 2385140Sgblack@eecs.umich.edu} 23910554Salexandru.dutu@amd.com 24010554Salexandru.dutu@amd.comunsigned int 24110554Salexandru.dutu@amd.comPciDevice::drain(DrainManager *dm) 24210554Salexandru.dutu@amd.com{ 24310554Salexandru.dutu@amd.com unsigned int count; 24410554Salexandru.dutu@amd.com count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm); 24510554Salexandru.dutu@amd.com if (count) 24610554Salexandru.dutu@amd.com setDrainState(Drainable::Draining); 24710554Salexandru.dutu@amd.com else 24812588Sgabeblack@google.com setDrainState(Drainable::Drained); 24912588Sgabeblack@google.com return count; 25010554Salexandru.dutu@amd.com} 25110554Salexandru.dutu@amd.com 25210554Salexandru.dutu@amd.comTick 25310554Salexandru.dutu@amd.comPciDevice::readConfig(PacketPtr pkt) 25410554Salexandru.dutu@amd.com{ 25510554Salexandru.dutu@amd.com int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 25612458Sgabeblack@google.com if (offset >= PCI_DEVICE_SPECIFIC) 25710554Salexandru.dutu@amd.com panic("Device specific PCI config space not implemented!\n"); 25810554Salexandru.dutu@amd.com 25910554Salexandru.dutu@amd.com pkt->allocate(); 26010554Salexandru.dutu@amd.com 26110554Salexandru.dutu@amd.com switch (pkt->getSize()) { 26210554Salexandru.dutu@amd.com case sizeof(uint8_t): 26310554Salexandru.dutu@amd.com pkt->set<uint8_t>(config.data[offset]); 26410554Salexandru.dutu@amd.com DPRINTF(PCIDEV, 26510554Salexandru.dutu@amd.com "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 26610554Salexandru.dutu@amd.com params()->pci_dev, params()->pci_func, offset, 26710554Salexandru.dutu@amd.com (uint32_t)pkt->get<uint8_t>()); 26810554Salexandru.dutu@amd.com break; 26910554Salexandru.dutu@amd.com case sizeof(uint16_t): 27012458Sgabeblack@google.com pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]); 27110554Salexandru.dutu@amd.com DPRINTF(PCIDEV, 27210554Salexandru.dutu@amd.com "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 27310554Salexandru.dutu@amd.com params()->pci_dev, params()->pci_func, offset, 27410554Salexandru.dutu@amd.com (uint32_t)pkt->get<uint16_t>()); 27510554Salexandru.dutu@amd.com break; 27610554Salexandru.dutu@amd.com case sizeof(uint32_t): 27710554Salexandru.dutu@amd.com pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]); 27810554Salexandru.dutu@amd.com DPRINTF(PCIDEV, 27910554Salexandru.dutu@amd.com "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 28010554Salexandru.dutu@amd.com params()->pci_dev, params()->pci_func, offset, 28110554Salexandru.dutu@amd.com (uint32_t)pkt->get<uint32_t>()); 28210554Salexandru.dutu@amd.com break; 28310554Salexandru.dutu@amd.com default: 28412458Sgabeblack@google.com panic("invalid access size(?) for PCI configspace!\n"); 28510554Salexandru.dutu@amd.com } 28610554Salexandru.dutu@amd.com pkt->makeAtomicResponse(); 28710554Salexandru.dutu@amd.com return configDelay; 28810554Salexandru.dutu@amd.com 28910554Salexandru.dutu@amd.com} 29010554Salexandru.dutu@amd.com 29110554Salexandru.dutu@amd.comAddrRangeList 29210554Salexandru.dutu@amd.comPciDevice::getAddrRanges() const 29310554Salexandru.dutu@amd.com{ 29410554Salexandru.dutu@amd.com AddrRangeList ranges; 29510554Salexandru.dutu@amd.com int x = 0; 29610554Salexandru.dutu@amd.com for (x = 0; x < 6; x++) 29710554Salexandru.dutu@amd.com if (BARAddrs[x] != 0) 29812458Sgabeblack@google.com ranges.push_back(RangeSize(BARAddrs[x],BARSize[x])); 29910554Salexandru.dutu@amd.com return ranges; 30010554Salexandru.dutu@amd.com} 30110554Salexandru.dutu@amd.com 30210554Salexandru.dutu@amd.comTick 30310554Salexandru.dutu@amd.comPciDevice::writeConfig(PacketPtr pkt) 30410554Salexandru.dutu@amd.com{ 30510554Salexandru.dutu@amd.com int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 30610554Salexandru.dutu@amd.com if (offset >= PCI_DEVICE_SPECIFIC) 30710554Salexandru.dutu@amd.com panic("Device specific PCI config space not implemented!\n"); 30810554Salexandru.dutu@amd.com 30910554Salexandru.dutu@amd.com switch (pkt->getSize()) { 31010554Salexandru.dutu@amd.com case sizeof(uint8_t): 31110554Salexandru.dutu@amd.com switch (offset) { 31210554Salexandru.dutu@amd.com case PCI0_INTERRUPT_LINE: 31310554Salexandru.dutu@amd.com config.interruptLine = pkt->get<uint8_t>(); 31410554Salexandru.dutu@amd.com break; 31510554Salexandru.dutu@amd.com case PCI_CACHE_LINE_SIZE: 31610554Salexandru.dutu@amd.com config.cacheLineSize = pkt->get<uint8_t>(); 31710554Salexandru.dutu@amd.com break; 31810554Salexandru.dutu@amd.com case PCI_LATENCY_TIMER: 31910554Salexandru.dutu@amd.com config.latencyTimer = pkt->get<uint8_t>(); 32012588Sgabeblack@google.com break; 32112588Sgabeblack@google.com /* Do nothing for these read-only registers */ 32210554Salexandru.dutu@amd.com case PCI0_INTERRUPT_PIN: 32310554Salexandru.dutu@amd.com case PCI0_MINIMUM_GRANT: 32410590Sgabeblack@google.com case PCI0_MAXIMUM_LATENCY: 32510554Salexandru.dutu@amd.com case PCI_CLASS_CODE: 32610554Salexandru.dutu@amd.com case PCI_REVISION_ID: 32710554Salexandru.dutu@amd.com break; 32810554Salexandru.dutu@amd.com default: 32910554Salexandru.dutu@amd.com panic("writing to a read only register"); 33010554Salexandru.dutu@amd.com } 33112458Sgabeblack@google.com DPRINTF(PCIDEV, 33210554Salexandru.dutu@amd.com "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 33310554Salexandru.dutu@amd.com params()->pci_dev, params()->pci_func, offset, 33410554Salexandru.dutu@amd.com (uint32_t)pkt->get<uint8_t>()); 33510554Salexandru.dutu@amd.com break; 33610554Salexandru.dutu@amd.com case sizeof(uint16_t): 33710554Salexandru.dutu@amd.com switch (offset) { 33810554Salexandru.dutu@amd.com case PCI_COMMAND: 33912588Sgabeblack@google.com config.command = pkt->get<uint8_t>(); 34012588Sgabeblack@google.com break; 34110554Salexandru.dutu@amd.com case PCI_STATUS: 34210554Salexandru.dutu@amd.com config.status = pkt->get<uint8_t>(); 34310554Salexandru.dutu@amd.com break; 34410554Salexandru.dutu@amd.com case PCI_CACHE_LINE_SIZE: 34510554Salexandru.dutu@amd.com config.cacheLineSize = pkt->get<uint8_t>(); 34610554Salexandru.dutu@amd.com break; 34710554Salexandru.dutu@amd.com default: 34810554Salexandru.dutu@amd.com panic("writing to a read only register"); 34910554Salexandru.dutu@amd.com } 35010554Salexandru.dutu@amd.com DPRINTF(PCIDEV, 35110554Salexandru.dutu@amd.com "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 35210554Salexandru.dutu@amd.com params()->pci_dev, params()->pci_func, offset, 35310590Sgabeblack@google.com (uint32_t)pkt->get<uint16_t>()); 35410590Sgabeblack@google.com break; 35510590Sgabeblack@google.com case sizeof(uint32_t): 35610590Sgabeblack@google.com switch (offset) { 35710590Sgabeblack@google.com case PCI0_BASE_ADDR0: 35810590Sgabeblack@google.com case PCI0_BASE_ADDR1: 35910554Salexandru.dutu@amd.com case PCI0_BASE_ADDR2: 36010554Salexandru.dutu@amd.com case PCI0_BASE_ADDR3: 36110554Salexandru.dutu@amd.com case PCI0_BASE_ADDR4: 36210554Salexandru.dutu@amd.com case PCI0_BASE_ADDR5: 36310554Salexandru.dutu@amd.com { 36410554Salexandru.dutu@amd.com int barnum = BAR_NUMBER(offset); 36510554Salexandru.dutu@amd.com 36610554Salexandru.dutu@amd.com if (!legacyIO[barnum]) { 36710554Salexandru.dutu@amd.com // convert BAR values to host endianness 36810554Salexandru.dutu@amd.com uint32_t he_old_bar = letoh(config.baseAddr[barnum]); 36910554Salexandru.dutu@amd.com uint32_t he_new_bar = letoh(pkt->get<uint32_t>()); 37010590Sgabeblack@google.com 37110590Sgabeblack@google.com uint32_t bar_mask = 37210590Sgabeblack@google.com BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK; 37310590Sgabeblack@google.com 37410590Sgabeblack@google.com // Writing 0xffffffff to a BAR tells the card to set the 37510554Salexandru.dutu@amd.com // value of the bar to a bitmask indicating the size of 37610554Salexandru.dutu@amd.com // memory it needs 37710554Salexandru.dutu@amd.com if (he_new_bar == 0xffffffff) { 37810554Salexandru.dutu@amd.com he_new_bar = ~(BARSize[barnum] - 1); 37910554Salexandru.dutu@amd.com } else { 38010554Salexandru.dutu@amd.com // does it mean something special to write 0 to a BAR? 38110554Salexandru.dutu@amd.com he_new_bar &= ~bar_mask; 38210554Salexandru.dutu@amd.com if (he_new_bar) { 38310554Salexandru.dutu@amd.com BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ? 38410554Salexandru.dutu@amd.com platform->calcPciIOAddr(he_new_bar) : 38510554Salexandru.dutu@amd.com platform->calcPciMemAddr(he_new_bar); 38610554Salexandru.dutu@amd.com pioPort.sendRangeChange(); 38710554Salexandru.dutu@amd.com } 38810554Salexandru.dutu@amd.com } 38910554Salexandru.dutu@amd.com config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) | 39010554Salexandru.dutu@amd.com (he_old_bar & bar_mask)); 39110554Salexandru.dutu@amd.com } 39210554Salexandru.dutu@amd.com } 39310554Salexandru.dutu@amd.com break; 39410554Salexandru.dutu@amd.com 39510554Salexandru.dutu@amd.com case PCI0_ROM_BASE_ADDR: 39610554Salexandru.dutu@amd.com if (letoh(pkt->get<uint32_t>()) == 0xfffffffe) 39710554Salexandru.dutu@amd.com config.expansionROM = htole((uint32_t)0xffffffff); 39810554Salexandru.dutu@amd.com else 39910554Salexandru.dutu@amd.com config.expansionROM = pkt->get<uint32_t>(); 40010554Salexandru.dutu@amd.com break; 40110554Salexandru.dutu@amd.com 40210554Salexandru.dutu@amd.com case PCI_COMMAND: 40310554Salexandru.dutu@amd.com // This could also clear some of the error bits in the Status 40410554Salexandru.dutu@amd.com // register. However they should never get set, so lets ignore 40510554Salexandru.dutu@amd.com // it for now 40610554Salexandru.dutu@amd.com config.command = pkt->get<uint32_t>(); 40710554Salexandru.dutu@amd.com break; 40810554Salexandru.dutu@amd.com 40910554Salexandru.dutu@amd.com default: 41010554Salexandru.dutu@amd.com DPRINTF(PCIDEV, "Writing to a read only register"); 41110554Salexandru.dutu@amd.com } 41210554Salexandru.dutu@amd.com DPRINTF(PCIDEV, 41312458Sgabeblack@google.com "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 41410554Salexandru.dutu@amd.com params()->pci_dev, params()->pci_func, offset, 41510554Salexandru.dutu@amd.com (uint32_t)pkt->get<uint32_t>()); 41610554Salexandru.dutu@amd.com break; 41710554Salexandru.dutu@amd.com default: 41810554Salexandru.dutu@amd.com panic("invalid access size(?) for PCI configspace!\n"); 41910554Salexandru.dutu@amd.com } 42010554Salexandru.dutu@amd.com pkt->makeAtomicResponse(); 42110554Salexandru.dutu@amd.com return configDelay; 42210554Salexandru.dutu@amd.com} 42310554Salexandru.dutu@amd.com 42410554Salexandru.dutu@amd.comvoid 42510554Salexandru.dutu@amd.comPciDevice::serialize(std::ostream &os) 42610554Salexandru.dutu@amd.com{ 42710554Salexandru.dutu@amd.com SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 42810554Salexandru.dutu@amd.com SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 42910554Salexandru.dutu@amd.com SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); 43010554Salexandru.dutu@amd.com 43110554Salexandru.dutu@amd.com // serialize the capability list registers 43210554Salexandru.dutu@amd.com paramOut(os, csprintf("pmcap.pid"), uint16_t(pmcap.pid)); 43310554Salexandru.dutu@amd.com paramOut(os, csprintf("pmcap.pc"), uint16_t(pmcap.pc)); 43410554Salexandru.dutu@amd.com paramOut(os, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs)); 43510554Salexandru.dutu@amd.com 43610554Salexandru.dutu@amd.com paramOut(os, csprintf("msicap.mid"), uint16_t(msicap.mid)); 43710554Salexandru.dutu@amd.com paramOut(os, csprintf("msicap.mc"), uint16_t(msicap.mc)); 43810554Salexandru.dutu@amd.com paramOut(os, csprintf("msicap.ma"), uint32_t(msicap.ma)); 43910554Salexandru.dutu@amd.com SERIALIZE_SCALAR(msicap.mua); 44010590Sgabeblack@google.com paramOut(os, csprintf("msicap.md"), uint16_t(msicap.md)); 44110590Sgabeblack@google.com SERIALIZE_SCALAR(msicap.mmask); 44210554Salexandru.dutu@amd.com SERIALIZE_SCALAR(msicap.mpend); 44310590Sgabeblack@google.com 44410590Sgabeblack@google.com paramOut(os, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid)); 44510554Salexandru.dutu@amd.com paramOut(os, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc)); 44610554Salexandru.dutu@amd.com paramOut(os, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab)); 44710554Salexandru.dutu@amd.com paramOut(os, csprintf("msixcap.mpba"), uint32_t(msixcap.mpba)); 44810554Salexandru.dutu@amd.com 44910590Sgabeblack@google.com // Only serialize if we have a non-zero base address 45010554Salexandru.dutu@amd.com if (MSIXCAP_BASE != 0x0) { 45110590Sgabeblack@google.com int msix_array_size = msixcap.mxc.ts + 1; 45210554Salexandru.dutu@amd.com int pba_array_size = msix_array_size/MSIXVECS_PER_PBA; 4535140Sgblack@eecs.umich.edu if ((msix_array_size % MSIXVECS_PER_PBA) > 0) { 4545140Sgblack@eecs.umich.edu pba_array_size++; 45510590Sgabeblack@google.com } 4565140Sgblack@eecs.umich.edu 45710554Salexandru.dutu@amd.com SERIALIZE_SCALAR(msix_array_size); 45810554Salexandru.dutu@amd.com SERIALIZE_SCALAR(pba_array_size); 45910554Salexandru.dutu@amd.com 46010554Salexandru.dutu@amd.com for (int i = 0; i < msix_array_size; i++) { 46110554Salexandru.dutu@amd.com paramOut(os, csprintf("msix_table[%d].addr_lo", i), 46210554Salexandru.dutu@amd.com msix_table[i].fields.addr_lo); 46310554Salexandru.dutu@amd.com paramOut(os, csprintf("msix_table[%d].addr_hi", i), 46410554Salexandru.dutu@amd.com msix_table[i].fields.addr_hi); 46510554Salexandru.dutu@amd.com paramOut(os, csprintf("msix_table[%d].msg_data", i), 46610554Salexandru.dutu@amd.com msix_table[i].fields.msg_data); 46710554Salexandru.dutu@amd.com paramOut(os, csprintf("msix_table[%d].vec_ctrl", i), 46810554Salexandru.dutu@amd.com msix_table[i].fields.vec_ctrl); 46910554Salexandru.dutu@amd.com } 47010554Salexandru.dutu@amd.com for (int i = 0; i < pba_array_size; i++) { 47110554Salexandru.dutu@amd.com paramOut(os, csprintf("msix_pba[%d].bits", i), 47210554Salexandru.dutu@amd.com msix_pba[i].bits); 47310554Salexandru.dutu@amd.com } 47410554Salexandru.dutu@amd.com } 47510554Salexandru.dutu@amd.com 47610554Salexandru.dutu@amd.com paramOut(os, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid)); 47710554Salexandru.dutu@amd.com paramOut(os, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap)); 47810554Salexandru.dutu@amd.com paramOut(os, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap)); 47910554Salexandru.dutu@amd.com paramOut(os, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc)); 48010554Salexandru.dutu@amd.com paramOut(os, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds)); 48110554Salexandru.dutu@amd.com paramOut(os, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap)); 48210554Salexandru.dutu@amd.com paramOut(os, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc)); 48310554Salexandru.dutu@amd.com paramOut(os, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls)); 48410554Salexandru.dutu@amd.com paramOut(os, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2)); 48510554Salexandru.dutu@amd.com paramOut(os, csprintf("pxcap.pxdc2"), uint32_t(pxcap.pxdc2)); 4865140Sgblack@eecs.umich.edu} 48710554Salexandru.dutu@amd.com 48810554Salexandru.dutu@amd.comvoid 48910590Sgabeblack@google.comPciDevice::unserialize(Checkpoint *cp, const std::string §ion) 49010590Sgabeblack@google.com{ 49110554Salexandru.dutu@amd.com UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 49210554Salexandru.dutu@amd.com UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 49310554Salexandru.dutu@amd.com UNSERIALIZE_ARRAY(config.data, 49410554Salexandru.dutu@amd.com sizeof(config.data) / sizeof(config.data[0])); 49510554Salexandru.dutu@amd.com 49610554Salexandru.dutu@amd.com // unserialize the capability list registers 49712458Sgabeblack@google.com uint16_t tmp16; 4986140Sgblack@eecs.umich.edu uint32_t tmp32; 49910554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("pmcap.pid"), tmp16); 50010554Salexandru.dutu@amd.com pmcap.pid = tmp16; 50110590Sgabeblack@google.com paramIn(cp, section, csprintf("pmcap.pc"), tmp16); 50210590Sgabeblack@google.com pmcap.pc = tmp16; 50310590Sgabeblack@google.com paramIn(cp, section, csprintf("pmcap.pmcs"), tmp16); 50410554Salexandru.dutu@amd.com pmcap.pmcs = tmp16; 50510554Salexandru.dutu@amd.com 50610554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("msicap.mid"), tmp16); 50710554Salexandru.dutu@amd.com msicap.mid = tmp16; 5086609Sgblack@eecs.umich.edu paramIn(cp, section, csprintf("msicap.mc"), tmp16); 50910554Salexandru.dutu@amd.com msicap.mc = tmp16; 51010590Sgabeblack@google.com paramIn(cp, section, csprintf("msicap.ma"), tmp32); 51110554Salexandru.dutu@amd.com msicap.ma = tmp32; 51210554Salexandru.dutu@amd.com UNSERIALIZE_SCALAR(msicap.mua); 51310554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("msicap.md"), tmp16);; 51410554Salexandru.dutu@amd.com msicap.md = tmp16; 51510554Salexandru.dutu@amd.com UNSERIALIZE_SCALAR(msicap.mmask); 51610554Salexandru.dutu@amd.com UNSERIALIZE_SCALAR(msicap.mpend); 51712458Sgabeblack@google.com 51810554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("msixcap.mxid"), tmp16); 51910554Salexandru.dutu@amd.com msixcap.mxid = tmp16; 52010590Sgabeblack@google.com paramIn(cp, section, csprintf("msixcap.mxc"), tmp16); 52110554Salexandru.dutu@amd.com msixcap.mxc = tmp16; 52210590Sgabeblack@google.com paramIn(cp, section, csprintf("msixcap.mtab"), tmp32); 52310590Sgabeblack@google.com msixcap.mtab = tmp32; 52410590Sgabeblack@google.com paramIn(cp, section, csprintf("msixcap.mpba"), tmp32); 52510590Sgabeblack@google.com msixcap.mpba = tmp32; 52610590Sgabeblack@google.com 52710554Salexandru.dutu@amd.com // Only allocate if MSIXCAP_BASE is not 0x0 52810554Salexandru.dutu@amd.com if (MSIXCAP_BASE != 0x0) { 52910554Salexandru.dutu@amd.com int msix_array_size; 53010554Salexandru.dutu@amd.com int pba_array_size; 53110554Salexandru.dutu@amd.com 53210554Salexandru.dutu@amd.com UNSERIALIZE_SCALAR(msix_array_size); 53310554Salexandru.dutu@amd.com UNSERIALIZE_SCALAR(pba_array_size); 53410590Sgabeblack@google.com 53510590Sgabeblack@google.com MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}}; 53610590Sgabeblack@google.com msix_table.resize(msix_array_size, tmp1); 53710590Sgabeblack@google.com 53810590Sgabeblack@google.com MSIXPbaEntry tmp2 = {0}; 53910590Sgabeblack@google.com msix_pba.resize(pba_array_size, tmp2); 54010590Sgabeblack@google.com 54110554Salexandru.dutu@amd.com for (int i = 0; i < msix_array_size; i++) { 54210554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("msix_table[%d].addr_lo", i), 54312458Sgabeblack@google.com msix_table[i].fields.addr_lo); 54410554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("msix_table[%d].addr_hi", i), 54510554Salexandru.dutu@amd.com msix_table[i].fields.addr_hi); 54612460Sgabeblack@google.com paramIn(cp, section, csprintf("msix_table[%d].msg_data", i), 54712460Sgabeblack@google.com msix_table[i].fields.msg_data); 54810554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("msix_table[%d].vec_ctrl", i), 54912460Sgabeblack@google.com msix_table[i].fields.vec_ctrl); 55010554Salexandru.dutu@amd.com } 55112460Sgabeblack@google.com for (int i = 0; i < pba_array_size; i++) { 55210554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("msix_pba[%d].bits", i), 55312460Sgabeblack@google.com msix_pba[i].bits); 55410554Salexandru.dutu@amd.com } 55512460Sgabeblack@google.com } 55610554Salexandru.dutu@amd.com 55712460Sgabeblack@google.com paramIn(cp, section, csprintf("pxcap.pxid"), tmp16); 55810554Salexandru.dutu@amd.com pxcap.pxid = tmp16; 55912460Sgabeblack@google.com paramIn(cp, section, csprintf("pxcap.pxcap"), tmp16); 56012460Sgabeblack@google.com pxcap.pxcap = tmp16; 56110554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("pxcap.pxdcap"), tmp32); 56210554Salexandru.dutu@amd.com pxcap.pxdcap = tmp32; 56310554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("pxcap.pxdc"), tmp16); 56410554Salexandru.dutu@amd.com pxcap.pxdc = tmp16; 56510554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("pxcap.pxds"), tmp16); 56610554Salexandru.dutu@amd.com pxcap.pxds = tmp16; 56710554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("pxcap.pxlcap"), tmp32); 56810554Salexandru.dutu@amd.com pxcap.pxlcap = tmp32; 56910554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("pxcap.pxlc"), tmp16); 57010554Salexandru.dutu@amd.com pxcap.pxlc = tmp16; 57110554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("pxcap.pxls"), tmp16); 57210554Salexandru.dutu@amd.com pxcap.pxls = tmp16; 57310554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("pxcap.pxdcap2"), tmp32); 57410554Salexandru.dutu@amd.com pxcap.pxdcap2 = tmp32; 57510554Salexandru.dutu@amd.com paramIn(cp, section, csprintf("pxcap.pxdc2"), tmp32); 57610554Salexandru.dutu@amd.com pxcap.pxdc2 = tmp32; 57710554Salexandru.dutu@amd.com pioPort.sendRangeChange(); 57810554Salexandru.dutu@amd.com} 57911906SBrandon.Potter@amd.com 58011321Ssteve.reinhardt@amd.com