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 §ion) 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