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