1793SN/A/*
211193SN/A * Copyright (c) 2013, 2015 ARM Limited
39957SN/A * All rights reserved
49957SN/A *
59957SN/A * The license below extends only to copyright in the software and shall
69957SN/A * not be construed as granting a license to any other intellectual
79957SN/A * property including but not limited to intellectual property relating
89957SN/A * to a hardware implementation of the functionality of the software
99957SN/A * licensed hereunder.  You may use the software subject to the license
109957SN/A * terms below provided that you ensure that this notice is replicated
119957SN/A * unmodified and in its entirety in all distributions of the software,
129957SN/A * modified or unmodified, in source code or in binary form.
139957SN/A *
141762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
15793SN/A * All rights reserved.
16793SN/A *
17793SN/A * Redistribution and use in source and binary forms, with or without
18793SN/A * modification, are permitted provided that the following conditions are
19793SN/A * met: redistributions of source code must retain the above copyright
20793SN/A * notice, this list of conditions and the following disclaimer;
21793SN/A * redistributions in binary form must reproduce the above copyright
22793SN/A * notice, this list of conditions and the following disclaimer in the
23793SN/A * documentation and/or other materials provided with the distribution;
24793SN/A * neither the name of the copyright holders nor the names of its
25793SN/A * contributors may be used to endorse or promote products derived from
26793SN/A * this software without specific prior written permission.
27793SN/A *
28793SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29793SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30793SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31793SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32793SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33793SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34793SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35793SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36793SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37793SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38793SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392665SN/A *
402665SN/A * Authors: Ali Saidi
412665SN/A *          Andrew Schultz
422665SN/A *          Miguel Serrano
43793SN/A */
44793SN/A
45793SN/A/* @file
46793SN/A * A single PCI device configuration space entry.
47793SN/A */
48793SN/A
4911260Sandreas.sandberg@arm.com#include "dev/pci/device.hh"
5011260Sandreas.sandberg@arm.com
51793SN/A#include <list>
52793SN/A#include <string>
53793SN/A#include <vector>
54793SN/A
55793SN/A#include "base/inifile.hh"
567676SN/A#include "base/intmath.hh"
5712334Sgabeblack@google.com#include "base/logging.hh"
587676SN/A#include "base/str.hh"
59793SN/A#include "base/trace.hh"
6011260Sandreas.sandberg@arm.com#include "debug/PciDevice.hh"
612565SN/A#include "mem/packet.hh"
623348SN/A#include "mem/packet_access.hh"
632565SN/A#include "sim/byteswap.hh"
644167SN/A#include "sim/core.hh"
65793SN/A
6611244SN/APciDevice::PciDevice(const PciDeviceParams *p)
679957SN/A    : DmaDevice(p),
6811244SN/A      _busAddr(p->pci_bus, p->pci_dev, p->pci_func),
699957SN/A      PMCAP_BASE(p->PMCAPBaseOffset),
7010479SN/A      PMCAP_ID_OFFSET(p->PMCAPBaseOffset+PMCAP_ID),
7110479SN/A      PMCAP_PC_OFFSET(p->PMCAPBaseOffset+PMCAP_PC),
7210479SN/A      PMCAP_PMCS_OFFSET(p->PMCAPBaseOffset+PMCAP_PMCS),
739957SN/A      MSICAP_BASE(p->MSICAPBaseOffset),
749957SN/A      MSIXCAP_BASE(p->MSIXCAPBaseOffset),
7510479SN/A      MSIXCAP_ID_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_ID),
7610479SN/A      MSIXCAP_MXC_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MXC),
7710479SN/A      MSIXCAP_MTAB_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MTAB),
7810479SN/A      MSIXCAP_MPBA_OFFSET(p->MSIXCAPBaseOffset+MSIXCAP_MPBA),
799957SN/A      PXCAP_BASE(p->PXCAPBaseOffset),
8011244SN/A
8111244SN/A      hostInterface(p->host->registerDevice(this, _busAddr,
8211244SN/A                                            (PciIntPin)p->InterruptPin)),
839957SN/A      pioDelay(p->pio_latency),
8411244SN/A      configDelay(p->config_latency)
85793SN/A{
8611244SN/A    fatal_if(p->InterruptPin >= 5,
8711244SN/A             "Invalid PCI interrupt '%i' specified.", p->InterruptPin);
8811244SN/A
894982SN/A    config.vendor = htole(p->VendorID);
904982SN/A    config.device = htole(p->DeviceID);
914982SN/A    config.command = htole(p->Command);
924982SN/A    config.status = htole(p->Status);
934982SN/A    config.revision = htole(p->Revision);
944982SN/A    config.progIF = htole(p->ProgIF);
954982SN/A    config.subClassCode = htole(p->SubClassCode);
964982SN/A    config.classCode = htole(p->ClassCode);
974982SN/A    config.cacheLineSize = htole(p->CacheLineSize);
984982SN/A    config.latencyTimer = htole(p->LatencyTimer);
994982SN/A    config.headerType = htole(p->HeaderType);
1004982SN/A    config.bist = htole(p->BIST);
1014982SN/A
1024982SN/A    config.baseAddr[0] = htole(p->BAR0);
1034982SN/A    config.baseAddr[1] = htole(p->BAR1);
1044982SN/A    config.baseAddr[2] = htole(p->BAR2);
1054982SN/A    config.baseAddr[3] = htole(p->BAR3);
1064982SN/A    config.baseAddr[4] = htole(p->BAR4);
1074982SN/A    config.baseAddr[5] = htole(p->BAR5);
1084982SN/A    config.cardbusCIS = htole(p->CardbusCIS);
1094982SN/A    config.subsystemVendorID = htole(p->SubsystemVendorID);
1104982SN/A    config.subsystemID = htole(p->SubsystemID);
1114982SN/A    config.expansionROM = htole(p->ExpansionROM);
1129957SN/A    config.capabilityPtr = htole(p->CapabilityPtr);
1139957SN/A    // Zero out the 7 bytes of reserved space in the PCI Config space register.
1149957SN/A    bzero(config.reserved, 7*sizeof(uint8_t));
1154982SN/A    config.interruptLine = htole(p->InterruptLine);
1164982SN/A    config.interruptPin = htole(p->InterruptPin);
1174982SN/A    config.minimumGrant = htole(p->MinimumGrant);
1184982SN/A    config.maximumLatency = htole(p->MaximumLatency);
1194982SN/A
1209957SN/A    // Initialize the capability lists
1219957SN/A    // These structs are bitunions, meaning the data is stored in host
1229957SN/A    // endianess and must be converted to Little Endian when accessed
1239957SN/A    // by the guest
1249957SN/A    // PMCAP
12510479SN/A    pmcap.pid = (uint16_t)p->PMCAPCapId; // pid.cid
12610479SN/A    pmcap.pid |= (uint16_t)p->PMCAPNextCapability << 8; //pid.next
1279957SN/A    pmcap.pc = p->PMCAPCapabilities;
1289957SN/A    pmcap.pmcs = p->PMCAPCtrlStatus;
1299957SN/A
1309957SN/A    // MSICAP
13110479SN/A    msicap.mid = (uint16_t)p->MSICAPCapId; //mid.cid
13210479SN/A    msicap.mid |= (uint16_t)p->MSICAPNextCapability << 8; //mid.next
1339957SN/A    msicap.mc = p->MSICAPMsgCtrl;
1349957SN/A    msicap.ma = p->MSICAPMsgAddr;
1359957SN/A    msicap.mua = p->MSICAPMsgUpperAddr;
1369957SN/A    msicap.md = p->MSICAPMsgData;
1379957SN/A    msicap.mmask = p->MSICAPMaskBits;
1389957SN/A    msicap.mpend = p->MSICAPPendingBits;
1399957SN/A
1409957SN/A    // MSIXCAP
14110479SN/A    msixcap.mxid = (uint16_t)p->MSIXCAPCapId; //mxid.cid
14210479SN/A    msixcap.mxid |= (uint16_t)p->MSIXCAPNextCapability << 8; //mxid.next
1439957SN/A    msixcap.mxc = p->MSIXMsgCtrl;
1449957SN/A    msixcap.mtab = p->MSIXTableOffset;
1459957SN/A    msixcap.mpba = p->MSIXPbaOffset;
1469957SN/A
1479957SN/A    // allocate MSIX structures if MSIXCAP_BASE
1489957SN/A    // indicates the MSIXCAP is being used by having a
1499957SN/A    // non-zero base address.
1509957SN/A    // The MSIX tables are stored by the guest in
1519957SN/A    // little endian byte-order as according the
1529957SN/A    // PCIe specification.  Make sure to take the proper
1539957SN/A    // actions when manipulating these tables on the host
15410479SN/A    uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff;
1559957SN/A    if (MSIXCAP_BASE != 0x0) {
15610479SN/A        int msix_vecs = msixcap_mxc_ts + 1;
1579957SN/A        MSIXTable tmp1 = {{0UL,0UL,0UL,0UL}};
1589957SN/A        msix_table.resize(msix_vecs, tmp1);
1599957SN/A
1609957SN/A        MSIXPbaEntry tmp2 = {0};
1619957SN/A        int pba_size = msix_vecs / MSIXVECS_PER_PBA;
1629957SN/A        if ((msix_vecs % MSIXVECS_PER_PBA) > 0) {
1639957SN/A            pba_size++;
1649957SN/A        }
1659957SN/A        msix_pba.resize(pba_size, tmp2);
1669957SN/A    }
16710479SN/A    MSIX_TABLE_OFFSET = msixcap.mtab & 0xfffffffc;
16810479SN/A    MSIX_TABLE_END = MSIX_TABLE_OFFSET +
16910479SN/A                     (msixcap_mxc_ts + 1) * sizeof(MSIXTable);
17010479SN/A    MSIX_PBA_OFFSET = msixcap.mpba & 0xfffffffc;
17110479SN/A    MSIX_PBA_END = MSIX_PBA_OFFSET +
17210479SN/A                   ((msixcap_mxc_ts + 1) / MSIXVECS_PER_PBA)
17310479SN/A                   * sizeof(MSIXPbaEntry);
17410479SN/A    if (((msixcap_mxc_ts + 1) % MSIXVECS_PER_PBA) > 0) {
17510479SN/A        MSIX_PBA_END += sizeof(MSIXPbaEntry);
17610479SN/A    }
1779957SN/A
1789957SN/A    // PXCAP
17910479SN/A    pxcap.pxid = (uint16_t)p->PXCAPCapId; //pxid.cid
18010479SN/A    pxcap.pxid |= (uint16_t)p->PXCAPNextCapability << 8; //pxid.next
1819957SN/A    pxcap.pxcap = p->PXCAPCapabilities;
1829957SN/A    pxcap.pxdcap = p->PXCAPDevCapabilities;
1839957SN/A    pxcap.pxdc = p->PXCAPDevCtrl;
1849957SN/A    pxcap.pxds = p->PXCAPDevStatus;
1859957SN/A    pxcap.pxlcap = p->PXCAPLinkCap;
1869957SN/A    pxcap.pxlc = p->PXCAPLinkCtrl;
1879957SN/A    pxcap.pxls = p->PXCAPLinkStatus;
1889957SN/A    pxcap.pxdcap2 = p->PXCAPDevCap2;
1899957SN/A    pxcap.pxdc2 = p->PXCAPDevCtrl2;
1909957SN/A
1914982SN/A    BARSize[0] = p->BAR0Size;
1924982SN/A    BARSize[1] = p->BAR1Size;
1934982SN/A    BARSize[2] = p->BAR2Size;
1944982SN/A    BARSize[3] = p->BAR3Size;
1954982SN/A    BARSize[4] = p->BAR4Size;
1964982SN/A    BARSize[5] = p->BAR5Size;
1974982SN/A
1985834SN/A    legacyIO[0] = p->BAR0LegacyIO;
1995834SN/A    legacyIO[1] = p->BAR1LegacyIO;
2005834SN/A    legacyIO[2] = p->BAR2LegacyIO;
2015834SN/A    legacyIO[3] = p->BAR3LegacyIO;
2025834SN/A    legacyIO[4] = p->BAR4LegacyIO;
2035834SN/A    legacyIO[5] = p->BAR5LegacyIO;
2045834SN/A
2054982SN/A    for (int i = 0; i < 6; ++i) {
2065834SN/A        if (legacyIO[i]) {
20710359SN/A            BARAddrs[i] = p->LegacyIOBase + letoh(config.baseAddr[i]);
2085834SN/A            config.baseAddr[i] = 0;
2095834SN/A        } else {
2105834SN/A            BARAddrs[i] = 0;
2115834SN/A            uint32_t barsize = BARSize[i];
2125834SN/A            if (barsize != 0 && !isPowerOf2(barsize)) {
2135834SN/A                fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]);
2145834SN/A            }
2154982SN/A        }
2164982SN/A    }
2172846SN/A}
2182846SN/A
2192846SN/ATick
2209807SN/APciDevice::readConfig(PacketPtr pkt)
2212846SN/A{
2222846SN/A    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
22310479SN/A
22410479SN/A    /* Return 0 for accesses to unimplemented PCI configspace areas */
22510479SN/A    if (offset >= PCI_DEVICE_SPECIFIC &&
22610479SN/A        offset < PCI_CONFIG_SIZE) {
22710479SN/A        warn_once("Device specific PCI config space "
22810479SN/A                  "not implemented for %s!\n", this->name());
22910479SN/A        switch (pkt->getSize()) {
23010479SN/A            case sizeof(uint8_t):
23113342Sgabeblack@google.com                pkt->setLE<uint8_t>(0);
23210479SN/A                break;
23310479SN/A            case sizeof(uint16_t):
23413342Sgabeblack@google.com                pkt->setLE<uint16_t>(0);
23510479SN/A                break;
23610479SN/A            case sizeof(uint32_t):
23713342Sgabeblack@google.com                pkt->setLE<uint32_t>(0);
23810479SN/A                break;
23910479SN/A            default:
24010479SN/A                panic("invalid access size(?) for PCI configspace!\n");
24110479SN/A        }
24210479SN/A    } else if (offset > PCI_CONFIG_SIZE) {
24310479SN/A        panic("Out-of-range access to PCI config space!\n");
24410479SN/A    }
24510479SN/A
2462846SN/A    switch (pkt->getSize()) {
2472846SN/A      case sizeof(uint8_t):
24813342Sgabeblack@google.com        pkt->setLE<uint8_t>(config.data[offset]);
24911260Sandreas.sandberg@arm.com        DPRINTF(PciDevice,
2503083SN/A            "readConfig:  dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
25111244SN/A            _busAddr.dev, _busAddr.func, offset,
25213342Sgabeblack@google.com            (uint32_t)pkt->getLE<uint8_t>());
2532846SN/A        break;
2542846SN/A      case sizeof(uint16_t):
25513342Sgabeblack@google.com        pkt->setLE<uint16_t>(*(uint16_t*)&config.data[offset]);
25611260Sandreas.sandberg@arm.com        DPRINTF(PciDevice,
2573083SN/A            "readConfig:  dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
25811244SN/A            _busAddr.dev, _busAddr.func, offset,
25913342Sgabeblack@google.com            (uint32_t)pkt->getLE<uint16_t>());
2602846SN/A        break;
2612846SN/A      case sizeof(uint32_t):
26213342Sgabeblack@google.com        pkt->setLE<uint32_t>(*(uint32_t*)&config.data[offset]);
26311260Sandreas.sandberg@arm.com        DPRINTF(PciDevice,
2643083SN/A            "readConfig:  dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
26511244SN/A            _busAddr.dev, _busAddr.func, offset,
26613342Sgabeblack@google.com            (uint32_t)pkt->getLE<uint32_t>());
2672846SN/A        break;
2682846SN/A      default:
2692846SN/A        panic("invalid access size(?) for PCI configspace!\n");
2702846SN/A    }
2714870SN/A    pkt->makeAtomicResponse();
2722846SN/A    return configDelay;
2732846SN/A
274793SN/A}
275793SN/A
2768711SN/AAddrRangeList
2779807SN/APciDevice::getAddrRanges() const
2782565SN/A{
2798711SN/A    AddrRangeList ranges;
2802565SN/A    int x = 0;
2812565SN/A    for (x = 0; x < 6; x++)
2822565SN/A        if (BARAddrs[x] != 0)
2838711SN/A            ranges.push_back(RangeSize(BARAddrs[x],BARSize[x]));
2848711SN/A    return ranges;
2852565SN/A}
2862565SN/A
2872846SN/ATick
2889807SN/APciDevice::writeConfig(PacketPtr pkt)
289793SN/A{
2902846SN/A    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
29110479SN/A
29210479SN/A    /* No effect if we write to config space that is not implemented*/
29310479SN/A    if (offset >= PCI_DEVICE_SPECIFIC &&
29410479SN/A        offset < PCI_CONFIG_SIZE) {
29510479SN/A        warn_once("Device specific PCI config space "
29610479SN/A                  "not implemented for %s!\n", this->name());
29710479SN/A        switch (pkt->getSize()) {
29810479SN/A            case sizeof(uint8_t):
29910479SN/A            case sizeof(uint16_t):
30010479SN/A            case sizeof(uint32_t):
30110479SN/A                break;
30210479SN/A            default:
30310479SN/A                panic("invalid access size(?) for PCI configspace!\n");
30410479SN/A        }
30510479SN/A    } else if (offset > PCI_CONFIG_SIZE) {
30610479SN/A        panic("Out-of-range access to PCI config space!\n");
30710479SN/A    }
3081155SN/A
3092846SN/A    switch (pkt->getSize()) {
3102846SN/A      case sizeof(uint8_t):
3112846SN/A        switch (offset) {
3122846SN/A          case PCI0_INTERRUPT_LINE:
31313342Sgabeblack@google.com            config.interruptLine = pkt->getLE<uint8_t>();
3145777SN/A            break;
3152846SN/A          case PCI_CACHE_LINE_SIZE:
31613342Sgabeblack@google.com            config.cacheLineSize = pkt->getLE<uint8_t>();
3175777SN/A            break;
3182846SN/A          case PCI_LATENCY_TIMER:
31913342Sgabeblack@google.com            config.latencyTimer = pkt->getLE<uint8_t>();
3202846SN/A            break;
3212846SN/A          /* Do nothing for these read-only registers */
3222846SN/A          case PCI0_INTERRUPT_PIN:
3232846SN/A          case PCI0_MINIMUM_GRANT:
3242846SN/A          case PCI0_MAXIMUM_LATENCY:
3252846SN/A          case PCI_CLASS_CODE:
3262846SN/A          case PCI_REVISION_ID:
3272846SN/A            break;
3282846SN/A          default:
3292846SN/A            panic("writing to a read only register");
3302846SN/A        }
33111260Sandreas.sandberg@arm.com        DPRINTF(PciDevice,
3323083SN/A            "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
33311244SN/A            _busAddr.dev, _busAddr.func, offset,
33413342Sgabeblack@google.com            (uint32_t)pkt->getLE<uint8_t>());
3352846SN/A        break;
3362846SN/A      case sizeof(uint16_t):
3372846SN/A        switch (offset) {
3382846SN/A          case PCI_COMMAND:
33913342Sgabeblack@google.com            config.command = pkt->getLE<uint8_t>();
3405777SN/A            break;
3412846SN/A          case PCI_STATUS:
34213342Sgabeblack@google.com            config.status = pkt->getLE<uint8_t>();
3435777SN/A            break;
3442846SN/A          case PCI_CACHE_LINE_SIZE:
34513342Sgabeblack@google.com            config.cacheLineSize = pkt->getLE<uint8_t>();
3462846SN/A            break;
3472846SN/A          default:
3482846SN/A            panic("writing to a read only register");
3492846SN/A        }
35011260Sandreas.sandberg@arm.com        DPRINTF(PciDevice,
3513083SN/A            "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
35211244SN/A            _busAddr.dev, _busAddr.func, offset,
35313342Sgabeblack@google.com            (uint32_t)pkt->getLE<uint16_t>());
3542846SN/A        break;
3552846SN/A      case sizeof(uint32_t):
3562846SN/A        switch (offset) {
3572846SN/A          case PCI0_BASE_ADDR0:
3582846SN/A          case PCI0_BASE_ADDR1:
3592846SN/A          case PCI0_BASE_ADDR2:
3602846SN/A          case PCI0_BASE_ADDR3:
3612846SN/A          case PCI0_BASE_ADDR4:
3622846SN/A          case PCI0_BASE_ADDR5:
3633086SN/A            {
3643086SN/A                int barnum = BAR_NUMBER(offset);
365793SN/A
3665834SN/A                if (!legacyIO[barnum]) {
3675834SN/A                    // convert BAR values to host endianness
3685834SN/A                    uint32_t he_old_bar = letoh(config.baseAddr[barnum]);
36913342Sgabeblack@google.com                    uint32_t he_new_bar = letoh(pkt->getLE<uint32_t>());
370795SN/A
3715834SN/A                    uint32_t bar_mask =
3725834SN/A                        BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK;
3732565SN/A
3745834SN/A                    // Writing 0xffffffff to a BAR tells the card to set the
3755834SN/A                    // value of the bar to a bitmask indicating the size of
3765834SN/A                    // memory it needs
3775834SN/A                    if (he_new_bar == 0xffffffff) {
3785834SN/A                        he_new_bar = ~(BARSize[barnum] - 1);
3795834SN/A                    } else {
3805834SN/A                        // does it mean something special to write 0 to a BAR?
3815834SN/A                        he_new_bar &= ~bar_mask;
3825834SN/A                        if (he_new_bar) {
3835834SN/A                            BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ?
38411244SN/A                                hostInterface.pioAddr(he_new_bar) :
38511244SN/A                                hostInterface.memAddr(he_new_bar);
3868851SN/A                            pioPort.sendRangeChange();
3875834SN/A                        }
3883086SN/A                    }
3895834SN/A                    config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) |
3905834SN/A                                                    (he_old_bar & bar_mask));
3912846SN/A                }
3922846SN/A            }
3932846SN/A            break;
3942565SN/A
3952846SN/A          case PCI0_ROM_BASE_ADDR:
39613342Sgabeblack@google.com            if (letoh(pkt->getLE<uint32_t>()) == 0xfffffffe)
3972846SN/A                config.expansionROM = htole((uint32_t)0xffffffff);
3982846SN/A            else
39913342Sgabeblack@google.com                config.expansionROM = pkt->getLE<uint32_t>();
4002846SN/A            break;
4012846SN/A
4022846SN/A          case PCI_COMMAND:
4032846SN/A            // This could also clear some of the error bits in the Status
4042846SN/A            // register. However they should never get set, so lets ignore
4052846SN/A            // it for now
40613342Sgabeblack@google.com            config.command = pkt->getLE<uint32_t>();
4072846SN/A            break;
4082846SN/A
4092846SN/A          default:
41011260Sandreas.sandberg@arm.com            DPRINTF(PciDevice, "Writing to a read only register");
4112846SN/A        }
41211260Sandreas.sandberg@arm.com        DPRINTF(PciDevice,
4133083SN/A            "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
41411244SN/A            _busAddr.dev, _busAddr.func, offset,
41513342Sgabeblack@google.com            (uint32_t)pkt->getLE<uint32_t>());
4162565SN/A        break;
4172565SN/A      default:
4182846SN/A        panic("invalid access size(?) for PCI configspace!\n");
4192565SN/A    }
4204870SN/A    pkt->makeAtomicResponse();
4212846SN/A    return configDelay;
422793SN/A}
423793SN/A
424793SN/Avoid
42510905SN/APciDevice::serialize(CheckpointOut &cp) const
426793SN/A{
4271854SN/A    SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0]));
4281854SN/A    SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
4291854SN/A    SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0]));
4309957SN/A
4319957SN/A    // serialize the capability list registers
43210905SN/A    paramOut(cp, csprintf("pmcap.pid"), uint16_t(pmcap.pid));
43310905SN/A    paramOut(cp, csprintf("pmcap.pc"), uint16_t(pmcap.pc));
43410905SN/A    paramOut(cp, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs));
4359957SN/A
43610905SN/A    paramOut(cp, csprintf("msicap.mid"), uint16_t(msicap.mid));
43710905SN/A    paramOut(cp, csprintf("msicap.mc"), uint16_t(msicap.mc));
43810905SN/A    paramOut(cp, csprintf("msicap.ma"), uint32_t(msicap.ma));
4399957SN/A    SERIALIZE_SCALAR(msicap.mua);
44010905SN/A    paramOut(cp, csprintf("msicap.md"), uint16_t(msicap.md));
4419957SN/A    SERIALIZE_SCALAR(msicap.mmask);
4429957SN/A    SERIALIZE_SCALAR(msicap.mpend);
4439957SN/A
44410905SN/A    paramOut(cp, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid));
44510905SN/A    paramOut(cp, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc));
44610905SN/A    paramOut(cp, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab));
44710905SN/A    paramOut(cp, csprintf("msixcap.mpba"), uint32_t(msixcap.mpba));
4489957SN/A
4499957SN/A    // Only serialize if we have a non-zero base address
4509957SN/A    if (MSIXCAP_BASE != 0x0) {
45110479SN/A        uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff;
45210479SN/A        int msix_array_size = msixcap_mxc_ts + 1;
4539957SN/A        int pba_array_size = msix_array_size/MSIXVECS_PER_PBA;
4549957SN/A        if ((msix_array_size % MSIXVECS_PER_PBA) > 0) {
4559957SN/A            pba_array_size++;
4569957SN/A        }
4579957SN/A
4589957SN/A        SERIALIZE_SCALAR(msix_array_size);
4599957SN/A        SERIALIZE_SCALAR(pba_array_size);
4609957SN/A
4619957SN/A        for (int i = 0; i < msix_array_size; i++) {
46210905SN/A            paramOut(cp, csprintf("msix_table[%d].addr_lo", i),
4639957SN/A                     msix_table[i].fields.addr_lo);
46410905SN/A            paramOut(cp, csprintf("msix_table[%d].addr_hi", i),
4659957SN/A                     msix_table[i].fields.addr_hi);
46610905SN/A            paramOut(cp, csprintf("msix_table[%d].msg_data", i),
4679957SN/A                     msix_table[i].fields.msg_data);
46810905SN/A            paramOut(cp, csprintf("msix_table[%d].vec_ctrl", i),
4699957SN/A                     msix_table[i].fields.vec_ctrl);
4709957SN/A        }
4719957SN/A        for (int i = 0; i < pba_array_size; i++) {
47210905SN/A            paramOut(cp, csprintf("msix_pba[%d].bits", i),
4739957SN/A                     msix_pba[i].bits);
4749957SN/A        }
4759957SN/A    }
4769957SN/A
47710905SN/A    paramOut(cp, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid));
47810905SN/A    paramOut(cp, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap));
47910905SN/A    paramOut(cp, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap));
48010905SN/A    paramOut(cp, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc));
48110905SN/A    paramOut(cp, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds));
48210905SN/A    paramOut(cp, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap));
48310905SN/A    paramOut(cp, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc));
48410905SN/A    paramOut(cp, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls));
48510905SN/A    paramOut(cp, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2));
48610905SN/A    paramOut(cp, csprintf("pxcap.pxdc2"), uint32_t(pxcap.pxdc2));
487793SN/A}
488793SN/A
489793SN/Avoid
49010905SN/APciDevice::unserialize(CheckpointIn &cp)
491793SN/A{
4921854SN/A    UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0]));
4931854SN/A    UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
4941854SN/A    UNSERIALIZE_ARRAY(config.data,
4951854SN/A                      sizeof(config.data) / sizeof(config.data[0]));
4969957SN/A
4979957SN/A    // unserialize the capability list registers
4989957SN/A    uint16_t tmp16;
4999957SN/A    uint32_t tmp32;
50010905SN/A    paramIn(cp, csprintf("pmcap.pid"), tmp16);
5019957SN/A    pmcap.pid = tmp16;
50210905SN/A    paramIn(cp, csprintf("pmcap.pc"), tmp16);
5039957SN/A    pmcap.pc = tmp16;
50410905SN/A    paramIn(cp, csprintf("pmcap.pmcs"), tmp16);
5059957SN/A    pmcap.pmcs = tmp16;
5069957SN/A
50710905SN/A    paramIn(cp, csprintf("msicap.mid"), tmp16);
5089957SN/A    msicap.mid = tmp16;
50910905SN/A    paramIn(cp, csprintf("msicap.mc"), tmp16);
5109957SN/A    msicap.mc = tmp16;
51110905SN/A    paramIn(cp, csprintf("msicap.ma"), tmp32);
5129957SN/A    msicap.ma = tmp32;
5139957SN/A    UNSERIALIZE_SCALAR(msicap.mua);
51410905SN/A    paramIn(cp, csprintf("msicap.md"), tmp16);;
5159957SN/A    msicap.md = tmp16;
5169957SN/A    UNSERIALIZE_SCALAR(msicap.mmask);
5179957SN/A    UNSERIALIZE_SCALAR(msicap.mpend);
5189957SN/A
51910905SN/A    paramIn(cp, csprintf("msixcap.mxid"), tmp16);
5209957SN/A    msixcap.mxid = tmp16;
52110905SN/A    paramIn(cp, csprintf("msixcap.mxc"), tmp16);
5229957SN/A    msixcap.mxc = tmp16;
52310905SN/A    paramIn(cp, csprintf("msixcap.mtab"), tmp32);
5249957SN/A    msixcap.mtab = tmp32;
52510905SN/A    paramIn(cp, csprintf("msixcap.mpba"), tmp32);
5269957SN/A    msixcap.mpba = tmp32;
5279957SN/A
5289957SN/A    // Only allocate if MSIXCAP_BASE is not 0x0
5299957SN/A    if (MSIXCAP_BASE != 0x0) {
5309957SN/A        int msix_array_size;
5319957SN/A        int pba_array_size;
5329957SN/A
5339957SN/A        UNSERIALIZE_SCALAR(msix_array_size);
5349957SN/A        UNSERIALIZE_SCALAR(pba_array_size);
5359957SN/A
5369957SN/A        MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}};
5379957SN/A        msix_table.resize(msix_array_size, tmp1);
5389957SN/A
5399957SN/A        MSIXPbaEntry tmp2 = {0};
5409957SN/A        msix_pba.resize(pba_array_size, tmp2);
5419957SN/A
5429957SN/A        for (int i = 0; i < msix_array_size; i++) {
54310905SN/A            paramIn(cp, csprintf("msix_table[%d].addr_lo", i),
5449957SN/A                    msix_table[i].fields.addr_lo);
54510905SN/A            paramIn(cp, csprintf("msix_table[%d].addr_hi", i),
5469957SN/A                    msix_table[i].fields.addr_hi);
54710905SN/A            paramIn(cp, csprintf("msix_table[%d].msg_data", i),
5489957SN/A                    msix_table[i].fields.msg_data);
54910905SN/A            paramIn(cp, csprintf("msix_table[%d].vec_ctrl", i),
5509957SN/A                    msix_table[i].fields.vec_ctrl);
5519957SN/A        }
5529957SN/A        for (int i = 0; i < pba_array_size; i++) {
55310905SN/A            paramIn(cp, csprintf("msix_pba[%d].bits", i),
5549957SN/A                    msix_pba[i].bits);
5559957SN/A        }
5569957SN/A    }
5579957SN/A
55810905SN/A    paramIn(cp, csprintf("pxcap.pxid"), tmp16);
5599957SN/A    pxcap.pxid = tmp16;
56010905SN/A    paramIn(cp, csprintf("pxcap.pxcap"), tmp16);
5619957SN/A    pxcap.pxcap = tmp16;
56210905SN/A    paramIn(cp, csprintf("pxcap.pxdcap"), tmp32);
5639957SN/A    pxcap.pxdcap = tmp32;
56410905SN/A    paramIn(cp, csprintf("pxcap.pxdc"), tmp16);
5659957SN/A    pxcap.pxdc = tmp16;
56610905SN/A    paramIn(cp, csprintf("pxcap.pxds"), tmp16);
5679957SN/A    pxcap.pxds = tmp16;
56810905SN/A    paramIn(cp, csprintf("pxcap.pxlcap"), tmp32);
5699957SN/A    pxcap.pxlcap = tmp32;
57010905SN/A    paramIn(cp, csprintf("pxcap.pxlc"), tmp16);
5719957SN/A    pxcap.pxlc = tmp16;
57210905SN/A    paramIn(cp, csprintf("pxcap.pxls"), tmp16);
5739957SN/A    pxcap.pxls = tmp16;
57410905SN/A    paramIn(cp, csprintf("pxcap.pxdcap2"), tmp32);
5759957SN/A    pxcap.pxdcap2 = tmp32;
57610905SN/A    paramIn(cp, csprintf("pxcap.pxdc2"), tmp32);
5779957SN/A    pxcap.pxdc2 = tmp32;
5788851SN/A    pioPort.sendRangeChange();
579793SN/A}
580793SN/A
581