device.cc revision 11260
12207SN/A/* 22207SN/A * Copyright (c) 2013, 2015 ARM Limited 32207SN/A * All rights reserved 42207SN/A * 52207SN/A * The license below extends only to copyright in the software and shall 62207SN/A * not be construed as granting a license to any other intellectual 72207SN/A * property including but not limited to intellectual property relating 82207SN/A * to a hardware implementation of the functionality of the software 92207SN/A * licensed hereunder. You may use the software subject to the license 102207SN/A * terms below provided that you ensure that this notice is replicated 112207SN/A * unmodified and in its entirety in all distributions of the software, 122207SN/A * modified or unmodified, in source code or in binary form. 132207SN/A * 142207SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 152207SN/A * All rights reserved. 162207SN/A * 172207SN/A * Redistribution and use in source and binary forms, with or without 182207SN/A * modification, are permitted provided that the following conditions are 192207SN/A * met: redistributions of source code must retain the above copyright 202207SN/A * notice, this list of conditions and the following disclaimer; 212207SN/A * redistributions in binary form must reproduce the above copyright 222207SN/A * notice, this list of conditions and the following disclaimer in the 232207SN/A * documentation and/or other materials provided with the distribution; 242207SN/A * neither the name of the copyright holders nor the names of its 252207SN/A * contributors may be used to endorse or promote products derived from 262207SN/A * this software without specific prior written permission. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292665Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302207SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312207SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3211793Sbrandon.potter@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3311793Sbrandon.potter@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 343589Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 354111Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362474SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 376335Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 383760Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 398229Snate@binkert.org * 402454SN/A * Authors: Ali Saidi 412454SN/A * Andrew Schultz 422680Sktlim@umich.edu * Miguel Serrano 438232Snate@binkert.org */ 442561SN/A 454434Ssaidi@eecs.umich.edu/* @file 462474SN/A * A single PCI device configuration space entry. 472207SN/A */ 482458SN/A 492474SN/A#include "dev/pci/device.hh" 502458SN/A 515958Sgblack@eecs.umich.edu#include <list> 525958Sgblack@eecs.umich.edu#include <string> 532207SN/A#include <vector> 545154Sgblack@eecs.umich.edu 555285Sgblack@eecs.umich.edu#include "base/inifile.hh" 565285Sgblack@eecs.umich.edu#include "base/intmath.hh" 572474SN/A#include "base/misc.hh" 582474SN/A#include "base/str.hh" 592474SN/A#include "base/trace.hh" 602474SN/A#include "debug/PciDevice.hh" 6110318Sandreas.hansson@arm.com#include "mem/packet.hh" 622474SN/A#include "mem/packet_access.hh" 632474SN/A#include "sim/byteswap.hh" 642474SN/A#include "sim/core.hh" 653415Sgblack@eecs.umich.edu 667741Sgblack@eecs.umich.edu 673415Sgblack@eecs.umich.eduPciDevice::PciDevice(const PciDeviceParams *p) 683415Sgblack@eecs.umich.edu : DmaDevice(p), 692474SN/A _busAddr(p->pci_bus, p->pci_dev, p->pci_func), 702474SN/A PMCAP_BASE(p->PMCAPBaseOffset), 717741Sgblack@eecs.umich.edu PMCAP_ID_OFFSET(p->PMCAPBaseOffset+PMCAP_ID), 727741Sgblack@eecs.umich.edu PMCAP_PC_OFFSET(p->PMCAPBaseOffset+PMCAP_PC), 734111Sgblack@eecs.umich.edu PMCAP_PMCS_OFFSET(p->PMCAPBaseOffset+PMCAP_PMCS), 747720Sgblack@eecs.umich.edu MSICAP_BASE(p->MSICAPBaseOffset), 757741Sgblack@eecs.umich.edu MSIXCAP_BASE(p->MSIXCAPBaseOffset), 767741Sgblack@eecs.umich.edu MSIXCAP_ID_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_ID), 777720Sgblack@eecs.umich.edu MSIXCAP_MXC_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MXC), 785128Sgblack@eecs.umich.edu MSIXCAP_MTAB_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MTAB), 797741Sgblack@eecs.umich.edu MSIXCAP_MPBA_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MPBA), 807720Sgblack@eecs.umich.edu PXCAP_BASE(p->PXCAPBaseOffset), 815128Sgblack@eecs.umich.edu 827741Sgblack@eecs.umich.edu hostInterface(p->host->registerDevice(this, _busAddr, 835128Sgblack@eecs.umich.edu (PciIntPin)p->InterruptPin)), 845128Sgblack@eecs.umich.edu pioDelay(p->pio_latency), 857741Sgblack@eecs.umich.edu configDelay(p->config_latency) 865128Sgblack@eecs.umich.edu{ 877720Sgblack@eecs.umich.edu fatal_if(p->InterruptPin >= 5, 885128Sgblack@eecs.umich.edu "Invalid PCI interrupt '%i' specified.", p->InterruptPin); 897741Sgblack@eecs.umich.edu 907720Sgblack@eecs.umich.edu config.vendor = htole(p->VendorID); 915128Sgblack@eecs.umich.edu config.device = htole(p->DeviceID); 927741Sgblack@eecs.umich.edu config.command = htole(p->Command); 935128Sgblack@eecs.umich.edu config.status = htole(p->Status); 947720Sgblack@eecs.umich.edu config.revision = htole(p->Revision); 955128Sgblack@eecs.umich.edu config.progIF = htole(p->ProgIF); 967741Sgblack@eecs.umich.edu config.subClassCode = htole(p->SubClassCode); 977720Sgblack@eecs.umich.edu config.classCode = htole(p->ClassCode); 985128Sgblack@eecs.umich.edu config.cacheLineSize = htole(p->CacheLineSize); 997741Sgblack@eecs.umich.edu config.latencyTimer = htole(p->LatencyTimer); 1005128Sgblack@eecs.umich.edu config.headerType = htole(p->HeaderType); 1017720Sgblack@eecs.umich.edu config.bist = htole(p->BIST); 1025128Sgblack@eecs.umich.edu 1037741Sgblack@eecs.umich.edu config.baseAddr[0] = htole(p->BAR0); 1045128Sgblack@eecs.umich.edu config.baseAddr[1] = htole(p->BAR1); 1057720Sgblack@eecs.umich.edu config.baseAddr[2] = htole(p->BAR2); 1064111Sgblack@eecs.umich.edu config.baseAddr[3] = htole(p->BAR3); 1074111Sgblack@eecs.umich.edu config.baseAddr[4] = htole(p->BAR4); 1084111Sgblack@eecs.umich.edu config.baseAddr[5] = htole(p->BAR5); 1094111Sgblack@eecs.umich.edu config.cardbusCIS = htole(p->CardbusCIS); 1104111Sgblack@eecs.umich.edu config.subsystemVendorID = htole(p->SubsystemVendorID); 1114111Sgblack@eecs.umich.edu config.subsystemID = htole(p->SubsystemID); 1122474SN/A config.expansionROM = htole(p->ExpansionROM); 1137532Ssteve.reinhardt@amd.com config.capabilityPtr = htole(p->CapabilityPtr); 1144111Sgblack@eecs.umich.edu // Zero out the 7 bytes of reserved space in the PCI Config space register. 1157532Ssteve.reinhardt@amd.com bzero(config.reserved, 7*sizeof(uint8_t)); 1164111Sgblack@eecs.umich.edu config.interruptLine = htole(p->InterruptLine); 1175713Shsul@eecs.umich.edu config.interruptPin = htole(p->InterruptPin); 1187741Sgblack@eecs.umich.edu config.minimumGrant = htole(p->MinimumGrant); 1194111Sgblack@eecs.umich.edu config.maximumLatency = htole(p->MaximumLatency); 1207741Sgblack@eecs.umich.edu 1215713Shsul@eecs.umich.edu // Initialize the capability lists 1222646Ssaidi@eecs.umich.edu // These structs are bitunions, meaning the data is stored in host 1235713Shsul@eecs.umich.edu // endianess and must be converted to Little Endian when accessed 1244997Sgblack@eecs.umich.edu // by the guest 1252561SN/A // PMCAP 1262561SN/A pmcap.pid = (uint16_t)p->PMCAPCapId; // pid.cid 1272561SN/A pmcap.pid |= (uint16_t)p->PMCAPNextCapability << 8; //pid.next 1282561SN/A pmcap.pc = p->PMCAPCapabilities; 1297741Sgblack@eecs.umich.edu pmcap.pmcs = p->PMCAPCtrlStatus; 1307741Sgblack@eecs.umich.edu 1315713Shsul@eecs.umich.edu // MSICAP 1327741Sgblack@eecs.umich.edu msicap.mid = (uint16_t)p->MSICAPCapId; //mid.cid 1337741Sgblack@eecs.umich.edu msicap.mid |= (uint16_t)p->MSICAPNextCapability << 8; //mid.next 1345713Shsul@eecs.umich.edu msicap.mc = p->MSICAPMsgCtrl; 1357741Sgblack@eecs.umich.edu msicap.ma = p->MSICAPMsgAddr; 1367741Sgblack@eecs.umich.edu msicap.mua = p->MSICAPMsgUpperAddr; 1375713Shsul@eecs.umich.edu msicap.md = p->MSICAPMsgData; 1387741Sgblack@eecs.umich.edu msicap.mmask = p->MSICAPMaskBits; 1397741Sgblack@eecs.umich.edu msicap.mpend = p->MSICAPPendingBits; 1405713Shsul@eecs.umich.edu 1417741Sgblack@eecs.umich.edu // MSIXCAP 1426337Sgblack@eecs.umich.edu msixcap.mxid = (uint16_t)p->MSIXCAPCapId; //mxid.cid 1437741Sgblack@eecs.umich.edu msixcap.mxid |= (uint16_t)p->MSIXCAPNextCapability << 8; //mxid.next 1447741Sgblack@eecs.umich.edu msixcap.mxc = p->MSIXMsgCtrl; 1455713Shsul@eecs.umich.edu msixcap.mtab = p->MSIXTableOffset; 1467741Sgblack@eecs.umich.edu msixcap.mpba = p->MSIXPbaOffset; 1475713Shsul@eecs.umich.edu 1487741Sgblack@eecs.umich.edu // allocate MSIX structures if MSIXCAP_BASE 1499375Sgblack@eecs.umich.edu // indicates the MSIXCAP is being used by having a 1504997Sgblack@eecs.umich.edu // non-zero base address. 1514997Sgblack@eecs.umich.edu // The MSIX tables are stored by the guest in 1524997Sgblack@eecs.umich.edu // little endian byte-order as according the 1534997Sgblack@eecs.umich.edu // PCIe specification. Make sure to take the proper 1547741Sgblack@eecs.umich.edu // actions when manipulating these tables on the host 1555713Shsul@eecs.umich.edu uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff; 1562474SN/A if (MSIXCAP_BASE != 0x0) { 1572474SN/A int msix_vecs = msixcap_mxc_ts + 1; 1585285Sgblack@eecs.umich.edu MSIXTable tmp1 = {{0UL,0UL,0UL,0UL}}; 1597532Ssteve.reinhardt@amd.com msix_table.resize(msix_vecs, tmp1); 1602585SN/A 1617532Ssteve.reinhardt@amd.com MSIXPbaEntry tmp2 = {0}; 1625285Sgblack@eecs.umich.edu int pba_size = msix_vecs / MSIXVECS_PER_PBA; 1635713Shsul@eecs.umich.edu if ((msix_vecs % MSIXVECS_PER_PBA) > 0) { 1647741Sgblack@eecs.umich.edu pba_size++; 1658829Sgblack@eecs.umich.edu } 1668829Sgblack@eecs.umich.edu msix_pba.resize(pba_size, tmp2); 1678829Sgblack@eecs.umich.edu } 1688829Sgblack@eecs.umich.edu MSIX_TABLE_OFFSET = msixcap.mtab & 0xfffffffc; 1695285Sgblack@eecs.umich.edu MSIX_TABLE_END = MSIX_TABLE_OFFSET + 17010318Sandreas.hansson@arm.com (msixcap_mxc_ts + 1) * sizeof(MSIXTable); 1714111Sgblack@eecs.umich.edu MSIX_PBA_OFFSET = msixcap.mpba & 0xfffffffc; 1723415Sgblack@eecs.umich.edu MSIX_PBA_END = MSIX_PBA_OFFSET + 1732561SN/A ((msixcap_mxc_ts + 1) / MSIXVECS_PER_PBA) 1747532Ssteve.reinhardt@amd.com * sizeof(MSIXPbaEntry); 1752561SN/A if (((msixcap_mxc_ts + 1) % MSIXVECS_PER_PBA) > 0) { 1767532Ssteve.reinhardt@amd.com MSIX_PBA_END += sizeof(MSIXPbaEntry); 1775285Sgblack@eecs.umich.edu } 1785713Shsul@eecs.umich.edu 1797741Sgblack@eecs.umich.edu // PXCAP 1808829Sgblack@eecs.umich.edu pxcap.pxid = (uint16_t)p->PXCAPCapId; //pxid.cid 1818829Sgblack@eecs.umich.edu pxcap.pxid |= (uint16_t)p->PXCAPNextCapability << 8; //pxid.next 1828829Sgblack@eecs.umich.edu pxcap.pxcap = p->PXCAPCapabilities; 1835285Sgblack@eecs.umich.edu pxcap.pxdcap = p->PXCAPDevCapabilities; 18410318Sandreas.hansson@arm.com pxcap.pxdc = p->PXCAPDevCtrl; 1855285Sgblack@eecs.umich.edu pxcap.pxds = p->PXCAPDevStatus; 1865285Sgblack@eecs.umich.edu pxcap.pxlcap = p->PXCAPLinkCap; 1875285Sgblack@eecs.umich.edu pxcap.pxlc = p->PXCAPLinkCtrl; 1885285Sgblack@eecs.umich.edu pxcap.pxls = p->PXCAPLinkStatus; 1895285Sgblack@eecs.umich.edu pxcap.pxdcap2 = p->PXCAPDevCap2; 1905285Sgblack@eecs.umich.edu pxcap.pxdc2 = p->PXCAPDevCtrl2; 1915285Sgblack@eecs.umich.edu 1925285Sgblack@eecs.umich.edu BARSize[0] = p->BAR0Size; 1935771Shsul@eecs.umich.edu BARSize[1] = p->BAR1Size; 1945285Sgblack@eecs.umich.edu BARSize[2] = p->BAR2Size; 1955285Sgblack@eecs.umich.edu BARSize[3] = p->BAR3Size; 1962474SN/A BARSize[4] = p->BAR4Size; 1973044Sgblack@eecs.umich.edu BARSize[5] = p->BAR5Size; 1987741Sgblack@eecs.umich.edu 1993044Sgblack@eecs.umich.edu legacyIO[0] = p->BAR0LegacyIO; 2003044Sgblack@eecs.umich.edu legacyIO[1] = p->BAR1LegacyIO; 2013044Sgblack@eecs.umich.edu legacyIO[2] = p->BAR2LegacyIO; 2023044Sgblack@eecs.umich.edu legacyIO[3] = p->BAR3LegacyIO; 2037741Sgblack@eecs.umich.edu legacyIO[4] = p->BAR4LegacyIO; 2047741Sgblack@eecs.umich.edu legacyIO[5] = p->BAR5LegacyIO; 2055286Sgblack@eecs.umich.edu 2062561SN/A for (int i = 0; i < 6; ++i) { 20711389Sbrandon.potter@amd.com if (legacyIO[i]) { 20811389Sbrandon.potter@amd.com BARAddrs[i] = p->LegacyIOBase + letoh(config.baseAddr[i]); 20911389Sbrandon.potter@amd.com config.baseAddr[i] = 0; 2102561SN/A } else { 2112561SN/A BARAddrs[i] = 0; 2122561SN/A uint32_t barsize = BARSize[i]; 2132585SN/A if (barsize != 0 && !isPowerOf2(barsize)) { 2142585SN/A fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]); 2152585SN/A } 2162585SN/A } 2172585SN/A } 2182585SN/A} 2192585SN/A 2207741Sgblack@eecs.umich.eduTick 2217741Sgblack@eecs.umich.eduPciDevice::readConfig(PacketPtr pkt) 2227741Sgblack@eecs.umich.edu{ 2232585SN/A int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 2242585SN/A 2252585SN/A /* Return 0 for accesses to unimplemented PCI configspace areas */ 2262585SN/A if (offset >= PCI_DEVICE_SPECIFIC && 2272585SN/A offset < PCI_CONFIG_SIZE) { 2282585SN/A warn_once("Device specific PCI config space " 2292585SN/A "not implemented for %s!\n", this->name()); 2302585SN/A switch (pkt->getSize()) { 2312585SN/A case sizeof(uint8_t): 2322585SN/A pkt->set<uint8_t>(0); 2332585SN/A break; 2347741Sgblack@eecs.umich.edu case sizeof(uint16_t): 2357741Sgblack@eecs.umich.edu pkt->set<uint16_t>(0); 2362976Sgblack@eecs.umich.edu break; 2377741Sgblack@eecs.umich.edu case sizeof(uint32_t): 2387741Sgblack@eecs.umich.edu pkt->set<uint32_t>(0); 2394793Sgblack@eecs.umich.edu break; 2407741Sgblack@eecs.umich.edu default: 24110318Sandreas.hansson@arm.com panic("invalid access size(?) for PCI configspace!\n"); 2427741Sgblack@eecs.umich.edu } 2437741Sgblack@eecs.umich.edu } else if (offset > PCI_CONFIG_SIZE) { 2444793Sgblack@eecs.umich.edu panic("Out-of-range access to PCI config space!\n"); 2452976Sgblack@eecs.umich.edu } 2462976Sgblack@eecs.umich.edu 2474793Sgblack@eecs.umich.edu switch (pkt->getSize()) { 2482976Sgblack@eecs.umich.edu case sizeof(uint8_t): 2494793Sgblack@eecs.umich.edu pkt->set<uint8_t>(config.data[offset]); 2502976Sgblack@eecs.umich.edu DPRINTF(PciDevice, 2514793Sgblack@eecs.umich.edu "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 25211389Sbrandon.potter@amd.com _busAddr.dev, _busAddr.func, offset, 25311389Sbrandon.potter@amd.com (uint32_t)pkt->get<uint8_t>()); 25411389Sbrandon.potter@amd.com break; 25511389Sbrandon.potter@amd.com case sizeof(uint16_t): 2567741Sgblack@eecs.umich.edu pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]); 2574793Sgblack@eecs.umich.edu DPRINTF(PciDevice, 2587741Sgblack@eecs.umich.edu "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 2594793Sgblack@eecs.umich.edu _busAddr.dev, _busAddr.func, offset, 2607741Sgblack@eecs.umich.edu (uint32_t)pkt->get<uint16_t>()); 2614793Sgblack@eecs.umich.edu break; 2624793Sgblack@eecs.umich.edu case sizeof(uint32_t): 2634793Sgblack@eecs.umich.edu pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]); 2644793Sgblack@eecs.umich.edu DPRINTF(PciDevice, 2657741Sgblack@eecs.umich.edu "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 2664793Sgblack@eecs.umich.edu _busAddr.dev, _busAddr.func, offset, 2672976Sgblack@eecs.umich.edu (uint32_t)pkt->get<uint32_t>()); 2682585SN/A break; 2697741Sgblack@eecs.umich.edu default: 2702561SN/A panic("invalid access size(?) for PCI configspace!\n"); 2714164Sgblack@eecs.umich.edu } 2725286Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 2734111Sgblack@eecs.umich.edu return configDelay; 2747741Sgblack@eecs.umich.edu 2757741Sgblack@eecs.umich.edu} 2764111Sgblack@eecs.umich.edu 2774111Sgblack@eecs.umich.eduAddrRangeList 2784111Sgblack@eecs.umich.eduPciDevice::getAddrRanges() const 2794111Sgblack@eecs.umich.edu{ 2804111Sgblack@eecs.umich.edu AddrRangeList ranges; 2814111Sgblack@eecs.umich.edu int x = 0; 2824111Sgblack@eecs.umich.edu for (x = 0; x < 6; x++) 2834111Sgblack@eecs.umich.edu if (BARAddrs[x] != 0) 2844111Sgblack@eecs.umich.edu ranges.push_back(RangeSize(BARAddrs[x],BARSize[x])); 2854111Sgblack@eecs.umich.edu return ranges; 2864111Sgblack@eecs.umich.edu} 2877741Sgblack@eecs.umich.edu 2885286Sgblack@eecs.umich.eduTick 2895286Sgblack@eecs.umich.eduPciDevice::writeConfig(PacketPtr pkt) 2905286Sgblack@eecs.umich.edu{ 2915286Sgblack@eecs.umich.edu int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 2925286Sgblack@eecs.umich.edu 2935286Sgblack@eecs.umich.edu /* No effect if we write to config space that is not implemented*/ 2944111Sgblack@eecs.umich.edu if (offset >= PCI_DEVICE_SPECIFIC && 2957741Sgblack@eecs.umich.edu offset < PCI_CONFIG_SIZE) { 2964111Sgblack@eecs.umich.edu warn_once("Device specific PCI config space " 2974111Sgblack@eecs.umich.edu "not implemented for %s!\n", this->name()); 2984111Sgblack@eecs.umich.edu switch (pkt->getSize()) { 2994111Sgblack@eecs.umich.edu case sizeof(uint8_t): 3004111Sgblack@eecs.umich.edu case sizeof(uint16_t): 3014111Sgblack@eecs.umich.edu case sizeof(uint32_t): 3024111Sgblack@eecs.umich.edu break; 3034111Sgblack@eecs.umich.edu default: 3047741Sgblack@eecs.umich.edu panic("invalid access size(?) for PCI configspace!\n"); 3055286Sgblack@eecs.umich.edu } 3064111Sgblack@eecs.umich.edu } else if (offset > PCI_CONFIG_SIZE) { 3074111Sgblack@eecs.umich.edu panic("Out-of-range access to PCI config space!\n"); 3084111Sgblack@eecs.umich.edu } 3094111Sgblack@eecs.umich.edu 3104111Sgblack@eecs.umich.edu switch (pkt->getSize()) { 3114111Sgblack@eecs.umich.edu case sizeof(uint8_t): 3127741Sgblack@eecs.umich.edu switch (offset) { 3137741Sgblack@eecs.umich.edu case PCI0_INTERRUPT_LINE: 3145286Sgblack@eecs.umich.edu config.interruptLine = pkt->get<uint8_t>(); 3155286Sgblack@eecs.umich.edu break; 3165286Sgblack@eecs.umich.edu case PCI_CACHE_LINE_SIZE: 3175286Sgblack@eecs.umich.edu config.cacheLineSize = pkt->get<uint8_t>(); 3185286Sgblack@eecs.umich.edu break; 3195286Sgblack@eecs.umich.edu case PCI_LATENCY_TIMER: 3205286Sgblack@eecs.umich.edu config.latencyTimer = pkt->get<uint8_t>(); 3215286Sgblack@eecs.umich.edu break; 3224111Sgblack@eecs.umich.edu /* Do nothing for these read-only registers */ 3235286Sgblack@eecs.umich.edu case PCI0_INTERRUPT_PIN: 3244111Sgblack@eecs.umich.edu case PCI0_MINIMUM_GRANT: 3254111Sgblack@eecs.umich.edu case PCI0_MAXIMUM_LATENCY: 3265285Sgblack@eecs.umich.edu case PCI_CLASS_CODE: 3278601Ssteve.reinhardt@amd.com case PCI_REVISION_ID: 3284111Sgblack@eecs.umich.edu break; 3294111Sgblack@eecs.umich.edu default: 3305286Sgblack@eecs.umich.edu panic("writing to a read only register"); 3315286Sgblack@eecs.umich.edu } 3325286Sgblack@eecs.umich.edu DPRINTF(PciDevice, 3335286Sgblack@eecs.umich.edu "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 3345286Sgblack@eecs.umich.edu _busAddr.dev, _busAddr.func, offset, 3355286Sgblack@eecs.umich.edu (uint32_t)pkt->get<uint8_t>()); 3365286Sgblack@eecs.umich.edu break; 3375286Sgblack@eecs.umich.edu case sizeof(uint16_t): 3385286Sgblack@eecs.umich.edu switch (offset) { 3395286Sgblack@eecs.umich.edu case PCI_COMMAND: 3405286Sgblack@eecs.umich.edu config.command = pkt->get<uint8_t>(); 3415286Sgblack@eecs.umich.edu break; 3424111Sgblack@eecs.umich.edu case PCI_STATUS: 3435941Sgblack@eecs.umich.edu config.status = pkt->get<uint8_t>(); 3445941Sgblack@eecs.umich.edu break; 3455941Sgblack@eecs.umich.edu case PCI_CACHE_LINE_SIZE: 3465941Sgblack@eecs.umich.edu config.cacheLineSize = pkt->get<uint8_t>(); 3475941Sgblack@eecs.umich.edu break; 3485941Sgblack@eecs.umich.edu default: 3495941Sgblack@eecs.umich.edu panic("writing to a read only register"); 3505941Sgblack@eecs.umich.edu } 3515941Sgblack@eecs.umich.edu DPRINTF(PciDevice, 3525941Sgblack@eecs.umich.edu "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 3535941Sgblack@eecs.umich.edu _busAddr.dev, _busAddr.func, offset, 3545941Sgblack@eecs.umich.edu (uint32_t)pkt->get<uint16_t>()); 3554111Sgblack@eecs.umich.edu break; 3565286Sgblack@eecs.umich.edu case sizeof(uint32_t): 3575286Sgblack@eecs.umich.edu switch (offset) { 3584111Sgblack@eecs.umich.edu case PCI0_BASE_ADDR0: 3594111Sgblack@eecs.umich.edu case PCI0_BASE_ADDR1: 3604111Sgblack@eecs.umich.edu case PCI0_BASE_ADDR2: 3615285Sgblack@eecs.umich.edu case PCI0_BASE_ADDR3: 3625567Snate@binkert.org case PCI0_BASE_ADDR4: 3634111Sgblack@eecs.umich.edu case PCI0_BASE_ADDR5: 3647741Sgblack@eecs.umich.edu { 3655286Sgblack@eecs.umich.edu int barnum = BAR_NUMBER(offset); 3668852Sandreas.hansson@arm.com 3675286Sgblack@eecs.umich.edu if (!legacyIO[barnum]) { 3684111Sgblack@eecs.umich.edu // convert BAR values to host endianness 3697741Sgblack@eecs.umich.edu uint32_t he_old_bar = letoh(config.baseAddr[barnum]); 3708852Sandreas.hansson@arm.com uint32_t he_new_bar = letoh(pkt->get<uint32_t>()); 3714111Sgblack@eecs.umich.edu 3727741Sgblack@eecs.umich.edu uint32_t bar_mask = 3737741Sgblack@eecs.umich.edu BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK; 3748852Sandreas.hansson@arm.com 3754111Sgblack@eecs.umich.edu // Writing 0xffffffff to a BAR tells the card to set the 3768852Sandreas.hansson@arm.com // value of the bar to a bitmask indicating the size of 3774111Sgblack@eecs.umich.edu // memory it needs 3784111Sgblack@eecs.umich.edu if (he_new_bar == 0xffffffff) { 3795285Sgblack@eecs.umich.edu he_new_bar = ~(BARSize[barnum] - 1); 3807741Sgblack@eecs.umich.edu } else { 3815285Sgblack@eecs.umich.edu // does it mean something special to write 0 to a BAR? 3828852Sandreas.hansson@arm.com he_new_bar &= ~bar_mask; 3835286Sgblack@eecs.umich.edu if (he_new_bar) { 3848852Sandreas.hansson@arm.com BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ? 3855286Sgblack@eecs.umich.edu hostInterface.pioAddr(he_new_bar) : 3864111Sgblack@eecs.umich.edu hostInterface.memAddr(he_new_bar); 3874117Sgblack@eecs.umich.edu pioPort.sendRangeChange(); 3884117Sgblack@eecs.umich.edu } 3894111Sgblack@eecs.umich.edu } 3908852Sandreas.hansson@arm.com config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) | 3914111Sgblack@eecs.umich.edu (he_old_bar & bar_mask)); 3927741Sgblack@eecs.umich.edu } 3937741Sgblack@eecs.umich.edu } 3947741Sgblack@eecs.umich.edu break; 3954111Sgblack@eecs.umich.edu 3965285Sgblack@eecs.umich.edu case PCI0_ROM_BASE_ADDR: 3974111Sgblack@eecs.umich.edu if (letoh(pkt->get<uint32_t>()) == 0xfffffffe) 3985713Shsul@eecs.umich.edu config.expansionROM = htole((uint32_t)0xffffffff); 3997741Sgblack@eecs.umich.edu else 4007741Sgblack@eecs.umich.edu config.expansionROM = pkt->get<uint32_t>(); 4017741Sgblack@eecs.umich.edu break; 4027741Sgblack@eecs.umich.edu 4035713Shsul@eecs.umich.edu case PCI_COMMAND: 4044111Sgblack@eecs.umich.edu // This could also clear some of the error bits in the Status 4055231Sgblack@eecs.umich.edu // register. However they should never get set, so lets ignore 4065231Sgblack@eecs.umich.edu // it for now 4075713Shsul@eecs.umich.edu config.command = pkt->get<uint32_t>(); 4085231Sgblack@eecs.umich.edu break; 40911389Sbrandon.potter@amd.com 4104111Sgblack@eecs.umich.edu default: 4117741Sgblack@eecs.umich.edu DPRINTF(PciDevice, "Writing to a read only register"); 4124111Sgblack@eecs.umich.edu } 4134111Sgblack@eecs.umich.edu DPRINTF(PciDevice, 4144111Sgblack@eecs.umich.edu "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 4154111Sgblack@eecs.umich.edu _busAddr.dev, _busAddr.func, offset, 4165128Sgblack@eecs.umich.edu (uint32_t)pkt->get<uint32_t>()); 4175285Sgblack@eecs.umich.edu break; 4185285Sgblack@eecs.umich.edu default: 4195285Sgblack@eecs.umich.edu panic("invalid access size(?) for PCI configspace!\n"); 4205285Sgblack@eecs.umich.edu } 4215285Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 4225285Sgblack@eecs.umich.edu return configDelay; 4238852Sandreas.hansson@arm.com} 4245285Sgblack@eecs.umich.edu 4258852Sandreas.hansson@arm.comvoid 4265285Sgblack@eecs.umich.eduPciDevice::serialize(CheckpointOut &cp) const 4275285Sgblack@eecs.umich.edu{ 4285285Sgblack@eecs.umich.edu SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 4295285Sgblack@eecs.umich.edu SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 4305285Sgblack@eecs.umich.edu SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); 4315285Sgblack@eecs.umich.edu 4325285Sgblack@eecs.umich.edu // serialize the capability list registers 4335285Sgblack@eecs.umich.edu paramOut(cp, csprintf("pmcap.pid"), uint16_t(pmcap.pid)); 4345285Sgblack@eecs.umich.edu paramOut(cp, csprintf("pmcap.pc"), uint16_t(pmcap.pc)); 4358852Sandreas.hansson@arm.com paramOut(cp, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs)); 4365285Sgblack@eecs.umich.edu 4378852Sandreas.hansson@arm.com paramOut(cp, csprintf("msicap.mid"), uint16_t(msicap.mid)); 4385285Sgblack@eecs.umich.edu paramOut(cp, csprintf("msicap.mc"), uint16_t(msicap.mc)); 4395285Sgblack@eecs.umich.edu paramOut(cp, csprintf("msicap.ma"), uint32_t(msicap.ma)); 4405285Sgblack@eecs.umich.edu SERIALIZE_SCALAR(msicap.mua); 4415128Sgblack@eecs.umich.edu paramOut(cp, csprintf("msicap.md"), uint16_t(msicap.md)); 4425128Sgblack@eecs.umich.edu SERIALIZE_SCALAR(msicap.mmask); 4435128Sgblack@eecs.umich.edu SERIALIZE_SCALAR(msicap.mpend); 4445128Sgblack@eecs.umich.edu 4455128Sgblack@eecs.umich.edu paramOut(cp, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid)); 4465128Sgblack@eecs.umich.edu paramOut(cp, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc)); 4475128Sgblack@eecs.umich.edu paramOut(cp, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab)); 4485128Sgblack@eecs.umich.edu paramOut(cp, csprintf("msixcap.mpba"), uint32_t(msixcap.mpba)); 4497741Sgblack@eecs.umich.edu 4505128Sgblack@eecs.umich.edu // Only serialize if we have a non-zero base address 4515128Sgblack@eecs.umich.edu if (MSIXCAP_BASE != 0x0) { 4525128Sgblack@eecs.umich.edu uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff; 4535128Sgblack@eecs.umich.edu int msix_array_size = msixcap_mxc_ts + 1; 4547741Sgblack@eecs.umich.edu int pba_array_size = msix_array_size/MSIXVECS_PER_PBA; 4555128Sgblack@eecs.umich.edu if ((msix_array_size % MSIXVECS_PER_PBA) > 0) { 4565128Sgblack@eecs.umich.edu pba_array_size++; 4575287Sgblack@eecs.umich.edu } 4585128Sgblack@eecs.umich.edu 4598852Sandreas.hansson@arm.com SERIALIZE_SCALAR(msix_array_size); 4605128Sgblack@eecs.umich.edu SERIALIZE_SCALAR(pba_array_size); 4615128Sgblack@eecs.umich.edu 4625128Sgblack@eecs.umich.edu for (int i = 0; i < msix_array_size; i++) { 4635128Sgblack@eecs.umich.edu paramOut(cp, csprintf("msix_table[%d].addr_lo", i), 4645128Sgblack@eecs.umich.edu msix_table[i].fields.addr_lo); 4655128Sgblack@eecs.umich.edu paramOut(cp, csprintf("msix_table[%d].addr_hi", i), 4665128Sgblack@eecs.umich.edu msix_table[i].fields.addr_hi); 4675128Sgblack@eecs.umich.edu paramOut(cp, csprintf("msix_table[%d].msg_data", i), 4685128Sgblack@eecs.umich.edu msix_table[i].fields.msg_data); 4695128Sgblack@eecs.umich.edu paramOut(cp, csprintf("msix_table[%d].vec_ctrl", i), 4705128Sgblack@eecs.umich.edu msix_table[i].fields.vec_ctrl); 4715128Sgblack@eecs.umich.edu } 4725128Sgblack@eecs.umich.edu for (int i = 0; i < pba_array_size; i++) { 4735128Sgblack@eecs.umich.edu paramOut(cp, csprintf("msix_pba[%d].bits", i), 4745128Sgblack@eecs.umich.edu msix_pba[i].bits); 4757741Sgblack@eecs.umich.edu } 4767741Sgblack@eecs.umich.edu } 4775128Sgblack@eecs.umich.edu 4785128Sgblack@eecs.umich.edu paramOut(cp, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid)); 4795128Sgblack@eecs.umich.edu paramOut(cp, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap)); 4805128Sgblack@eecs.umich.edu paramOut(cp, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap)); 4815128Sgblack@eecs.umich.edu paramOut(cp, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc)); 4825128Sgblack@eecs.umich.edu paramOut(cp, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds)); 4835128Sgblack@eecs.umich.edu paramOut(cp, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap)); 4847741Sgblack@eecs.umich.edu paramOut(cp, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc)); 4855128Sgblack@eecs.umich.edu paramOut(cp, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls)); 4865128Sgblack@eecs.umich.edu paramOut(cp, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2)); 4875128Sgblack@eecs.umich.edu paramOut(cp, csprintf("pxcap.pxdc2"), uint32_t(pxcap.pxdc2)); 4885128Sgblack@eecs.umich.edu} 4897741Sgblack@eecs.umich.edu 4905128Sgblack@eecs.umich.eduvoid 4915128Sgblack@eecs.umich.eduPciDevice::unserialize(CheckpointIn &cp) 4925128Sgblack@eecs.umich.edu{ 4935128Sgblack@eecs.umich.edu UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 4948852Sandreas.hansson@arm.com UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 4955128Sgblack@eecs.umich.edu UNSERIALIZE_ARRAY(config.data, 4965128Sgblack@eecs.umich.edu sizeof(config.data) / sizeof(config.data[0])); 4975128Sgblack@eecs.umich.edu 4985128Sgblack@eecs.umich.edu // unserialize the capability list registers 4995128Sgblack@eecs.umich.edu uint16_t tmp16; 5005128Sgblack@eecs.umich.edu uint32_t tmp32; 5015128Sgblack@eecs.umich.edu paramIn(cp, csprintf("pmcap.pid"), tmp16); 5025128Sgblack@eecs.umich.edu pmcap.pid = tmp16; 5035128Sgblack@eecs.umich.edu paramIn(cp, csprintf("pmcap.pc"), tmp16); 5045128Sgblack@eecs.umich.edu pmcap.pc = tmp16; 5055128Sgblack@eecs.umich.edu paramIn(cp, csprintf("pmcap.pmcs"), tmp16); 5065128Sgblack@eecs.umich.edu pmcap.pmcs = tmp16; 5075128Sgblack@eecs.umich.edu 5085128Sgblack@eecs.umich.edu paramIn(cp, csprintf("msicap.mid"), tmp16); 5095958Sgblack@eecs.umich.edu msicap.mid = tmp16; 5105958Sgblack@eecs.umich.edu paramIn(cp, csprintf("msicap.mc"), tmp16); 5116701Sgblack@eecs.umich.edu msicap.mc = tmp16; 5125958Sgblack@eecs.umich.edu paramIn(cp, csprintf("msicap.ma"), tmp32); 5135958Sgblack@eecs.umich.edu msicap.ma = tmp32; 5146701Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(msicap.mua); 5155958Sgblack@eecs.umich.edu paramIn(cp, csprintf("msicap.md"), tmp16);; 5165958Sgblack@eecs.umich.edu msicap.md = tmp16; 5175958Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(msicap.mmask); 5185958Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(msicap.mpend); 5195958Sgblack@eecs.umich.edu 5205958Sgblack@eecs.umich.edu paramIn(cp, csprintf("msixcap.mxid"), tmp16); 5215958Sgblack@eecs.umich.edu msixcap.mxid = tmp16; 5225958Sgblack@eecs.umich.edu paramIn(cp, csprintf("msixcap.mxc"), tmp16); 5235958Sgblack@eecs.umich.edu msixcap.mxc = tmp16; 5245958Sgblack@eecs.umich.edu paramIn(cp, csprintf("msixcap.mtab"), tmp32); 5256701Sgblack@eecs.umich.edu msixcap.mtab = tmp32; 5265958Sgblack@eecs.umich.edu paramIn(cp, csprintf("msixcap.mpba"), tmp32); 5275958Sgblack@eecs.umich.edu msixcap.mpba = tmp32; 5286701Sgblack@eecs.umich.edu 5295958Sgblack@eecs.umich.edu // Only allocate if MSIXCAP_BASE is not 0x0 5305958Sgblack@eecs.umich.edu if (MSIXCAP_BASE != 0x0) { 5315958Sgblack@eecs.umich.edu int msix_array_size; 5325958Sgblack@eecs.umich.edu int pba_array_size; 5335958Sgblack@eecs.umich.edu 5345958Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(msix_array_size); 5355958Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(pba_array_size); 5365958Sgblack@eecs.umich.edu 5375958Sgblack@eecs.umich.edu MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}}; 5385958Sgblack@eecs.umich.edu msix_table.resize(msix_array_size, tmp1); 53910223Ssteve.reinhardt@amd.com 5405958Sgblack@eecs.umich.edu MSIXPbaEntry tmp2 = {0}; 5415958Sgblack@eecs.umich.edu msix_pba.resize(pba_array_size, tmp2); 5425958Sgblack@eecs.umich.edu 5435958Sgblack@eecs.umich.edu for (int i = 0; i < msix_array_size; i++) { 5448829Sgblack@eecs.umich.edu paramIn(cp, csprintf("msix_table[%d].addr_lo", i), 54510223Ssteve.reinhardt@amd.com msix_table[i].fields.addr_lo); 5465958Sgblack@eecs.umich.edu paramIn(cp, csprintf("msix_table[%d].addr_hi", i), 5475958Sgblack@eecs.umich.edu msix_table[i].fields.addr_hi); 54810223Ssteve.reinhardt@amd.com paramIn(cp, csprintf("msix_table[%d].msg_data", i), 54910223Ssteve.reinhardt@amd.com msix_table[i].fields.msg_data); 5508829Sgblack@eecs.umich.edu paramIn(cp, csprintf("msix_table[%d].vec_ctrl", i), 5515958Sgblack@eecs.umich.edu msix_table[i].fields.vec_ctrl); 5525958Sgblack@eecs.umich.edu } 5535958Sgblack@eecs.umich.edu for (int i = 0; i < pba_array_size; i++) { 5545958Sgblack@eecs.umich.edu paramIn(cp, csprintf("msix_pba[%d].bits", i), 5555958Sgblack@eecs.umich.edu msix_pba[i].bits); 55610223Ssteve.reinhardt@amd.com } 55710223Ssteve.reinhardt@amd.com } 5588829Sgblack@eecs.umich.edu 5595958Sgblack@eecs.umich.edu paramIn(cp, csprintf("pxcap.pxid"), tmp16); 5605958Sgblack@eecs.umich.edu pxcap.pxid = tmp16; 5615958Sgblack@eecs.umich.edu paramIn(cp, csprintf("pxcap.pxcap"), tmp16); 5625958Sgblack@eecs.umich.edu pxcap.pxcap = tmp16; 563 paramIn(cp, csprintf("pxcap.pxdcap"), tmp32); 564 pxcap.pxdcap = tmp32; 565 paramIn(cp, csprintf("pxcap.pxdc"), tmp16); 566 pxcap.pxdc = tmp16; 567 paramIn(cp, csprintf("pxcap.pxds"), tmp16); 568 pxcap.pxds = tmp16; 569 paramIn(cp, csprintf("pxcap.pxlcap"), tmp32); 570 pxcap.pxlcap = tmp32; 571 paramIn(cp, csprintf("pxcap.pxlc"), tmp16); 572 pxcap.pxlc = tmp16; 573 paramIn(cp, csprintf("pxcap.pxls"), tmp16); 574 pxcap.pxls = tmp16; 575 paramIn(cp, csprintf("pxcap.pxdcap2"), tmp32); 576 pxcap.pxdcap2 = tmp32; 577 paramIn(cp, csprintf("pxcap.pxdc2"), tmp32); 578 pxcap.pxdc2 = tmp32; 579 pioPort.sendRangeChange(); 580} 581 582