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 &section)
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