device.cc revision 2665
12497SN/A/*
210405Sandreas.hansson@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
38711SN/A * All rights reserved.
48711SN/A *
58711SN/A * Redistribution and use in source and binary forms, with or without
68711SN/A * modification, are permitted provided that the following conditions are
78711SN/A * met: redistributions of source code must retain the above copyright
88711SN/A * notice, this list of conditions and the following disclaimer;
98711SN/A * redistributions in binary form must reproduce the above copyright
108711SN/A * notice, this list of conditions and the following disclaimer in the
118711SN/A * documentation and/or other materials provided with the distribution;
128711SN/A * neither the name of the copyright holders nor the names of its
138711SN/A * contributors may be used to endorse or promote products derived from
142497SN/A * this software without specific prior written permission.
152497SN/A *
162497SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172497SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182497SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192497SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202497SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212497SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222497SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232497SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242497SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252497SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262497SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272497SN/A *
282497SN/A * Authors: Ali Saidi
292497SN/A *          Andrew Schultz
302497SN/A *          Miguel Serrano
312497SN/A */
322497SN/A
332497SN/A/* @file
342497SN/A * A single PCI device configuration space entry.
352497SN/A */
362497SN/A
372497SN/A#include <list>
382497SN/A#include <string>
392665SN/A#include <vector>
402665SN/A
418715SN/A#include "base/inifile.hh"
428922SN/A#include "base/misc.hh"
432497SN/A#include "base/str.hh"	// for to_number
442497SN/A#include "base/trace.hh"
452497SN/A#include "dev/pciconfigall.hh"
462982SN/A#include "dev/pcidev.hh"
4710405Sandreas.hansson@arm.com#include "dev/tsunamireg.h"
482497SN/A#include "mem/packet.hh"
492497SN/A#include "sim/builder.hh"
502846SN/A#include "sim/byteswap.hh"
512548SN/A#include "sim/param.hh"
5210405Sandreas.hansson@arm.com#include "sim/root.hh"
539152SN/A
5410405Sandreas.hansson@arm.comusing namespace std;
5510405Sandreas.hansson@arm.com
562497SN/APciDev::PciDev(Params *p)
5710405Sandreas.hansson@arm.com    : DmaDevice(p), plat(p->platform), configData(p->configData),
589157SN/A      pioDelay(p->pio_delay)
599091SN/A{
609279SN/A    // copy the config data from the PciConfigData object
619279SN/A    if (configData) {
629279SN/A        memcpy(config.data, configData->config.data, sizeof(config.data));
639814SN/A        memcpy(BARSize, configData->BARSize, sizeof(BARSize));
649240SN/A        memcpy(BARAddrs, configData->BARAddrs, sizeof(BARAddrs));
658851SN/A    } else
6610405Sandreas.hansson@arm.com        panic("NULL pointer to configuration data");
679036SN/A
6810405Sandreas.hansson@arm.com    // Setup pointer in config space to point to this entry
6910405Sandreas.hansson@arm.com    if (p->configSpace->deviceExists(p->deviceNum, p->functionNum))
708851SN/A        panic("Two PCI devices occuping same dev: %#x func: %#x",
7110405Sandreas.hansson@arm.com              p->deviceNum, p->functionNum);
7210405Sandreas.hansson@arm.com    else
737523SN/A        p->configSpace->registerDevice(p->deviceNum, p->functionNum, this);
747523SN/A}
759278SN/A
7610405Sandreas.hansson@arm.comvoid
779278SN/APciDev::readConfig(int offset, uint8_t *data)
789278SN/A{
799278SN/A    if (offset >= PCI_DEVICE_SPECIFIC)
809294SN/A        panic("Device specific PCI config space not implemented!\n");
8110405Sandreas.hansson@arm.com
822640SN/A    *data = config.data[offset];
838948SN/A
848948SN/A    DPRINTF(PCIDEV,
858922SN/A            "read device: %#x function: %#x register: %#x 1 bytes: data: %#x\n",
868851SN/A            params()->deviceNum, params()->functionNum, offset, *data);
879031SN/A}
888715SN/A
898922SN/Avoid
908922SN/APciDev::addressRanges(AddrRangeList &range_list)
918922SN/A{
928922SN/A    int x = 0;
939294SN/A    range_list.clear();
9410405Sandreas.hansson@arm.com    for (x = 0; x < 6; x++)
958922SN/A        if (BARAddrs[x] != 0)
968948SN/A            range_list.push_back(RangeSize(BARAddrs[x],BARSize[x]));
978948SN/A}
988948SN/A
998922SN/Avoid
1008922SN/APciDev::readConfig(int offset, uint16_t *data)
1013489SN/A{
1022640SN/A    if (offset >= PCI_DEVICE_SPECIFIC)
1032640SN/A        panic("Device specific PCI config space not implemented!\n");
1049547SN/A
10510405Sandreas.hansson@arm.com    *data = *(uint16_t*)&config.data[offset];
1062497SN/A
10710405Sandreas.hansson@arm.com    DPRINTF(PCIDEV,
1089547SN/A            "read device: %#x function: %#x register: %#x 2 bytes: data: %#x\n",
1099547SN/A            params()->deviceNum, params()->functionNum, offset, *data);
1109648SN/A}
1115354SN/A
1129547SN/Avoid
1139547SN/APciDev::readConfig(int offset, uint32_t *data)
1143210SN/A{
1159549SN/A    if (offset >= PCI_DEVICE_SPECIFIC)
11610405Sandreas.hansson@arm.com        panic("Device specific PCI config space not implemented!\n");
11710405Sandreas.hansson@arm.com
11810405Sandreas.hansson@arm.com    *data = *(uint32_t*)&config.data[offset];
11910405Sandreas.hansson@arm.com
12010405Sandreas.hansson@arm.com    DPRINTF(PCIDEV,
1219549SN/A            "read device: %#x function: %#x register: %#x 4 bytes: data: %#x\n",
1229545SN/A            params()->deviceNum, params()->functionNum, offset, *data);
12310405Sandreas.hansson@arm.com}
1243218SN/A
12510405Sandreas.hansson@arm.com
12610405Sandreas.hansson@arm.comvoid
12710405Sandreas.hansson@arm.comPciDev::writeConfig(int offset,  const uint8_t data)
1289547SN/A{
1295354SN/A    if (offset >= PCI_DEVICE_SPECIFIC)
1305354SN/A        panic("Device specific PCI config space not implemented!\n");
1319715SN/A
13210405Sandreas.hansson@arm.com    DPRINTF(PCIDEV,
1339715SN/A            "write device: %#x function: %#x reg: %#x size: 1 data: %#x\n",
13410405Sandreas.hansson@arm.com            params()->deviceNum, params()->functionNum, offset, data);
13510347SN/A
1369092SN/A    switch (offset) {
1379092SN/A      case PCI0_INTERRUPT_LINE:
1389092SN/A        config.interruptLine = data;
1399715SN/A      case PCI_CACHE_LINE_SIZE:
14010405Sandreas.hansson@arm.com        config.cacheLineSize = data;
1415354SN/A      case PCI_LATENCY_TIMER:
14210405Sandreas.hansson@arm.com        config.latencyTimer = data;
1439612SN/A        break;
1449612SN/A      /* Do nothing for these read-only registers */
14510405Sandreas.hansson@arm.com      case PCI0_INTERRUPT_PIN:
1469612SN/A      case PCI0_MINIMUM_GRANT:
1475354SN/A      case PCI0_MAXIMUM_LATENCY:
14810405Sandreas.hansson@arm.com      case PCI_CLASS_CODE:
1499091SN/A      case PCI_REVISION_ID:
15010405Sandreas.hansson@arm.com        break;
1519091SN/A      default:
1529712SN/A        panic("writing to a read only register");
1539712SN/A    }
1549712SN/A}
15510405Sandreas.hansson@arm.com
1569091SN/Avoid
1573244SN/APciDev::writeConfig(int offset, const uint16_t data)
1583244SN/A{
1599715SN/A    if (offset >= PCI_DEVICE_SPECIFIC)
1608948SN/A        panic("Device specific PCI config space not implemented!\n");
16110405Sandreas.hansson@arm.com
1628948SN/A    DPRINTF(PCIDEV,
1639716SN/A            "write device: %#x function: %#x reg: %#x size: 2 data: %#x\n",
1649716SN/A            params()->deviceNum, params()->functionNum, offset, data);
1659716SN/A
1669716SN/A    switch (offset) {
16710405Sandreas.hansson@arm.com      case PCI_COMMAND:
1689716SN/A        config.command = data;
1699716SN/A      case PCI_STATUS:
1709716SN/A        config.status = data;
1719716SN/A      case PCI_CACHE_LINE_SIZE:
1729716SN/A        config.cacheLineSize = data;
1739716SN/A        break;
1749716SN/A      default:
1759716SN/A        panic("writing to a read only register");
1769716SN/A    }
1779612SN/A}
1789612SN/A
17910405Sandreas.hansson@arm.com
1809612SN/Avoid
1819715SN/APciDev::writeConfig(int offset, const uint32_t data)
1829091SN/A{
1838948SN/A    if (offset >= PCI_DEVICE_SPECIFIC)
1849091SN/A        panic("Device specific PCI config space not implemented!\n");
1859612SN/A
1869611SN/A    DPRINTF(PCIDEV,
1879091SN/A            "write device: %#x function: %#x reg: %#x size: 4 data: %#x\n",
1888948SN/A            params()->deviceNum, params()->functionNum, offset, data);
1898948SN/A
1909715SN/A    switch (offset) {
1918975SN/A      case PCI0_BASE_ADDR0:
19210405Sandreas.hansson@arm.com      case PCI0_BASE_ADDR1:
1938948SN/A      case PCI0_BASE_ADDR2:
1949612SN/A      case PCI0_BASE_ADDR3:
1959612SN/A      case PCI0_BASE_ADDR4:
1969091SN/A      case PCI0_BASE_ADDR5:
1979091SN/A
19810405Sandreas.hansson@arm.com        uint32_t barnum, bar_mask;
1999092SN/A        Addr base_addr, base_size, space_base;
2009091SN/A
2019091SN/A        barnum = BAR_NUMBER(offset);
2029715SN/A
2039091SN/A        if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) {
20410405Sandreas.hansson@arm.com            bar_mask = BAR_IO_MASK;
2059715SN/A            space_base = TSUNAMI_PCI0_IO;
2069091SN/A        } else {
2079612SN/A            bar_mask = BAR_MEM_MASK;
2089612SN/A            space_base = TSUNAMI_PCI0_MEMORY;
2099715SN/A        }
2109091SN/A
2119612SN/A        // Writing 0xffffffff to a BAR tells the card to set the
2129612SN/A        // value of the bar to size of memory it needs
2139612SN/A        if (letoh(data) == 0xffffffff) {
2149715SN/A            // This is I/O Space, bottom two bits are read only
2159612SN/A
2169612SN/A            config.baseAddr[barnum] = letoh(
2179612SN/A                    (~(BARSize[barnum] - 1) & ~bar_mask) |
2189612SN/A                    (letoh(config.baseAddr[barnum]) & bar_mask));
2199091SN/A        } else {
2209091SN/A            config.baseAddr[barnum] = letoh(
2219092SN/A                (letoh(data) & ~bar_mask) |
2228948SN/A                (letoh(config.baseAddr[barnum]) & bar_mask));
2238948SN/A
2249715SN/A            if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
2258948SN/A                base_addr = (letoh(data) & ~bar_mask) + space_base;
22610405Sandreas.hansson@arm.com                base_size = BARSize[barnum];
2272657SN/A                BARAddrs[barnum] = base_addr;
2288915SN/A
2299091SN/A            pioPort->sendStatusChange(Port::RangeChange);
2309092SN/A            }
2319091SN/A        }
2329091SN/A        break;
2339091SN/A
2343252SN/A      case PCI0_ROM_BASE_ADDR:
2359612SN/A        if (letoh(data) == 0xfffffffe)
2369612SN/A            config.expansionROM = htole((uint32_t)0xffffffff);
23710347SN/A        else
23810347SN/A            config.expansionROM = data;
23910347SN/A        break;
24010347SN/A
2419710SN/A      case PCI_COMMAND:
24210405Sandreas.hansson@arm.com        // This could also clear some of the error bits in the Status
2439091SN/A        // register. However they should never get set, so lets ignore
2449342SN/A        // it for now
2453512SN/A        config.command = data;
2469342SN/A        break;
2473512SN/A
2482657SN/A      default:
2492657SN/A        DPRINTF(PCIDEV, "Writing to a read only register");
2509715SN/A    }
2518915SN/A}
25210405Sandreas.hansson@arm.com
2538915SN/Avoid
2549612SN/APciDev::serialize(ostream &os)
2559612SN/A{
2568915SN/A    SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0]));
2579091SN/A    SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
2589091SN/A    SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0]));
2599091SN/A}
2609611SN/A
2619091SN/Avoid
2628915SN/APciDev::unserialize(Checkpoint *cp, const std::string &section)
2639611SN/A{
2649611SN/A    UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0]));
26510347SN/A    UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
2669612SN/A    UNSERIALIZE_ARRAY(config.data,
2679611SN/A                      sizeof(config.data) / sizeof(config.data[0]));
2689612SN/A}
26910405Sandreas.hansson@arm.com
2709611SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS
2718915SN/A
27210405Sandreas.hansson@arm.comBEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigData)
2739612SN/A
2749091SN/A    Param<uint16_t> VendorID;
2759612SN/A    Param<uint16_t> DeviceID;
2769612SN/A    Param<uint16_t> Command;
2779091SN/A    Param<uint16_t> Status;
2789091SN/A    Param<uint8_t> Revision;
27910405Sandreas.hansson@arm.com    Param<uint8_t> ProgIF;
28010405Sandreas.hansson@arm.com    Param<uint8_t> SubClassCode;
2818915SN/A    Param<uint8_t> ClassCode;
2828915SN/A    Param<uint8_t> CacheLineSize;
2838915SN/A    Param<uint8_t> LatencyTimer;
2849715SN/A    Param<uint8_t> HeaderType;
2858915SN/A    Param<uint8_t> BIST;
28610405Sandreas.hansson@arm.com    Param<uint32_t> BAR0;
2878915SN/A    Param<uint32_t> BAR1;
2889612SN/A    Param<uint32_t> BAR2;
2899612SN/A    Param<uint32_t> BAR3;
2909715SN/A    Param<uint32_t> BAR4;
2918915SN/A    Param<uint32_t> BAR5;
2929715SN/A    Param<uint32_t> CardbusCIS;
2939715SN/A    Param<uint16_t> SubsystemVendorID;
29410405Sandreas.hansson@arm.com    Param<uint16_t> SubsystemID;
2959715SN/A    Param<uint32_t> ExpansionROM;
2969612SN/A    Param<uint8_t> InterruptLine;
2979715SN/A    Param<uint8_t> InterruptPin;
2989715SN/A    Param<uint8_t> MinimumGrant;
2999612SN/A    Param<uint8_t> MaximumLatency;
30010405Sandreas.hansson@arm.com    Param<uint32_t> BAR0Size;
3019612SN/A    Param<uint32_t> BAR1Size;
3029091SN/A    Param<uint32_t> BAR2Size;
3038915SN/A    Param<uint32_t> BAR3Size;
3049612SN/A    Param<uint32_t> BAR4Size;
3059612SN/A    Param<uint32_t> BAR5Size;
3068915SN/A
3078915SN/AEND_DECLARE_SIM_OBJECT_PARAMS(PciConfigData)
3088915SN/A
3099031SN/ABEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigData)
31010405Sandreas.hansson@arm.com
3112497SN/A    INIT_PARAM(VendorID, "Vendor ID"),
3129279SN/A    INIT_PARAM(DeviceID, "Device ID"),
3139279SN/A    INIT_PARAM_DFLT(Command, "Command Register", 0x00),
3149279SN/A    INIT_PARAM_DFLT(Status, "Status Register", 0x00),
3159279SN/A    INIT_PARAM_DFLT(Revision, "Device Revision", 0x00),
3169279SN/A    INIT_PARAM_DFLT(ProgIF, "Programming Interface", 0x00),
3179031SN/A    INIT_PARAM(SubClassCode, "Sub-Class Code"),
3189031SN/A    INIT_PARAM(ClassCode, "Class Code"),
3197523SN/A    INIT_PARAM_DFLT(CacheLineSize, "System Cacheline Size", 0x00),
3207523SN/A    INIT_PARAM_DFLT(LatencyTimer, "PCI Latency Timer", 0x00),
3219279SN/A    INIT_PARAM_DFLT(HeaderType, "PCI Header Type", 0x00),
32210405Sandreas.hansson@arm.com    INIT_PARAM_DFLT(BIST, "Built In Self Test", 0x00),
3237523SN/A    INIT_PARAM_DFLT(BAR0, "Base Address Register 0", 0x00),
3247523SN/A    INIT_PARAM_DFLT(BAR1, "Base Address Register 1", 0x00),
3259279SN/A    INIT_PARAM_DFLT(BAR2, "Base Address Register 2", 0x00),
3267523SN/A    INIT_PARAM_DFLT(BAR3, "Base Address Register 3", 0x00),
3274958SN/A    INIT_PARAM_DFLT(BAR4, "Base Address Register 4", 0x00),
3282846SN/A    INIT_PARAM_DFLT(BAR5, "Base Address Register 5", 0x00),
3292846SN/A    INIT_PARAM_DFLT(CardbusCIS, "Cardbus Card Information Structure", 0x00),
3307523SN/A    INIT_PARAM_DFLT(SubsystemVendorID, "Subsystem Vendor ID", 0x00),
3319405SN/A    INIT_PARAM_DFLT(SubsystemID, "Subsystem ID", 0x00),
33210405Sandreas.hansson@arm.com    INIT_PARAM_DFLT(ExpansionROM, "Expansion ROM Base Address Register", 0x00),
3339279SN/A    INIT_PARAM(InterruptLine, "Interrupt Line Register"),
3349279SN/A    INIT_PARAM(InterruptPin, "Interrupt Pin Register"),
3352846SN/A    INIT_PARAM_DFLT(MinimumGrant, "Minimum Grant", 0x00),
3369031SN/A    INIT_PARAM_DFLT(MaximumLatency, "Maximum Latency", 0x00),
33710405Sandreas.hansson@arm.com    INIT_PARAM_DFLT(BAR0Size, "Base Address Register 0 Size", 0x00),
3388849SN/A    INIT_PARAM_DFLT(BAR1Size, "Base Address Register 1 Size", 0x00),
3399031SN/A    INIT_PARAM_DFLT(BAR2Size, "Base Address Register 2 Size", 0x00),
3402846SN/A    INIT_PARAM_DFLT(BAR3Size, "Base Address Register 3 Size", 0x00),
3412846SN/A    INIT_PARAM_DFLT(BAR4Size, "Base Address Register 4 Size", 0x00),
3428849SN/A    INIT_PARAM_DFLT(BAR5Size, "Base Address Register 5 Size", 0x00)
3438849SN/A
34410405Sandreas.hansson@arm.comEND_INIT_SIM_OBJECT_PARAMS(PciConfigData)
3458849SN/A
3463074SN/ACREATE_SIM_OBJECT(PciConfigData)
3473074SN/A{
34810405Sandreas.hansson@arm.com    PciConfigData *data = new PciConfigData(getInstanceName());
3492497SN/A
35010405Sandreas.hansson@arm.com    data->config.vendor = htole(VendorID);
3512497SN/A    data->config.device = htole(DeviceID);
35210405Sandreas.hansson@arm.com    data->config.command = htole(Command);
3539407SN/A    data->config.status = htole(Status);
3549407SN/A    data->config.revision = htole(Revision);
3559279SN/A    data->config.progIF = htole(ProgIF);
3569279SN/A    data->config.subClassCode = htole(SubClassCode);
3579279SN/A    data->config.classCode = htole(ClassCode);
3582846SN/A    data->config.cacheLineSize = htole(CacheLineSize);
3599279SN/A    data->config.latencyTimer = htole(LatencyTimer);
3609279SN/A    data->config.headerType = htole(HeaderType);
3619279SN/A    data->config.bist = htole(BIST);
3629279SN/A
3639279SN/A    data->config.baseAddr0 = htole(BAR0);
3649279SN/A    data->config.baseAddr1 = htole(BAR1);
3659279SN/A    data->config.baseAddr2 = htole(BAR2);
3669279SN/A    data->config.baseAddr3 = htole(BAR3);
3679279SN/A    data->config.baseAddr4 = htole(BAR4);
3689407SN/A    data->config.baseAddr5 = htole(BAR5);
36910405Sandreas.hansson@arm.com    data->config.cardbusCIS = htole(CardbusCIS);
3709279SN/A    data->config.subsystemVendorID = htole(SubsystemVendorID);
3712534SN/A    data->config.subsystemID = htole(SubsystemVendorID);
3729279SN/A    data->config.expansionROM = htole(ExpansionROM);
3739279SN/A    data->config.interruptLine = htole(InterruptLine);
3749279SN/A    data->config.interruptPin = htole(InterruptPin);
3759279SN/A    data->config.minimumGrant = htole(MinimumGrant);
3769032SN/A    data->config.maximumLatency = htole(MaximumLatency);
3779279SN/A
3789279SN/A    data->BARSize[0] = BAR0Size;
3799279SN/A    data->BARSize[1] = BAR1Size;
3807523SN/A    data->BARSize[2] = BAR2Size;
3819279SN/A    data->BARSize[3] = BAR3Size;
3829279SN/A    data->BARSize[4] = BAR4Size;
3839279SN/A    data->BARSize[5] = BAR5Size;
38410405Sandreas.hansson@arm.com
3859279SN/A    return data;
3869279SN/A}
3879279SN/A
3889279SN/AREGISTER_SIM_OBJECT("PciConfigData", PciConfigData)
3899279SN/A
3909279SN/A#endif // DOXYGEN_SHOULD_SKIP_THIS
3919279SN/A