Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / include / pcie.h
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: pcie.h
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
#ifndef _PCIE_NEW_
#define _PCIE_NEW_
#include "module.h"
#include "pci_common.h"
#include <stdlib.h>
#include <assert.h>
// fw declaration
class genericPcieDev;
class genericPcieDevIf;
// Helper PCIE function:
// convert "count" bytes to byte enables.
// assume that count <= 8 and the bytes are
// contiguous
inline uint8_t pcie_countToBe(int count){
uint8_t be = 0;
if(count > 8)
assert(0);
for(int i = 0; i < count; i++)
be |= 1 << i;
return be;
}
enum pcie_space {PCIE_CFG = 0, PCIE_IO, PCIE_MEM, PCIE_MSG, PCIE_NSPACES = 4};
static const char *pcie_space_names[] = {"PCIE_CFG", "PCIE_IO", "PCIE_MEM", "PCIE_MSG", "PCIE_UNKN"};
#define pcie_space2name(space) ((int)space < PCIE_NSPACES ? (pcie_space_names[(int)space]) : "PCIE_UNKN")
static const int busShift = 20;
static const int devShift = 15;
static const int funShift = 12;
enum tlp_orderingAttr { \
defaultOrdering, /* strongly ordered model*/ \
relaxedOrdering /* relaxed ordering model*/
};
enum tlp_snoopAttr { \
snoop, /* hw enforced cache coherency, default */ \
noSnoop /* hw enforced cache cohrencey not expected*/
};
struct tlp_Attr{
tlp_orderingAttr oA;
tlp_snoopAttr sA;
};
enum tlp_trafficClass {
TC0, /* best effort service class, default TC */
TC1, /* differntiated service classes */
TC2,
TC3,
TC4,
TC5,
TC6,
TC7
};
// these attributes are not needed from functional sim viewpoint.
// hence create a struct to bundle them and pass around in functions
// in case anyone ever cares for more.
struct tlp_X{
tlp_Attr ta;
tlp_trafficClass tc;
uint8_t tag; /* unique id used to match request with completion*/
bool TD; /* includes TLP digest ? true:false*/
bool EP; /* is TLP poisoned ? true:false*/
};
static const tlp_X dont_care_attrs = {{defaultOrdering,snoop},TC0,0, false, false};
enum pcieComplStatus { \
// values same as those in completion status of completer TLP
SC = 0x0 /* successful completion */,
UR = 0x1 /* unsupported request */,
CRS =0x2 /* configuration retry request status */,
CA = 0x4 /* completer abort */,
// these values though not returned in Completion packet, can be
// returned by sim models
CMPL_TO, /* completion timeout */
// the bus or endpoint needs to tell the requester
// in this model since no timing is present
CMPL_POISONED, // a completer returns a completion TLP that is poisoned
SIM_OK, /* for posted xactns that do not return completion*/
SIM_FAIL /* status, use these reserved values for internal use */
};
// while handling a TLP, some actions depends upon
// whether the TLP is originated by the device,
// or it has reached the final destination device,
// or is passing through a bridge/switch in the fabric.
// a trasnmitter can be a requester as well, however
// an intermediate bridge cannot be. the same distinction holds
// for completer/receiver
enum pciExpTLPHandler{
requester,
completer,
transmitter,
receiver
};
struct pcieCompleter{
pcieComplStatus status;
uint16_t completerId;
pcieCompleter(pcieComplStatus st, uint16_t cI ){
status=st;
completerId = cI;
}
pcieCompleter(int st, int cI){
status = (pcieComplStatus)st;
completerId = (uint16_t)cI;
}
pcieCompleter(pcieComplStatus st){
status = st;
completerId = 0;
}
pcieCompleter(){
status = SIM_OK;
completerId = 0;
}
};
// addressing mode (either 32 or 64 bit) for memory space access,
// configuration type (either 0 or 1) for configuration accesses
// the space identifier tells which of the fields is valid,
// mem* and conf* are mutually exclusive
enum addrMd_xactnType{
mem_addr32,
mem_addr64,
conf_type0,
conf_type1
};
// message routing methods
enum msgRouting {
routed_to_RC = 0x0, /* RC = root complex */
routed_by_addr = 0x1,
routed_by_id = 0x2,
broadcast_from_RC = 0x3,
local = 0x4, /* terminate at receiver */
gathered_routed_to_RC = 0x5,
invalid_routing
};
#define PCIE_COMPLETER_ID(BUS,DEV,FUN) ((BUS & 0xff) << 8 | (DEV & 0x1f) << 3 | (FUN & 0x7))
#define PCIE_REQUESTER_ID(BUS,DEV,FUN) PCIE_COMPLETER_ID(BUS,DEV,FUN)
//////////// pci express messages //////////////////
// spec defined messages
enum pciExpMsgCode{
/* INTx Mechanism Messages */
MSG_Assert_INTA = 0x20,
MSG_Assert_INTB = 0x21,
MSG_Assert_INTC = 0x22,
MSG_Assert_INTD = 0x23,
MSG_Deassert_INTA = 0x24,
MSG_Deassert_INTB = 0x25,
MSG_Deassert_INTC = 0x26,
MSG_Deassert_INTD = 0x27,
/* Power Management Messages */
MSG_PM_Active_State_Nak = 0x14,
MSG_PM_PME = 0x18,
MSG_PME_Turn_Off = 0x19,
MSG_PME_TO_Ack = 0x1b,
/* error signalling messages*/
MSG_ERR_COR = 0x30,
MSG_ERR_NONFATAL = 0x31,
MSG_ERR_FATAL = 0x32,
/* Locked Transactions Support */
MSG_Unlock = 0x00,
/* Set_Slot_Power_Limit Message */
MSG_Set_Slot_Power_Limit = 0x50,
/* Hot-Plug Signaling Messages */
MSG_Attention_Indicator_On = 0x41,
MSG_Attention_Indicator_Blink = 0x43,
MSG_Attention_Indicator_Off = 0x40,
MSG_Power_Indicator_On = 0x45,
MSG_Power_Indicator_Blink = 0x47,
MSG_Power_Indicator_Off = 0x44,
MSG_Attention_Button_Pressed = 0x48
};
struct pciExpMsgUtility{
private:
struct pciExpMsg{
char * name;
pciExpMsgCode code;
msgRouting routing;
pciExpMsg(const char * n,pciExpMsgCode c,msgRouting r){
name = strdup(n);
code = c;
routing = r;
}
~pciExpMsg(){
if(name)
free(name);
}
};
static const int numMsgs = 24;
pciExpMsg *pciExpMsgDb[numMsgs];
public:
pciExpMsgUtility(){
pciExpMsgDb[0] = new pciExpMsg("Unlock", MSG_Unlock, broadcast_from_RC);
pciExpMsgDb[1] = new pciExpMsg("ERR_COR", MSG_ERR_COR, routed_to_RC);
pciExpMsgDb[2] = new pciExpMsg("ERR_NONFATAL", MSG_ERR_NONFATAL, routed_to_RC);
pciExpMsgDb[3] = new pciExpMsg("ERR_FATAL", MSG_ERR_FATAL, routed_to_RC);
pciExpMsgDb[4] = new pciExpMsg("Assert_INTA", MSG_Assert_INTA, local);
pciExpMsgDb[5] = new pciExpMsg("Assert_INTB", MSG_Assert_INTB, local);
pciExpMsgDb[6] = new pciExpMsg("Assert_INTC", MSG_Assert_INTC, local);
pciExpMsgDb[7] = new pciExpMsg("Assert_INTD", MSG_Assert_INTD, local);
pciExpMsgDb[8] = new pciExpMsg("Deassert_INTA", MSG_Deassert_INTA, local);
pciExpMsgDb[9] = new pciExpMsg("Deassert_INTB", MSG_Deassert_INTB, local);
pciExpMsgDb[10] = new pciExpMsg("Deassert_INTC", MSG_Deassert_INTC, local);
pciExpMsgDb[11] = new pciExpMsg("Deassert_INTD", MSG_Deassert_INTD, local);
pciExpMsgDb[12] = new pciExpMsg("PM_Active_State_Nak", MSG_PM_Active_State_Nak,local);
pciExpMsgDb[13] = new pciExpMsg("PM_PME", MSG_PM_PME, routed_to_RC);
pciExpMsgDb[14] = new pciExpMsg("PME_Turn_Off", MSG_PME_Turn_Off, broadcast_from_RC);
pciExpMsgDb[15] = new pciExpMsg("PME_TO_Ack", MSG_PME_TO_Ack, gathered_routed_to_RC);
pciExpMsgDb[16] = new pciExpMsg("Set_Slot_Power_Limit",MSG_Set_Slot_Power_Limit, local);
pciExpMsgDb[17] = new pciExpMsg("Attention_Indicator_On", MSG_Attention_Indicator_On, local);
pciExpMsgDb[18] = new pciExpMsg("Attention_Indicator_Blink", MSG_Attention_Indicator_Blink, local);
pciExpMsgDb[19] = new pciExpMsg("Attention_Indicator_Off", MSG_Attention_Indicator_Off, local);
pciExpMsgDb[20] = new pciExpMsg("Power_Indicator_On", MSG_Power_Indicator_On, local);
pciExpMsgDb[21] = new pciExpMsg("Power_Indicator_Blink", MSG_Power_Indicator_Blink, local);
pciExpMsgDb[22] = new pciExpMsg("Power_Indicator_Off", MSG_Power_Indicator_Off, local);
pciExpMsgDb[23] = new pciExpMsg("Attention_Button_Pressed", MSG_Attention_Button_Pressed, local);
}
const char * msgCode2name(pciExpMsgCode code){
for(int i = 0; i < numMsgs; i++)
if(code == pciExpMsgDb[i]->code)
return pciExpMsgDb[i]->name;
// programming error ??
//printf("ERROR msgCode2name: no msg code 0x%x registered \n",code);
//assert(0);
return 0;
}
msgRouting msgCode2Routing(pciExpMsgCode code){
for(int i = 0; i < numMsgs; i++)
if(code == pciExpMsgDb[i]->code)
return pciExpMsgDb[i]->routing;
// programming error ??
// printf("ERROR msgCode2Routing: no msg code 0x%x registered \n",code);
// assert(0);
return invalid_routing;
}
};
/////////////// AER //////////////////////////////////////////
enum pciExpAERRegOffset {
UNCORR_ERR_STAT_OFFSET = 4,
UNCORR_ERR_MASK_OFFSET = 8,
UNCORR_ERR_SEVERITY_OFFSET = 0xc,
CORR_ERR_STAT_OFFSET = 0x10,
CORR_ERR_MASK_OFFSET = 0x14,
ADVANCED_ERR_CAPCNTRL_OFFSET = 0x18,
HDR_LOG_OFFSET = 0x1c,
ROOT_ERR_CMD_OFFSET = 0x2c,
ROOT_ERR_STAT_OFFSET = 0x30,
CORR_ERR_SRC_ID_OFFSET = 0x34,
ERR_SRC_ID_OFFSET = 0x36
};
static const int aerUncorrErrBitMask = 0x1ff011;
static const int aerCorrErrBitMask = 0x11c1;
// bit positions of spec defined uncorrectable errors
// relevent to uncorrectable error status/mask/severity registers
enum pciExpAER_ErrBitPos {
uncorr_trng_err_bp = 0,
uncorr_data_lnk_protocol_err_bp = 4,
uncorr_poisoned_tld_bp = 12,
uncorr_flow_cntrl_protocol_err_bp = 13,
uncorr_completion_timeout_bp = 14,
uncorr_completer_abort_bp = 15,
uncorr_unexpexted_completion_bp = 16,
uncorr_receiver_overflow_bp = 17,
uncorr_malformed_tlp_bp = 18,
uncorr_ecrc_err_bp = 19,
uncorr_unsupported_req_bp = 20,
// bit positions of spec defined correctable errors
// relevent to correctable error mask/status register
corr_receiver_err_bp = 0,
corr_bad_tlp_bp = 6,
corr_bad_dllp_bp = 7,
corr_replay_num_rollover_bp = 8,
corr_replay_timer_timeout_bp = 12
};
// errors that can be reported by pci express advanced error reporting.
// include both correctable and non correctable errors.
enum pciExp_Error{
// un-correctable errors // detecting agent
trainingErr, // device
dataLinkProtocolErr, // device
poisonedTLP, // receiver
poisonedDMA, // receiver
flowCntrlProtocolErr, // receiver
completionTimeout, // requester
completerAbort, // completer, sets error bits at both xmiter & receiver
unexpectedCompletion, // receiver. a completion that was not expected.
// reason is problems with routing.
receiverOverflow, // receiver
malformedTLP, // receiver
ecrcErr, // receiver
ecrcDMAErr, // receiver
unsupportedRequest, // sets error bits at both xmiter & receiver
// correctable errors
receiverErr, // detected at receiver
badTLP, // receiver
badDLLP, // receiver
replayNumRollover, // transmitter
replayTimerTimeout // transmitter
};
// pci Express error classification.
// fatal and nonfatal are sub classifications of uncorrectable errors.
enum pciExpErrorType{
errCorrectable,
errUnCorrectable_fatal,
errUnCorrectable_nonfatal
};
class pciExpErrUtility{
private:
struct pciExpErr{
pciExp_Error error;
char * name;
pciExpErrorType dfltErrType;
pciExpMsgCode errMessage;
pciExpAER_ErrBitPos bitpos; // bit position of error in status/mask/severity regs
pciExpErr(pciExp_Error e,const char * n, pciExpErrorType et,pciExpMsgCode em, pciExpAER_ErrBitPos bp ){
error = e;
name = strdup(n);
dfltErrType = et;
errMessage = em;
bitpos = bp;
}
~pciExpErr(){
if(name)
free(name);
}
};
static const int numErr = 16;
pciExpErr * pciExpErrDb[numErr];
public:
pciExpErrUtility(){
pciExpErrDb[0] = new pciExpErr(trainingErr,"traning error",errUnCorrectable_fatal,MSG_ERR_FATAL,uncorr_trng_err_bp);
pciExpErrDb[1] = new pciExpErr(receiverErr,"receiver error",errCorrectable,MSG_ERR_COR,corr_receiver_err_bp);
pciExpErrDb[2] = new pciExpErr(badTLP,"Bad TLP",errCorrectable,MSG_ERR_COR,corr_bad_tlp_bp);
pciExpErrDb[3] = new pciExpErr(badDLLP,"Bad DLLP",errCorrectable,MSG_ERR_COR,corr_bad_dllp_bp);
pciExpErrDb[4] = new pciExpErr(replayTimerTimeout,"Replay Timeout",errCorrectable,MSG_ERR_COR,corr_replay_timer_timeout_bp);
pciExpErrDb[5] = new pciExpErr(replayNumRollover,"Replay NUM rollover",errCorrectable,MSG_ERR_COR,corr_replay_num_rollover_bp);
pciExpErrDb[6] = new pciExpErr(dataLinkProtocolErr,"Data link layer protocol error",errUnCorrectable_fatal,MSG_ERR_FATAL,uncorr_data_lnk_protocol_err_bp);
pciExpErrDb[7] = new pciExpErr(poisonedTLP,"Poisoned TLP received",errUnCorrectable_nonfatal,MSG_ERR_NONFATAL,uncorr_poisoned_tld_bp);
pciExpErrDb[8] = new pciExpErr(ecrcErr,"ECRC check fail",errUnCorrectable_nonfatal,MSG_ERR_NONFATAL,uncorr_ecrc_err_bp);
pciExpErrDb[9] = new pciExpErr(unsupportedRequest,"unsupported request",errUnCorrectable_nonfatal,MSG_ERR_NONFATAL,uncorr_unsupported_req_bp);
pciExpErrDb[10] = new pciExpErr(completionTimeout,"Completion timeout",errUnCorrectable_nonfatal,MSG_ERR_NONFATAL,uncorr_completion_timeout_bp);
pciExpErrDb[11] = new pciExpErr(completerAbort,"Completer abort",errUnCorrectable_nonfatal,MSG_ERR_NONFATAL,uncorr_completer_abort_bp);
pciExpErrDb[12] = new pciExpErr(unexpectedCompletion,"Unexpected completion",errUnCorrectable_nonfatal,MSG_ERR_NONFATAL,uncorr_unexpexted_completion_bp);
pciExpErrDb[13] = new pciExpErr(receiverOverflow,"Receiver overflow",errUnCorrectable_fatal,MSG_ERR_FATAL,uncorr_receiver_overflow_bp);
pciExpErrDb[14] = new pciExpErr(malformedTLP,"malformed TLP",errUnCorrectable_fatal,MSG_ERR_FATAL,uncorr_malformed_tlp_bp);
pciExpErrDb[15] = new pciExpErr(flowCntrlProtocolErr,"Flow control protocol error",errUnCorrectable_fatal,MSG_ERR_FATAL,uncorr_flow_cntrl_protocol_err_bp);
}
const char * error2Name(pciExp_Error e){
for(int i = 0; i < numErr; i++)
if(e == pciExpErrDb[i]->error)
return pciExpErrDb[i]->name;
// programming error ??
// printf("ERROR error2Name: no error code 0x%x registered \n",e);
// assert(0);
return 0;
}
pciExpErrorType error2DfltErrType(pciExp_Error e){
for(int i = 0; i < numErr; i++)
if(e == pciExpErrDb[i]->error)
return pciExpErrDb[i]->dfltErrType;
// programming error ??
// printf("ERROR error2DfltErrType: no error code 0x%x registered \n",e);
// assert(0);
return (pciExpErrorType)-1;
}
pciExpMsgCode error2DfltErrMsg(pciExp_Error e){
for(int i = 0; i < numErr; i++)
if(e == pciExpErrDb[i]->error)
return pciExpErrDb[i]->errMessage;
// programming error ??
// printf("ERROR error2DfltErrMsg: no error code 0x%x registered \n",e);
// assert(0);
return (pciExpMsgCode)-1;
}
pciExpAER_ErrBitPos error2RegBitPos(pciExp_Error e){
for(int i = 0; i < numErr; i++)
if(e == pciExpErrDb[i]->error)
return pciExpErrDb[i]->bitpos;
// programming error ??
// printf("ERROR error2RegBitPos: no error code 0x%x registered \n",e);
// assert(0);
return (pciExpAER_ErrBitPos)-1;
}
};
class pciExpEnhncdCapHdr: public pciConfReg{
public:
static const int pciExpExtCapId_lbp = 15;
static const int pciExpExtCapId_rbp = 0;
static const int pciExpExtCapId_size = 16;
static const int capVersion_lbp = 19;
static const int capVersion_rbp = 16;
static const int capVersion_size = 4;
static const int nxtCapOffset_lbp = 31;
static const int nxtCapOffset_rbp = 20;
static const int nxtCapOffset_size = 12;
static const int capVersion = 1;
pciExpEnhncdCapHdr(uint32_t por_val = capVersion << capVersion_rbp, uint32_t mask = 0x0, void *d = 0, const char * name = "pciExpEnhancedCapHeader") \
: pciConfReg(name,4,por_val, mask, d){}
};
class pciExpAER_UnCorrErrStatReg:public pciConfReg{
public:
pciExpAER_UnCorrErrStatReg(uint32_t por_val = 0x0, uint32_t mask = 0x1ff011, void * d = 0, const char * name = "AdvErrRep-UnCorrErrStatReg") \
: pciConfReg(name, 4, por_val, mask, d){}
uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
assert(bytes_to_write == 4);
assert(byte_offset == 0);
// rw1c register
uint32_t oldval = val;
buf &= mask; // 0 out the ro bits if any in buf
buf = ~buf; // flip the 0's to 1's and vice versa
val &= buf; // and with val so that bits set to 1 are turned off
// bits written to with 0 are unaffected.
if(debug_level >= 2)
printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,oldval,val);
return 4;
}
};
class pciExpAER_CorrErrStatReg: public pciConfReg{
public:
pciExpAER_CorrErrStatReg(uint32_t por_val = 0x0, uint32_t mask = 0x11c1, void * d = 0, const char * name = "AdvErrRep-CorrErrStatReg") \
: pciConfReg(name, 4, por_val, mask, d){}
uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
assert(bytes_to_write == 4);
assert(byte_offset == 0);
// rw1c register
uint32_t oldval = val;
buf &= mask;
buf = ~buf;
val &= buf;
if(debug_level >= 2)
printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,oldval,val);
return 4;
}
};
class pciExpAER_ErrCapCntrlReg: public pciConfReg{
public:
static const int firstErrPointer_lbp = 4;
static const int firstErrPointer_rbp = 0;
static const int firstErrPointer_size = 5;
static const int ecrcGenCapable_bp = 5;
static const int ecrcGenEnable_bp = 6;
static const int ecrcCheckCapable_bp = 7;
static const int ecrcCheckEnable_bp = 8;
pciExpAER_ErrCapCntrlReg(uint32_t por_val = 0x0, uint32_t mask = 0x140, void * d = 0, const char * name = "AdvErrRep-ErrCapCntrlReg")
: pciConfReg(name, 4, por_val, mask, d){}
};
class pciExpAER_RootErrCmdReg:public pciConfReg{
public:
static const int fatal_err_rprtng_enable_bp = 0;
static const int non_fatal_err_rprtng_enable_bp = 1;
static const int corr_err_rprtng_enable_bp = 2;
pciExpAER_RootErrCmdReg(uint32_t por_val = 0x0, uint32_t mask = 0x3, void * d = 0, const char * name = "AdvErrRep-RootErrCmdReg")
: pciConfReg(name, 4, por_val, mask, d){}
};
class pciExpAER_RootErrStatReg: public pciConfReg{
public:
static const int err_cor_recvd_bp = 0;
static const int multi_err_cor_recvd_bp = 1;
static const int err_ftl_nonftl_recvd_bp = 2;
static const int multi_err_ftl_nonftl_recvd_bp = 3;
static const int first_uncorr_fatal_bp = 4;
static const int non_ftl_err_msg_recvd_bp = 5;
static const int ftl_err_msg_recvd_bp = 6;
static const int adv_err_intr_msg_lbp = 31;
static const int adv_err_intr_msg_rbp = 27;
static const int adv_err_intr_msg_size = 5;
pciExpAER_RootErrStatReg(uint32_t por_val = 0x0, uint32_t mask = 0xff, void * d = 0, const char * name = "AdvErrRep-RootErrStatusReg")
:pciConfReg(name, 4, por_val, mask, d){}
uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
assert(bytes_to_write == 4);
assert(byte_offset == 0);
// rw1c register
uint32_t oldval = val;
buf &= mask; // 0 out the ro bits if any in buf
buf = ~buf; // flip the 0's to 1's and vice versa
val &= buf; // and with val so that bits set to 1 are turned off
// bits written to with 0 are unaffected.
if(debug_level >= 2)
printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,oldval,val);
return 4;
}
};
///////////////////////////////////////////////////////////////
// pciexpress specific configuration register definitions.
// register offset in bytes for pci express capability
enum pciExpCapRegOffsets{
PCI_EXP_CAP_ID_OFFSET = 0x0,
PCI_EXP_NXT_CAP_PTR_OFFSET = 0x1,
PCI_EXP_CAP_REG_OFFSET = 0x2,
PCI_EXP_DEV_CAP_OFFSET = 0x4,
PCI_EXP_DEV_CTRL_OFFSET = 0x8,
PCI_EXP_DEV_STAT_OFFSET = 0xa,
PCI_EXP_LINK_CAP_OFFSET = 0xc,
PCI_EXP_LINK_CONT_OFFSET = 0x10,
PCI_EXP_LINK_STAT_OFFSET = 0x12,
PCI_EXP_SLOT_CAP_OFFSET = 0x14,
PCI_EXP_SLOT_CTRL_OFFSET = 0x18,
PCI_EXP_SLOT_STAT_OFFSET = 0x1a,
PCI_EXP_ROOT_CTRL_OFFSET = 0x1c,
PCI_EXP_RSVDP_OFFSET = 0x1e,
PCI_EXP_ROOT_STAT = 0x20
};
static const int pciExpCapSize = 0x24; // in bytes
// pciexpress capability registers.
static const int pciExpressCapId = 0x10;
class pciExpCapReg:public pciConfReg{
public:
static const int capVersion_val = 1;
static const int capVersion_lbp = 3;
static const int capVersion_rbp = 0;
static const int capVersion_size = 4;
static const int devPortType_lbp = 7;
static const int devPortType_rbp = 4;
static const int devPortType_size = 4;
enum devPortType_val {
pci_exp_end_pnt = 0x0,
pci_exp_leg_end_pnt = 0x1,
pci_exp_root_port = 0x4,
pci_exp_swtch_upstrm_prt = 0x5,
pci_exp_swtch_dwnstrm_prt = 0x6,
pci_exp_to_pci_x_bridge = 0x7,
pci_x_to_pci_exp_bridge = 0x8
};
static const int slotImpl_bp = 8;
// if 1 then device is either
// a) root port of pcie root complex
// b) dwnstrm port of pcie swtch
static const int intrMsgNo_lbp = 13;
static const int intrMsgNo_rbp = 9;
static const int intrMsgNo_size = 4;
pciExpCapReg(uint16_t por_val = 0, uint16_t mask = 0x0, void * d = 0, const char * name = "pcieExpCapReg")\
:pciConfReg(name,2,por_val,mask,d){} // size = 2, RO.
// a read only register. models can use the base class getBit,setBit and
// get-setRange() with the const defintions above to r/w individual fields
};
class pciExpDevCapReg:public pciConfReg{
public:
static const int maxPayload_lbp = 2;
static const int maxPayload_rbp = 0;
static const int maxPayload_size = 3;
enum maxPayload_val {
s128 = 0x0,
s256 = 0x1,
s512 = 0x2,
s1k = 0x3,
s2k = 0x4,
s4k = 0x5
};
static const int phantomFunc_lbp = 4;
static const int phantomFunc_rbp = 3;
static const int phantomFunc_size = 2;
enum phantomFunc_val {
Pf_0 = 0x0, // no phantom functions
Pf_4 = 0x1, // first msb of function # used for phantom functions, 4 available
Pf_6 = 0x2, // 2 msbs of function # used for phantom functions, 6 available,
Pf_8 = 0x3 // all (3) bits of function # used for phantom functions, 8 available
};
static const int extendedTag_bp = 5;
// 0 => 5 bit tag support
// 1 => 8 bit '' ''
static const int endPntL0sLat_lbp = 8;
static const int endPntL0sLat_rbp = 6;
static const int endPntL0sLat_size = 3;
enum endPntL0sLat_val {
l0_lat_64ns = 0x0, // < 64ns
l0_lat_64_128ns = 0x1, // 64 ns to < 128ns
l0_lat_128_256ns = 0x2, // 128ns to < 256ns
l3_lat_256_512ns = 0x3, // 256ns to < 512ns
l0_lat_512ns_1us = 0x4, // 512ns to < 1us
l0_lat_1us_2us = 0x5, // 1us to < 2us
l0_lat_2us_4us = 0x6, // 2us to 4us
l0_lat_4us = 0x7 // > 4us
};
static const int endPntL1Lat_lbp = 9;
static const int endPntL1Lat_rbp = 11;
static const int endPntL1Lat_size = 3;
enum endPntL1Lat_val {
l1_lat_1us = 0x0, // < 1us
l1_lat_1_2us = 0x1, // 1us to < 2us
l1_lat_2_4us = 0x2, // 2us to < 4us
l1_lat_4_8us = 0x3, // 4us to < 8us
l1_lat_8_16us = 0x4, // 8us to < 16us
l1_lat_16_32us = 0x5, // 16us to < 32us
l1_lat_32_64us = 0x6, // 32us to 64us
l1_lat_64us = 0x7 // > 64us
};
static const int attnBtnPrsnt_bp = 12;
// valid for the following devices only:
// pcie endpoint
// legacy pcie endpoint
// upstrm port of pcie swtch
// pcie to pci/pcix bridge
static const int attnIndPrsnt_bp = 13;
// valid for same devices as for attention button present bit
static const int pwrIndPrsnt_bp = 14;
// same devices as above
static const int capturedSltPwrLmtVal_lbp = 25;
static const int capturedSltPwrLmtVal_rbp = 18;
static const int capturedSltPwrLmtVal_size = 8;
static const int capturedSltPwrLmtSz_lbp = 27;
static const int capturedSltPwrLmtSz_rbp = 26;
static const int capturedSltPwrLmtSz_size = 2;
pciExpDevCapReg(uint32_t por_val, uint32_t mask = 0, void * d = 0, const char * name = "pcieDevCapReg")\
:pciConfReg(name,4,por_val,mask, d){} // size 4 bytes, RO reg
};
class pciExpDevCntrlReg:public pciConfReg{
public:
static const int corrErrRepEn_bp = 0;
static const int nonFatalErrRepEn_bp = 1;
static const int fatalErrRepEn_bp = 2;
static const int unsprtdReqRepEn_bp = 3;
static const int rlxdOrdrEn_bp = 4;
static const int maxPaylodSz_lbp = 7;
static const int maxPaylodSz_rbp = 5;
static const int maxPaylodSz_size = 2;
enum maxPaylodSz_val {
Pls_128b = 0, // 128b
Pls_s256b = 1, // 256b
Pls_s512b = 2, // 512b
Pls_s1k = 3, // 1k
Pls_s2k = 4, // 2k
Pls_s4k = 5 // 4k
};
static const int extTagFldEn_bp = 8;
static const int phntmFuncEn_bp = 9;
static const int auxPwrPMEn_bp = 10;
static const int noSnpEn_bp = 11;
static const int maxRdReqSz_lbp = 14;
static const int maxRdReqSz_rbp = 12;
static const int maxRdReqSz_size = 3;
enum maxRdReqSz_val {
Rrs_128b = 0, // 128b
Rrs_256b = 1, // 256b
Rrs_512b = 2, // 512b
Rrs_1k = 3, // 1k
Rrs_2k = 4, // 2k
Rrs_4k = 5 // 4k
};
// default por val = 0b 0000 1000 1000 0000 = 0x0880
pciExpDevCntrlReg(uint16_t por_val = 0x0880, uint16_t mask = 0x7fff, void * d = 0, const char * name = "pcieDevCapReg")\
:pciConfReg(name, 2, por_val, mask, d){} // size = 2
};
class pciExpDevStatReg: public pciConfReg{
public:
static const int corrErrDet_bp = 0; // rw1c
static const int nonFtlErrDet_bp = 1; // rw1c
static const int ftlErrDet_bp = 2; // rw1c
static const int unSprtdReqDet_bp = 3; // rw1c
static const int auxPwrSel_bp = 4; // ro
static const int xactnPndng_bp = 5; // ro
pciExpDevStatReg(uint16_t por_val = 0, uint16_t mask = 0x000f, void *d = 0, const char * name = "pcieDevStatReg")\
:pciConfReg(name, 2, por_val, mask, d){} // size = 2.
uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
assert(bytes_to_write == 2); // if fails, write a more generic functions like in
// the base class
uint32_t oldval = val;
buf &= mask; // 0 out the ro bits if any in buf
buf = ~buf; // flip the 0's to 1's and vice versa
val &= buf; // and with val so that bits set to 1 are turned off
// bits written to with 0 are unaffected.
if(debug_level >= 2)
printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,oldval,val);
return 2;
}
// NOTE models would use setBit etc to set the bits in this reg, not the write
// function. this function is for the s/w use
};
class pciExpLnkCapReg: public pciConfReg{
public:
static const int maxLnkSpeed_lbp = 3;
static const int maxLnkSpeed_rbp = 0;
static const int maxLnkSpeed_size = 4;
static const int maxLnkSpeed_val = 1; // 2.5 Gb/s, all other values are reserved
static const int maxLnkWdth_lbp = 9;
static const int maxLnkWdth_rbp = 4;
static const int maxLnkWdth_size = 6;
enum maxLnkWdth_val {
x1 = 1,
x2 = 2,
x4 = 4,
x8 = 8,
x12 = 12,
x16 = 16,
x32 = 32
};
// ASPM support
static const int actvStatePwrMgmt_lbp = 11;
static const int actvStatePwrMgmt_rbp = 10;
static const int actvStatePwrMgmt_size = 2;
enum actvStatePwrMgmt_val {
L0s_supported = 1,
L0s_and_L01_supported = 3
};
static const int L0sExitLat_lbp = 14;
static const int L0sExitLat_rbp = 12;
static const int L0sExitLat_size = 3;
enum L0sExitLat_val {
L0el_64ns = 0,
L0el_64_128ns = 1,
L0el_128_256ns = 2,
L0el_256_512ns = 3,
L0el_512_1us = 4,
L0el_1_2us = 5,
L0el_2_4us = 6,
L0el_4us = 7 // > 4us
};
static const int L1ExitLat_lbp = 17;
static const int L1ExitLat_rbp = 15;
static const int L1ExitLat_size = 3;
enum L1ExitLat_val {
L1el_1us = 0,
L1el_1_2us = 1,
L1el_2_4us = 2,
L1el_4_8us = 3,
L1el_8_16us = 4,
L1el_16_32us = 5,
L1el_32_64us = 6,
L1el_64us = 7 // > 64us
};
// port number for this pcie port
static const int portNo_lbp = 31;
static const int portNo_rbp = 24;
static const int portNo_size = 8;
// default por_val = 0x00000411
// 2,5 Gb/s x1 link, l0s_exit_lat<64ns, ;1exitLat < 1us,
// port = 0, l0s supported
pciExpLnkCapReg(uint32_t por_val = 0x411, uint32_t mask = 0, void * d = 0, const char * name = "pcieLnkCapReg")\
:pciConfReg(name, 4, por_val, mask,d){} // ro 4 byte reg
};
class pciExpLnkCntrlReg: public pciConfReg{
public:
static const int aspmCntrl_lbp = 1;
static const int aspmCntrl_rbp = 0;
static const int aspmCntrl_size = 2;
enum aspmCntrl_val {
aspm_disabled = 0,
l0s_enabled = 1,
l1_enabled = 2,
l0_l1_enabled = 3
};
static const int rcb_bp = 3;
// root_ports 0 = 64byte, 1 = 128 byte, RO
// endpoints 0 = 64byte, 1 = 128 byte, RW
// switch ports, RO, hardwire to 0
static const int lnkDisable_bp = 4;
// if 1, link is disabled.
static const int lnkRetrain_bp = 5;
// always reads 0., RW
static const int commonClkConf_bp = 6;
static const int extendedSynch_bp = 7;
pciExpLnkCntrlReg(uint16_t por_val, uint16_t mask = 0xff, void * d= 0, const char * name = "pcieLinkCntrlReg") \
:pciConfReg(name, 2, por_val, mask, d){} //mask = 0xff
};
class pciExpLnkStatReg: public pciConfReg{
public:
static const int lnkSpeed_lbp = 3;
static const int lnkSpeed_rbp = 0;
static const int lnkSpeed_size = 4;
static const int lnkSpeed_val = 1; // 2.5 Gb/s, RO
static const int lnkWdth_lbp = 9;
static const int lnkWdth_rbp = 4;
static const int lnkWdth_size = 6;
enum lnkWdth_val {
x1 = 1,
x2 = 2,
x4 = 4,
x8 = 8,
x16 = 16,
x32 = 32
};
static const int trainingError_bp = 10; // 1 if an error occurred during link training
static const int lnkTraining_bp = 11; // if 1 means link traning is in progress, hw
// clears this bit on completion
static const int slot_ClkConf_bp = 12; // indicates if 1 that the component uses the
// same clock as platform
pciExpLnkStatReg(uint16_t por_val = 0x1011, uint16_t mask = 0, void * d = 0, const char * name = "pcieLinkStatReg") \
:pciConfReg(name,2,por_val,mask,d){} // size = 2, RO reg.
// por_val is for link speed = 2.5Gb/s, link wodth = X1
// no training error, no traning in progress, same reference clock as platform
};
class pciExpSlotCapReg: public pciConfReg{
public:
static const int attnBtnPrsnt_bp = 0;
static const int attnCntrlPrsnt_bp = 1;
static const int mrlSensorPrsnt_bp = 2;
static const int attnIndPrsnt_bp = 3;
static const int pwrIndPrsnt_bp = 4;
static const int hotPlugSurprise_bp = 5;
static const int hotPlugCapable_bp = 6;
static const int slotPwrLmtVal_lbp = 7;
static const int slotPwrLmtVal_rbp = 14;
static const int slotPwrLmtVal_size = 8;
static const int slotPwrLmtScale_lbp = 16;
static const int slotPwrLmtScale_rbp = 15;
static const int slotPwrLmtScale_size = 2;
static const int physSlotNum_lbp = 31;
static const int physSlotNum_rbp = 19;
static const int physSlotNum_size = 13;
pciExpSlotCapReg(uint32_t por_val = 0x0, uint32_t mask = 0, void * d = 0, const char * name = "pcieSlotCapReg") \
:pciConfReg(name, 4, por_val, mask, d){}
// RO register. however writes to some fields cause messages to be sent.
// hence the write method needs to be overriden
};
class pciExpSlotCntrlReg: public pciConfReg{
public:
static const int attnBtnPressEn_bp = 0;
static const int pwrFaultDetEn_bp = 1;
static const int mrlSensorChngEn_bp = 2;
static const int prescDetChngEn_bp = 3;
static const int commdCompIntEn_bp = 4;
static const int hotPlugIntEn_bp = 5;
static const int attnIndCntrl_lbp = 7;
static const int attnIndCntrl_rbp = 6;
static const int attnIndCntrl_size = 2;
enum attnIndCntrl_val {
attnInd_on = 1,
attnInd_blink = 2,
attnInd_off = 3
};
static const int pwrIndCntrl_lbp = 9;
static const int pwrIndCntrl_rbp = 8;
static const int pwrIndCntrl_size = 2;
enum pwrIndCntrl_val {
pwrIndCntrl_on = 1,
pwrIndCntrl_blink = 2,
pwrIndCntrl_off = 3
};
static const int pwrCntrlerCntrl_bp = 10;
// 0 - power on, 1 power off
pciExpSlotCntrlReg(uint16_t por_val = 0x3c0, uint16_t mask = 0x0fff, void * d = 0, const char * name = "pcieSlotContrlReg") \
:pciConfReg(name, 2, por_val, mask, d){}
// por val has lights off, power on
// some writes generate an interrupts.
// hence the write method may need to be over-ridden
};
class pciExpSlotStatReg: public pciConfReg{
public:
static const int attnBtnPrsd_bp = 0;
static const int pwrFltDet_bp = 1;
static const int mrlSnsrChngd_bp = 2;
static const int prsnceDetChng_bp = 3;
static const int cmdCmplt_bp = 4;
static const int mrlSnsrState_bp = 5;
static const int prsnceDetState_p = 6;
pciExpSlotStatReg(uint16_t por_val = 0x0, uint16_t mask = 0xf, void * d = 0, const char * name = "pcieSlotStatReg") \
:pciConfReg(name, 2, por_val, mask, d){} // size 2, lowest nibble writable as w1c
uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
assert(bytes_to_write == 2); // if fails, write a more generic functions like in
// the base class
uint32_t oldval = val;
buf &= mask; // 0 out the ro bits if any in buf
buf = ~buf; // flip the 0's to 1's and vice versa
val &= buf; // and with val so that bits set to 1 are turned off
// bits written to with 0 are unaffected.
if(debug_level >= 2)
printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,oldval,val);
return 2;
}
};
class pciExpRootCntrlReg: public pciConfReg{
public:
static const int sysErrOnCorrErrEn_bp = 0;
static const int sysErrOnNonFtlErrEn_bp = 1;
static const int sysErrOnFtlErrEn_bp = 2;
static const int pmeIntrEn_bp = 3;
pciExpRootCntrlReg(uint16_t por_val = 0x0, uint16_t mask = 0xf, void * d = 0, const char * name = "pcieRootCntrlReg") \
: pciConfReg(name, 2, por_val, 0xf, d){} // mask=0xf rw bits
};
class pciExpRootStatReg: public pciConfReg{
public:
static const int pmeReqId_lbp = 15;
static const int pmeReqId_rbp = 0;
static const int pmeReqId_size = 16;
static const int pmeStat_bp = 16;
static const int pmePending_bp = 17;
pciExpRootStatReg(uint32_t por_val = 0, uint32_t mask = 0x10000, void * d = 0, const char * name = "pcieRootStatReg") \
: pciConfReg(name, 4, por_val, mask, d){}
// bit 16 is rw1c. over-ride the write function
};
//////////////////////////////////////
// MSI 2.3 related regs.
static const int msiCapId = 0x5;
// relative offsets from start of capability structure
enum pciMsiCapRegOffsets{
MSI_CAPID_OFFSET = 0,
MSI_NEXTPTR_OFFSET = 1,
MSI_MSGCNTRL_OFFSET = 2,
MSI_MSGADDR0_OFFSET = 4,
MSI_MSGADDR1_OFFSET = 8,
MSI_MSGDATA32_OFFSET = 8,
MSI_MSGDATA64_OFFSET = 0xc
};
class msiCapMsgCntrl: public pciConfReg{
public:
static const int is64bitAddrCapable_bp = 7;
static const int multiMsgEn_lbp = 6;
static const int multiMsgEn_rbp = 4;
static const int multiMsgEn_size = 3;
enum multiMsgEn_val {
msgEn1 = 0,
msgEn2 = 1,
msgEn4 = 2,
msgEn8 = 3,
msgEn16 = 4,
msgEn32 = 5
};
static const int multiMsgCapable_lbp = 3;
static const int multiMsgCapable_rbp = 1;
static const int multiMsgCapable_size = 3;
enum multiMsgCapable_val {
msgCap1 = 0,
msgCap2 = 1,
msgCap4 = 2,
msgCap8 = 3,
msgCap16 = 4,
msgCap32 = 5
};
static const int msiEnable_bp = 0;
msiCapMsgCntrl(uint16_t por_val = 0, uint16_t mask = 0xf1, void* d = 0, const char * name = "pciMsiMsgCapCntrlReg") \
: pciConfReg(name, 2, por_val, mask, d){}
};
class pcieCommandReg:public pciConfReg{
//command register reset value is 0. Device specific model should set
//the write mask for this register, so that the probing software can determine
//the capabilities of the device. in general if a device does not support
//a particular feature/operation, the corresponding mask bit should be set
//to 0 to disable writes.
/*
bit # Function
0 Control I/O space response. Devices that do not support
i/o access must h/w this bit to 0, ie bit 0 of write mask is 0
1 Control memory space access.
2 Control a devices ability to act as master. Devices that do
not generate PCI accesses must hardwire this bit to 0
6 Controls devices response to parity errors
8 controls SERR#
10 interrupt disable
all other bits are either reserved or RDONLY hardwired to 0
reference:pcie spec rev 10.2
*/
public:
enum commandRegBits {IO_SPACE = 0, MEM_SPACE = 1, BUS_MASTER = 2,
PARITY_ERR_EN = 6, SERR_ENABLE = 8, INTR_DIS = 10};
pcieCommandReg(const char * name, genericPcieDev * d, uint16_t write_mask,uint16_t val=0):\
pciConfReg(name,2,val,write_mask & 0x547, (void *)d){
if(d == 0){
printf("pcie command reg constructor error: must provide genericPcieDev device pointer\n");
return;
}
}
virtual uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write);
private:
//try to map/unmap all the base registers if they map pci space 'spc'
void mapSpace(pcie_space spc);
void unMapSpace(pcie_space spc);
};
class pcieStatusReg:public pciConfReg{
//status register provides additional information about a devices
//capabilities. This register may not be 0 at reset. A device must
//provide the initial value of this register at reset, as well as the mask
//describing writable bits. this register is RW1C
//devices set the writable bits to indicate abnormal conditions during xactns.
public:
enum statusRegBits{ INTR_STAT = 0x3, MASTER_DATA_PARITY_ERROR = 0x8,\
SIGNALED_TARGET_ABORT = 0xb, RECEIVED_TARGET_ABORT = 0xc, RECEIVED_MASTER_ABORT = 0xd, \
SIGNALED_SYSTEM_ERROR = 0xe, DETECTED_PARITY_ERROR = 0xf};
pcieStatusReg(const char * name, genericPcieDev * d, uint16_t init_val, uint16_t write_mask): \
pciConfReg(name,2,init_val, write_mask & 0xf900 ,d){
if(d == 0){
printf("pcie status reg constructor error: must provide genericPcieDev device pointer\n");
return;
}
}
uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
assert(bytes_to_write == 2);
uint32_t oldval = val;
// if fails, write a more generic function in here.
buf &= mask; // 0 out the ro bits if any in buf
buf = ~buf; // flip the 0's to 1's and vice versa
val &= buf; // and with val so that bits set to 1 are turned off
// bits written to with 0 are unaffected.
if(debug_level >= 2)
printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,oldval,val);
return 2;
}
};
class pcieBaseAddrReg:public pciConfReg{
/*
Format of BAR - - -
I/O space bit 0 - hardwired to 1
bit 1 - reserved, hardwired to 0
memory space bit 0 - hardwired to 0
bit [2,1] - 00 => locate anywhere in 32 bit address space
- 01 => reserved
- 10 => locate anywhere in 64 bit address space
- 11 => reserved
bit 3 - hardwired to 1 if device memory space has no side
effects on reads and host bridge can merge writes
into this range. (ie prefetchable)
*/
public:
bool isPrefetchable; //if memory then prefetchable or not?
uint32_t val_32To63; //upper 32 bits in case of 64 bit reg
uint32_t mask_32To63; //mask " " " " " " etc
uint64_t mapSize;
bool isMapped;
uint64_t oldVal;
pcie_space space;
int bartype;
static const int IO = 0x1; //0001
static const int MEM32 = 0x0; //0000
static const int MEM64 = 0x4; //0100
static const int PREFETCH = 0x8; //1000
public:
//constructor: default is mem32, non-prefetchable mapping
pcieBaseAddrReg(const char * name, genericPcieDev * d,uint64_t spaceSize,pcie_space space , bool ismem32 = true, bool isPrefetchable = false);
virtual uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write);
uint8_t read(uint32_t *buf, uint8_t bytes_to_read, uint8_t byte_offset,uint8_t buf_offset){
if(byte_offset <= 3)
return pciConfReg::read(buf,bytes_to_read,byte_offset,buf_offset);
// return the bytes in buf. 'bytes_to_read' bytes are filled in from (char*)buf + buf_offset
// w/0 affecting the other bytes in *buf.
byte_offset -= 4;
uint8_t bytes_read = (4 - byte_offset) >= bytes_to_read ? bytes_to_read: 4 - byte_offset;
uint64_t byte_mask = (~ ((uint64_t) -1 << bytes_read * 8));//eg for bytes_read=1, mask = 0xff
*buf = (*buf & ~(byte_mask << buf_offset * 8)) | (val_32To63 >> byte_offset * 8 & byte_mask) << buf_offset * 8;
return bytes_read;
}
virtual void print(){
printf("name <%s>, size<%x>", name,size);
if(size == 8)
printf("value <%lx %lx>, mask <%lx %lx>",val_32To63,val,mask_32To63, mask);
else
printf("value <%lx>, mask <%lx>",val,mask);
printf(" Space<%s>Size<%llx>\n",pcie_space2name(space),mapSize);
}
void reMap();
bool map();
bool unmap();
};
// interface functions that need to be supported by a pcie bus.
class pcieBusIf{
public:
// set the bridge interface for this bus
virtual void setBridgeIf(genericPcieDevIf *) = 0;
virtual int busif_getBusno() = 0;
// return bus number for this bus (query from the bridge). this is the secondary
// bus number register in the upstream bridges conf space header.
virtual bool busif_map(const char * devName, pcie_space, uint64_t base, uint64_t size) = 0;
// map a device into 32 bit IO or 64 bit memory space
virtual bool busif_unmap(const char * devName, pcie_space, uint64_t base) = 0;
// unmap a particular address space
virtual bool busif_addDevice(const char * devName, int dev, int fun) = 0;
// add device into internal data structures. add it to PCIE_CONF space as well.
virtual bool busif_deleteDevice(const char * devName) = 0;
// delete device from all the address maps.
virtual bool dump(const char * dir, const char* file) = 0;
virtual bool restore(const char * dir, const char* file) = 0;
virtual mmi_instance_t getDevInstance(int dev,int fun) = 0;
// NOTE1: no interrupt interface is present since only MSIs are used which are normal MEM writes
// OR, INTx emulation is done using writes in MSG space.
// NOTE2: no dma function is present either. The dma would be done by routing normal MEM writes
// from downstream devices to the bridge upstream.
// the following 2 functions can be used by devices to access other devices/functions
// under the pcie bus
// access the mem, io, conf space addresses under this bus hierarchy.
virtual pcieCompleter busif_access(pcie_space, bool wr, uint64_t addr, void * data, \
uint16_t length, uint8_t be, uint16_t reqId, addrMd_xactnType addr64,SAM_DeviceId* samId = 0, tlp_X args = dont_care_attrs ) = 0;
// addr is a 64 bit flat address into one of the mem/io/conf spaces.
// the bus would call one of the devif functions based upon the space.
virtual pcieCompleter busif_msgAccess(uint8_t messageCode, msgRouting route, uint16_t reqId, SAM_DeviceId *samId = 0, \
uint64_t tarIdOrAddr = 0x0, /*msg tlp*/ \
void * data = 0, uint16_t length = 0, /* msgd tlp*/ \
uint16_t vendor = 0x0, uint32_t vendor_data = 0x0, tlp_X args = dont_care_attrs ) = 0; /* vendor defined msg*/
// msgs are posted xactns, hence return SIM_* values only
/* NOTES:
1) the bus should forward all unmapped xactns to upstream bridge
interface.
2) the byte enables should never be non-contiguous in func sim model,
because no write merging, etc is ever done.
*/
};
// interface functions that can be called by bus.
class genericPcieDevIf{
public:
virtual const char *devif_getBusName()=0;
virtual int devif_getDevice()=0;
virtual int devif_getFunction() = 0;
virtual mmi_instance_t devif_getInstance()=0;
virtual const char *devif_getName()=0;
virtual pcieCompleter devif_memAccess(bool wr, uint64_t addr, addrMd_xactnType mode, void * data,\
uint16_t length, uint8_t be, uint16_t reqId, tlp_X args = dont_care_attrs, SAM_DeviceId* samId = 0) = 0;
// 'data' is a byte array where, the lowest addressed byte goes to
// lowest addressed memory location ie (uint8_t*)data[0] <=> (uint8_t*)addr[0].
// for all the accesses(mem, io, conf)
// uint8_t* data corrsponds to byte-enable bit0
// uint8_t* data + 1 corresponds to byte-enable bit1, and so on
// since pcie is endian neutral, no byte swap will be done anywhere.
// the length of the byte array will be length * 4
// 'length' is in number of doublewords(DW = 4 bytes).
// 'be' is the byte enable mask for last and first DW.
// in case of less than 4 byte r/w, the byte enable specify which
// particular byte to read/write (not length).
virtual pcieCompleter devif_ioAccess(bool wr, uint32_t addr, void * data, uint8_t be, uint16_t reqId, \
uint16_t length = 1, tlp_X args = dont_care_attrs, SAM_DeviceId * samId = 0) = 0;
// only 32 bit addressing.
// only 4 bytes of maximum data access,
// length has to be 1, if not then error condition.
// args have to be default args, if not, error condition.
// 'be' should 0000xxxxb.
virtual pcieCompleter devif_msgAccess(uint8_t messageCode, msgRouting route, uint64_t tarIdOrAddr, uint16_t reqId, /*msg tlp*/ \
void * data = 0, uint16_t length = 0, /* msgd tlp*/ \
uint16_t vendorId = 0x0, uint32_t vendor_data = 0x0, tlp_X args = dont_care_attrs, SAM_DeviceId* samId = 0) = 0; /* vendor defined msg*/
// address routing though supported is not used aywhere in pcie spec msg descr.
// tarIdOrAddr field either encodes a 16 bit target id or a 64 bit address. route determines
// which meaning is being used
// posted xactns, hence return SIM_* values only
// route and tarIdOrAddr is needed at device level because further routing may be done by the
// intermediate bridge device in a hierarchy
virtual pcieCompleter devif_confAccess(bool wr, uint32_t offset, void * data, \
uint8_t be, uint16_t reqId, addrMd_xactnType tType = conf_type0, uint16_t length = 1, tlp_X args = dont_care_attrs,\
SAM_DeviceId *samId = 0) = 0;
// 'regNo' is the 12 bit register number (offset into confSpace).
// 'be' must be 0000xxxxb.
// 'length' should be 1, if not, an error condition.
// 'args' should be don't care defaults , else an error.
// NOTE: bridges should forward the conf access accordingly when a type1 conf request is received.
virtual void devif_confAccessCb(bool wr, uint64_t offset, uint8_t be=0xf) = 0;
// non pure functions to be over-ridden only by bridges/root complexes
virtual bool devif_isBridge(){return false;}
virtual bool devif_isRootCmplx(){return false;}
// this function should return the value of secondary bus number
// from conf space header. this is the "bus number" of the bus
// connected to the downstream side of this bridge.
virtual int devif_getBusNo(){return -1;}
// return the primary bus number of the bridge device.
virtual int devif_getPriBusNo(){return -1;}
// return subordinate bus # under the hierarchy originating from this bridge
virtual int devif_getSubBusNo(){return -1;}
// NOTE1: need these bus functions because the values are programmable by s/w
// and can change anytime. Hence they should always be read from the config regs.
// NOTE2: there is no seperate bridge interface. A bridge exports
// the interface defined by this class.
// NOTE3: A bridge shall map in the space of devices below its hierarchy into the
// primary bus (map the range in membase/limit, iobase/limit registers etc).
// The bus shall call the appropriate space access function.
// the address can distinguish whether the access is to bridge internal space
// or to downstream devices
};
// forward declarations
class genericPcieDev:public genericPcieDevIf, pciDebug{
public:
const char * busName; /*upstream bus if any*/
pcieBusIf * busIf; /*upstream busif*/
int device;
int function;
pciConfSpace * confSpace;
bool mapSpace(pcie_space, uint64_t base, uint64_t size);
bool unmapSpace(pcie_space, uint64_t base);
/* (un)map address range for IO/MEM space */
/* NOTE : CONF space gets mapped during busif_addDevice() */
//pci bus exported functions
const char *devif_getBusName() { return busName;}
int devif_getDevice() { return device;}
int devif_getFunction() { return function;}
//functions to be called by specific device implementation
//to allow parsing of busName and attach to pcie bus, at right points of time.
// these functions are implemented by this class
bool dev_parse_arg(const char *arg); /*to be called from Module::parse_args()*/
bool dev_check_args(); /*to be called from Module::check_arg()*/
bool dev_module_added(const char *bus_name);/*to be called from Module::module_added()*/
bool dev_module_deleted(const char *target_name);/*to be called from Module::module_deleted()*/
void dev_init_done(int debug_level); /*to be called from Module::init_done()*/
// should be called from Module::dump(restore)
bool dump(const char * dump_dir,const char *dump_file);
bool restore(const char * dump_dir, const char *dump_file);
pcieCompleter devif_memAccess(bool wr, uint64_t addr, addrMd_xactnType mode, void * data,\
uint16_t length, uint8_t be, uint16_t reqId, tlp_X args, SAM_DeviceId* samId);
pcieCompleter devif_ioAccess(bool wr, uint32_t addr, void * data, uint8_t be, uint16_t reqId,\
uint16_t length, tlp_X args, SAM_DeviceId *samId);
pcieCompleter devif_msgAccess(uint8_t messageCode, msgRouting route, uint64_t tarIdOrAddr, uint16_t reqId,/*msg tlp*/ \
void * data, uint16_t length, /* msgd tlp*/ \
uint16_t vendorId, uint32_t vendor_data, tlp_X args, SAM_DeviceId *samId); /* vendor defined msg*/
pcieCompleter devif_confAccess(bool wr, uint32_t offset, void * data, \
uint8_t be,uint16_t reqId, addrMd_xactnType tType, uint16_t length, tlp_X args,SAM_DeviceId * samId);
genericPcieDev(confHeaderType htype);
genericPcieDev();
// print info about config space registers, etc.
void pcieDevInfo();
// return the bus,dev,fun id for this module.
// this could work as either completer id or requester id
uint16_t getId(){ return PCIE_REQUESTER_ID(busIf->busif_getBusno(), device, function);}
pciExpMsgUtility *msgDB;
pciExpErrUtility *errDB;
void initPciConfSpace(confHeaderType); // provide a default initialization
// for some conf regs based upon header type
uint16_t pciExpCapOffset;
uint16_t msiCapOffset;
uint16_t aerCapOffset;
bool aerCapable;
bool msiEnabled(){
msiCapMsgCntrl * r;
if(r = dynamic_cast<msiCapMsgCntrl*>(confSpace->getConfReg(msiCapOffset + MSI_MSGCNTRL_OFFSET)))
return r->getBit(msiCapMsgCntrl::msiEnable_bp);
else
return false;
}
void addMsiCap(uint8_t next_ptr, uint16_t offset, uint16_t msiCapMsgCntrl_reset_val = 0);
// add pci2.3 Msi Capability registers to the configuration header
// next_ptr - next capability offset
// offset - byte offset where to add the regs,
// reset_val is the the reset value of this register. tells whether it is 64 bit addr
// capable and the number of messages requested
// utility function. route a predefined pci express message.
// does not include messages with TLP or vendor defined mesages.
// also no messgags with id or address routing are accepted.
// these messages should be sent using the busif_msgAccess directly
pcieCompleter routeMsg(pciExpMsgCode code);
// add the advanced error capability at the specified offset.
// NOTE: some extra regs for root ports are not added.
void addAERCap(uint16_t capOffset, uint16_t nextCapPtr);
// handle an error condition from the perspective of a receiver/completer
// of a TLP or as the detecting agent( eg trainingErr) of an
// error condition.
// process an error by setting relevent bits in status registers etc.
// in case of advanced error reporting (AER) capability present,
// update those registers as well.
// header is a pointer to uint32_t[4] array which contains
// the TLP packet header in case AER is supported and header
// logging is enabled. default value is null
pcieCompleter processErrorRcvrCmpltr(pciExp_Error error, uint32_t * header = 0);
// handle the completion of a request initiated by this device.
// set the relevent bits for all the completion statu's defined
// including CMPL_TO etc.
// returns 0 on success (No simulation error), -1 otherwise
int handleCompletion(pcieCompleter C);
bool isCorrErr(pciExp_Error error){
switch(error){
case receiverErr:
case badTLP:
case replayNumRollover:
case replayTimerTimeout:
return true;
default:
return false;
}
}
// "guess" the possible size of the request, given the byte enables.
// NOTE: assumes upto 8 byte request.
// for non contiguous byte-enables, the size is returned
// as the next higher power of 2 ie for be = 0b0101 size = 4.
// compliant devices should never need to use this function
int byteEnabletoSize(uint8_t be){
switch(be){
case 0:
case 1:
return be;
case 2:
case 3:
return 2;
case 4:case 5:case 6:case 7:
case 8:case 9:case 10:case 11:
case 12:case 13:case 14:case 15:
return 4;
default:
return 8;
}
}
/*NOTES:
A) specific PCIE dev implementations should provide implementation for
following virtual functions.
virtual mmi_instance_t devif_getInstance()=0;
virtual const char *devif_getName()=0;
B) Specific device impl. should call
pcieBusIf::busif_access() &
pcieBusIf::busif_msgAccess() directly for,
1) peer-to-peer IO/MEM/CONF space access or for DVMA through upstream bridge, &
2) access into pcie msg space.
Should not ever need to call other busIf functions. Their intended usage is for
this genericPcie class impl.
C) The generic class provides default implementations for
devif_memAccess(),devif_ioAccess() & devif_msgAccess().
If these address spaces are defined by
the device then these functions should be overridden.
devif_confAccess() is implemented by this generic class.
Normally it would not need to be overridden, except when there is some
non standard behaviour, in which case it should be.
Also devif_confAccessCb() is provided for specific implementations
to do impl. dep. stuff on access to conf space regs. this function is
called after each r/w to conf space registers from devif_confAccess().this function is
left pure virtual, hence must be overridden.
Other approach would be to
override the default config space register impl.
*/
};
#define GENERIC_PCIE_DEV_INTERFACE "genericPcieDevIntf"
#define PCIE_BUS_INTERFACE "pcieBusIntf"
#endif //_PCIE_NEW_