Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / pcie_bridge / pcie_bridge.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: pcie_bridge.cc
// 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 ============================================
#include "pcie_bridge.h"
static const char * pcieToPcieBridge_help = "\n\
SAM functional model for PCIE-PCIE bridge component of PLX 8532\n\
The switch is composed by sysconf'ing individual pcie bridges\n\
connected by an internal pcie bus (also sysconf'ed)\n\
The following illustrates a sample configuration with the buses\n\
numbered in DFS order.\n\
|--------------PCIE Bridge----------------|\n\
bus [0] _____|_____ \n\
_____________________________|______________________\n\
| | |\n\
| port0 (upstream) |\n\
| internal bus [1]____________|_________________ |PCIE switch\n\
| | | | |\n\
| downstream port1 port2 (downstream) ... |\n\
|________________|____________|______________________|\n\
| |\n\
bus [2] ___|___ ___|___ bus [5]\n\
|\n\
PCIE-PCI[E] bridge/PCIE device\n\
\n\
Sysconf format for individual pcie bridge is: \n\
sysconf pcie_bridge <instance name> bus=<upstream bus> secbus=<downstream bus>\n\
dev=<device number> [upstream]\n\
where,\n\
\'bus\' is the upstream bus for this bridge instance\n\
\'secbus\' is the secondary bus of this bridge instance\n\
\'dev\' is the device number on the upstream bus\n\
\'upstream\' is boolean parameter that designates the bridge as a switch\n\
upstream port. If absent the bridge is a downstream port\n\
\n\
Example switch config - port 0 as upstream and 1 2 8 9 as downstream\n\
{NOTE: port is same as dev here. Can also add ports 3 10 11 as well}\n\
#upstream port - pcie_a is primary bus of upstream bridge\n\
sysconf pcie_bridge b0 bus=pcie_a dev=0 fun=0 secbus=pcie_int upstream\n\
#internal virtual pcie bus\n\
sysconf pcie_bus pcie_int bridge=b0\n\
#downstream ports connected at upstream to pcie_int\n\
sysconf pcie_bridge b1 bus=pcie_int dev=1 secbus=pcie_b\n\
sysconf pcie_bridge b2 bus=pcie_int dev=2 secbus=pcie_c\n\
sysconf pcie_bridge b3 bus=pcie_int dev=8 secbus=pcie_d\n\
sysconf pcie_bridge b4 bus=pcie_int dev=9 secbus=pcie_e\n\
#downstream pcie buses\n\
sysconf pcie_bus pcie_b bridge=b1\n\
sysconf pcie_bus pcie_c bridge=b2\n\
sysconf pcie_bus pcie_d bridge=b3\n\
sysconf pcie_bus pcie_e bridge=b4\n\
\n\
For UI help type <instance name>\n\
For module specific info type \'modinfo <instance name>\'\n";
const char *
Module::get_help_string(){
return pcieToPcieBridge_help;
}
Module *
Module::create(const char *_modname, const char *_instance_name){
return new PcieBridge(_modname, _instance_name);
}
pcieToPcieBridge_ui_cmd (void * obj, int argc, char * argv[]){
PcieBridge * i = dynamic_cast<PcieBridge*>((Module *)obj);
i->handle_ui(argc, argv);
return 0;
}
PcieBridge::PcieBridge(const char* modname, const char * instance_name)
: Module(modname, instance_name){
debug_info("PCIE-PCIE bridge: creating instance %s\n", instance_name);
mem32_base = mem32_limit = 0;
mem64_base = mem64_limit = 0;
io_base = io_limit = 0;
upstream_port = false;
secBusName = 0;
bCR = 0;
mmi_register_instance_cmd(getInstance(),pcieToPcieBridge_help,pcieToPcieBridge_ui_cmd);
pendingIntr[0] = pendingIntr[1] = pendingIntr[2] = pendingIntr[3] = false;
assert(pthread_mutex_init(&intMutex,0) == 0);
dump_version1_0 = strdup("v1.0"); // never change
current_dump_version = dump_version1_0; // change if when dump format changes,
// i.e. point current to new version
// string
}
PcieBridge::~PcieBridge(){
debug_info("%s: destructor\n", HERE);
}
const char *
PcieBridge::get_help(){
return Module::get_help_string();
}
bool
PcieBridge::dump(FILE * fp) {
char *dumpDir = DR_get_dir();
assert(dumpDir);
bool ret = genericPcieDev::dump (dumpDir, getName());
const int bufsize = 64 * 1024;
char buf[bufsize];
char tbuf[bufsize];
// intx interrupts
// dump the port/device numbers of downstream ports/devices
fprintf(fp,"%s\n",current_dump_version);
fprintf(fp,"downstream ports/devices with pending interrupts\n");
for(int i = 0; i < 4; i++){
sprintf(buf,"Int%c ",'A' + i);
list<int>::iterator listIt;
tbuf[0] = 0;
for(listIt = intLine[i].begin(); listIt != intLine[i].end(); listIt++){
sprintf(tbuf,"0x%x ",*listIt);
strcat(buf,tbuf);
}
fwrite(buf,strlen(buf),1,fp);
fwrite("\n",strlen("\n"),1,fp);
}
// now dump the intx pending status
fprintf(fp,"Pending interrupts to upstream bridge\n");
for(char i = 0; i < 4; i++)
fprintf(fp,"int%c-%s\n", i+'A', pendingIntr[i]? "Asserted":"Deasserted");
fclose(fp);
return ret;
}
bool
PcieBridge::restore(FILE * fp) {
char *dumpDir = DR_get_dir();
assert(dumpDir);
bool ret = genericPcieDev::restore (dumpDir, getName());
const int bufsize = 64 * 1024;
char buf[bufsize];
// read the version string.
fgets(buf,bufsize,fp);
if(!strcmp(current_dump_version,buf)){
printf("%s: dump version unknown\n",getName());
assert(0);
}
// throw away the comment line
fgets(buf,bufsize,fp);
for(int i = 0; i < 4; i++){
fgets(buf,bufsize,fp);
strtok(buf," "); // intr line number, ignore
const char * port_val;
while( port_val = strtok(0," ") ){
if(port_val[0] == '\n')
break;
uint64_t val = strtoull(port_val,0,0);
intLine[i].push_back(val);
intLine[i].sort();
intLine[i].unique();
pendingIntr[i] = true;
}
}
// ignore the other dump data as it can be derived from data above
return ret;
}
void
PcieBridge::initPci(){
char reg_descr[100];
snprintf(reg_descr, 100, "%s-%s Vender ID", devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr, 2,0x10b5,0x0,0x0),PCI_CONF_VENID);
snprintf(reg_descr, 100, "%s-%s Device ID", devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr, 2,0x8532,0x0,0x0),PCI_CONF_DEVID);
snprintf(reg_descr, 100, "%s-%s command register", devif_getName(),busName);
confSpace->addConfReg(new bridgeCommandReg(reg_descr,(genericPcieDev*)this,0x547,0x0),PCI_CONF_COMM);// write mask = 0x547
snprintf(reg_descr,100,"%s-%s Primary device status reg", devif_getName(),busName);
confSpace->addConfReg(new pcieStatusReg(reg_descr,(genericPcieDev*)this,0x0010,0xc900),PCI_CONF_STAT);//write mask = 0xc900
// this reg has some rw1c bit fields. over-ride the pciStatusReg class r/w functions in case OS ever complains.
snprintf(reg_descr,100,"%s-%s revision id", devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0xbb,0x0),PCI_CONF_REVID);// rev id = 0xBB, the latest silicon revision, ro
snprintf(reg_descr,100,"%s-%s prog interface",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_CONF_PROGCLASS);//0x00, ro
snprintf(reg_descr,100,"%s-%s sub class",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x4,0x0),PCI_CONF_SUBCLASS);//0x04, ro
snprintf(reg_descr,100,"%s-%s base class",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x06,0x0),PCI_CONF_BASCLASS);//0x06, ro
snprintf(reg_descr,100,"%s-%s cache line size",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xff),PCI_CONF_CACHE_LINESZ);//0x00,
snprintf(reg_descr,100,"%s-%s latency timer",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_CONF_LATENCY_TIMER);//0x00,
snprintf(reg_descr,100,"%s-%s Header type",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x01,0x00),PCI_CONF_HEADER);
snprintf(reg_descr,100,"%s-%s Base Address 0",devif_getName(),busName);
if (upstream_port)
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0xfffe0000),PCI_CONF_BASE0); // Base Address writable
else
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),PCI_CONF_BASE0); // Base Address read only
snprintf(reg_descr,100,"%s-%s Base Address 1",devif_getName(),busName);
if (upstream_port)
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0xffffffff),PCI_CONF_BASE1); // Base Address writable
else
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),PCI_CONF_BASE1); // Base Address read only
snprintf(reg_descr,100,"%s-%s Primary Bus No",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xff),PCI_BCNF_PRIBUS);//0x00, rw
snprintf(reg_descr,100,"%s-%s Secondary Bus No",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xff),PCI_BCNF_SECBUS);//0x00, rw
snprintf(reg_descr,100,"%s-%s Subordinate Bus No",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xff),PCI_BCNF_SUBBUS);//0x00, rw
snprintf(reg_descr,100,"%s-%s Secondary Latency Timer",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_BCNF_LATENCY_TIMER);//0x0, RO
snprintf(reg_descr,100,"%s-%s I/O Base",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0xf1,0xf0),PCI_BCNF_IO_BASE_LOW);//0xf1, rw
snprintf(reg_descr,100,"%s-%s I/O Limit",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x01,0xf0),PCI_BCNF_IO_LIMIT_LOW);//0x01, rw
snprintf(reg_descr,100,"%s-%s Secondary Status",devif_getName(),busName);
confSpace->addConfReg(new pciSecondaryStatusReg(0,0xc100,0,reg_descr),PCI_BCNF_SEC_STATUS);//0x0, rw
snprintf(reg_descr,100,"%s-%s Memory Base",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,2,0xfff0,0xfff0),PCI_BCNF_MEM_BASE);//0xfff0, rw
snprintf(reg_descr,100,"%s-%s Memory Limit",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x00,0xfff0),PCI_BCNF_MEM_LIMIT);//0x00, rw
snprintf(reg_descr,100,"%s-%s Prefetchable Memory Base",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,2,0xfff1,0xfff0),PCI_BCNF_PF_BASE_LOW);//0xfff1, rw
snprintf(reg_descr,100,"%s-%s Prefetchable Memory Limit",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x01,0xfff0),PCI_BCNF_PF_LIMIT_LOW);//0x01, rw
snprintf(reg_descr,100,"%s-%s Prefetchable Memory Base Upper Portion",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0xffffffff),PCI_BCNF_PF_BASE_HIGH);//0x0, rw
snprintf(reg_descr,100,"%s-%s Prefetchable Memory Limit Upper Portion",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0xffffffff),PCI_BCNF_PF_LIMIT_HIGH);//0x0, rw
snprintf(reg_descr,100,"%s-%s I/O Base High",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,2,0xffff,0xffff),PCI_BCNF_IO_BASE_HI); //0xffff, rw
snprintf(reg_descr,100,"%s-%s I/O Limit High",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0xffff),PCI_BCNF_IO_LIMIT_HI); //0x0, rw
snprintf(reg_descr,100,"%s-%s Capabilities List Pointer",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x40,0x0),PCI_BCNF_CAP_PTR); //0x40, RO
snprintf(reg_descr,100,"%s-%s Interrupt Line",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xff),PCI_BCNF_ILINE); //0x0, RW
snprintf(reg_descr,100,"%s-%s Interrupt Pin",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x1,0x0),PCI_BCNF_IPIN); //0x1, RO
snprintf(reg_descr,100,"%s-%s Bridge control",devif_getName(),busName);
confSpace->addConfReg(new pciBridgeControlReg(0x0,0x5f,0,reg_descr),PCI_BCNF_BCNTRL); //0x0, RW
snprintf(reg_descr,100,"%s-%s Power Management Capability ID",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x01,0x00),BRIDGE_POWER_CAP_ADDR); //0x01, RO
snprintf(reg_descr,100,"%s-%s Next Capability Pointer",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x48,0x00),BRIDGE_POWER_CAP_ADDR+1); //0x48, RO
snprintf(reg_descr,100,"%s-%s ower Management Version",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,2,0xc802,0x00),BRIDGE_POWER_CAP_ADDR+2); //0xc802, RO
addMsiCap(BRIDGE_PCIE_CAP_ADDR, BRIDGE_MSI_CAP_ADDR, 0x80);
snprintf(reg_descr,100,"%s PCI Express Capability Identifier",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x10,0x00),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_CAP_ID_OFFSET);
snprintf(reg_descr,100,"%s Next Item Pointer",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_NXT_CAP_PTR_OFFSET);
snprintf(reg_descr,100,"%s PCI Express Capability",getName());
if (upstream_port)
confSpace->addConfReg(new pciExpCapReg(0x51,0x0,0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_CAP_REG_OFFSET);
else
confSpace->addConfReg(new pciExpCapReg(0x161,0x0,0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_CAP_REG_OFFSET);
snprintf(reg_descr,100,"%s PCI Express Device Capabilities Register",getName());
if (upstream_port)
confSpace->addConfReg(new pciExpDevCapReg(0x7001,0x0,0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_DEV_CAP_OFFSET);
else
confSpace->addConfReg(new pciExpDevCapReg(0x1,0x0,0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_DEV_CAP_OFFSET);
snprintf(reg_descr,100,"%s PCI Express Device Control Register",getName());
confSpace->addConfReg(new pciExpDevCntrlReg(0x0,0xef,0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_DEV_CTRL_OFFSET);
snprintf(reg_descr,100,"%s PCI Express Device Status Register",getName());
confSpace->addConfReg(new pciExpDevStatReg(0x0,0xf,0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_DEV_STAT_OFFSET);
snprintf(reg_descr,100,"%s PCI Express Link Capabilities Register",getName());
confSpace->addConfReg(new pciExpLnkCapReg(device << 24 | 0x2dc41,0x0,0x0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_LINK_CAP_OFFSET);
snprintf(reg_descr,100,"%s PCI Express Link Control Register",getName());
if (upstream_port)
confSpace->addConfReg(new pciExpLnkCntrlReg(0x0,0xc3,0x0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_LINK_CONT_OFFSET);
else
confSpace->addConfReg(new pciExpLnkCntrlReg(0x0,0xf3,0x0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_LINK_CONT_OFFSET);
snprintf(reg_descr,100,"%s PCI Express Link Status Register",getName());
confSpace->addConfReg(new pciExpLnkStatReg(0x11,0x0,0x0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_LINK_STAT_OFFSET);
snprintf(reg_descr,100,"%s PCI Express Slot Capabilities Register",getName());
if (upstream_port)
confSpace->addConfReg(new pciExpSlotCapReg(0x0,0x0,0x0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_SLOT_CAP_OFFSET);
else
confSpace->addConfReg(new pciExpSlotCapReg(0xcdf,0x0,0x0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_SLOT_CAP_OFFSET);
snprintf(reg_descr,100,"%s PCI Express Slot Control Register",getName());
if (upstream_port)
confSpace->addConfReg(new pciExpSlotCntrlReg(0x0,0x0,0x0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_SLOT_CTRL_OFFSET);
else
confSpace->addConfReg(new pciExpSlotCntrlReg(0x7c0,0x7ff,0x0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_SLOT_CTRL_OFFSET);
snprintf(reg_descr,100,"%s PCI Express Slot Status Register",getName());
if (upstream_port)
confSpace->addConfReg(new pciExpSlotStatReg(0x0,0x0,0x0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_SLOT_STAT_OFFSET);
else
confSpace->addConfReg(new pciExpSlotStatReg(0x0,0x1f,0x0,reg_descr),BRIDGE_PCIE_CAP_ADDR + PCI_EXP_SLOT_STAT_OFFSET);
snprintf(reg_descr,100,"%s Device Serial Number Extended Capability ID",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x3,0x0),BRIDGE_DEV_SERNUM_XCAP_ADDR);
snprintf(reg_descr,100,"%s Device Serial Number Capability Version & Next Pointer",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,2,0xfb41,0x0),BRIDGE_DEV_SERNUM_XCAP_ADDR + SERNUM_VER_NXTPTR_OFFSET);
snprintf(reg_descr,100,"%s Device Serial Number Low",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0xedf,0x0),BRIDGE_DEV_SERNUM_XCAP_ADDR + SERNUM_SN_LOW_OFFSET);
snprintf(reg_descr,100,"%s Device Serial Number High",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x1,0x0),BRIDGE_DEV_SERNUM_XCAP_ADDR + SERNUM_SN_HIGH_OFFSET);
addAERCap(BRIDGE_ADV_ERR_CAP_ADDR, BRIDGE_PWRBGT_HDR_ADDR);
snprintf(reg_descr,100,"%s Power Budgeting Enhanced Capability Header",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x14810004,0x0),BRIDGE_PWRBGT_HDR_ADDR);
snprintf(reg_descr,100,"%s Power Budgeting Data Select Register",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xff),BRIDGE_PWRBGT_HDR_ADDR + PWRBGT_DSEL_OFFSET);
snprintf(reg_descr,100,"%s Power Budgeting Data Register",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),BRIDGE_PWRBGT_HDR_ADDR + PWRBGT_DATA_OFFSET);
snprintf(reg_descr,100,"%s Power Budget Capability",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x1,0x0),BRIDGE_PWRBGT_HDR_ADDR + PWRBGT_DATA_CAP_OFFSET);
}
void
PcieBridge::init_done(){
initPci();
dev_init_done(debug_level);
mem32_base = GET_MEM_BASE(confSpace);
mem32_limit = GET_MEM_LIMIT(confSpace);
io_base = GET_IO_BASE(confSpace);
io_limit = GET_IO_LIMIT(confSpace);
mem64_base = GET_PF_MEM_BASE(confSpace);
mem64_limit = GET_PF_MEM_LIMIT(confSpace);
bCR = (bridgeCommandReg*)confSpace->getConfReg(PCI_CONF_COMM);
}
void
PcieBridge::module_added(mmi_instance_t target, const char *target_name){
if (secBusName && !strcmp(target_name,secBusName)){
secBusIf = (pcieBusIf*)mmi_get_interface(target, PCIE_BUS_INTERFACE);
secBusIf->setBridgeIf((genericPcieDevIf*)this);
}
if(busName && !strcmp(target_name, busName)){
busIf = (pcieBusIf*)mmi_get_interface(target, PCIE_BUS_INTERFACE);
}
dev_module_added(target_name);
}
void
PcieBridge::module_deleted(mmi_instance_t target, const char *target_name){
dev_module_deleted(target_name);
}
void
PcieBridge::modinfo(){
printf("%s: pcie-pcie virtual bridge device component of PLX 8532\n",getName());
printf("device id <0x%lx>, vendor id <0x%lx>\n",confSpace->readConf(PCI_CONF_VENID),\
confSpace->readConf(PCI_CONF_DEVID));
printf("The port type is %s\n",upstream_port?"Upstream":"Downstream");
printf("Upstream pcie bus is <%s>, secondary pcie bus is <%s>\n",busName,secBusName);
printf("To display pcie config regs, type \'%s dump\'\n",getName());
}
bool
PcieBridge::parse_arg(const char *arg){
if (argval("secbus",arg,&secBusName)) {
debug_more("%s:secondary bus = %s\n",getName(),secBusName);
return true;
}else if (!strcmp(arg, "upstream")){
debug_more("%s: port type <Upstream>\n",getName());
upstream_port = true;
return true;
} else
return dev_parse_arg(arg);
}
bool
PcieBridge::check_args(){
if(!secBusName){
debug_err("%s: ERROR: must specify a secondary PCIE bus\n", getName());
return false;
}else
return dev_check_args();
}
void*
PcieBridge::get_interface(const char *name){
if (!strcmp(name, GENERIC_PCIE_DEV_INTERFACE))
return (genericPcieDevIf*)this;
else if(!strcmp(name, PCI_BRIDGE_INTERFACE))
return (pciBridgeIf*)this;
else return 0;
}
void
PcieBridge::devif_confAccessCb(bool wr, uint64_t offset, uint8_t be){
if (!wr)
return;
switch (offset) {
case PCI_BCNF_PF_BASE_HIGH:
case PCI_BCNF_PF_BASE_LOW:
case PCI_BCNF_PF_LIMIT_HIGH:
case PCI_BCNF_PF_LIMIT_LOW:
if (!mem_mapped()){
mem64_base = GET_PF_MEM_BASE(confSpace);
mem64_limit = GET_PF_MEM_LIMIT(confSpace);
return;
}else{
if(mem64_base < mem64_limit){
debug_more("%s unmap MEM64[%llx %llx]\n",getName(), mem64_base, mem64_limit);
unmapSpace(PCIE_MEM, mem64_base);
}
mem64_base = GET_PF_MEM_BASE(confSpace);
mem64_limit = GET_PF_MEM_LIMIT(confSpace);
if (mem64_base < mem64_limit) {
debug_more("%s remap: MEM64 [%llx %llx]\n", getName(), mem64_base, mem64_limit);
mapSpace(PCIE_MEM, mem64_base, mem64_limit - mem64_base + 1);
}
}
break;
case PCI_BCNF_MEM_BASE:
case PCI_BCNF_MEM_LIMIT:
if (!mem_mapped()){
mem32_base = GET_MEM_BASE(confSpace);
mem32_limit = GET_MEM_LIMIT(confSpace);
return;
}else{
if(mem32_base < mem32_limit){
debug_more("%s unmap: MEM[%lx %lx]\n",getName(), mem32_base, mem32_limit);
unmapSpace(PCIE_MEM, mem32_base);
}
mem32_base = GET_MEM_BASE(confSpace);
mem32_limit = GET_MEM_LIMIT(confSpace);
if (mem32_base < mem32_limit) {
debug_more("%s remap: MEM[%lx %lx]\n",getName(), mem32_base, mem32_limit);
mapSpace(PCIE_MEM, mem32_base, mem32_limit - mem32_base);
}
}
break;
case PCI_BCNF_IO_BASE_LOW:
case PCI_BCNF_IO_LIMIT_LOW:
case PCI_BCNF_IO_BASE_HI:
case PCI_BCNF_IO_LIMIT_HI:
if (!io_mapped()){
io_base = GET_IO_BASE(confSpace);
io_limit = GET_IO_LIMIT(confSpace);
return;
}else{
if(io_base < io_limit){
debug_more("%s unmap: IO[%lx %lx]\n",getName(), io_base, io_limit);
unmapSpace(PCIE_IO, io_base);
}
io_base = GET_IO_BASE(confSpace);
io_limit = GET_IO_LIMIT(confSpace);
if (io_base < io_limit) {
debug_more("%s remap: IO[%lx %lx]\n",getName(), io_base, io_limit);
mapSpace(PCIE_IO, io_base, io_limit - io_base);
}
}
break;
default: return;
}
return;
}
pcieCompleter
PcieBridge::devif_confAccess(bool wr, uint32_t addr, void * data, uint8_t be, uint16_t reqId, addrMd_xactnType tType, uint16_t length, tlp_X args, SAM_DeviceId *id) {
uint32_t l_buf;
int size = byteEnabletoSize(be); // length is the number of words
if (tType == conf_type1) {
pcieCompleter ret;
if(wr)
debug_more("%s:conf wr xactn type 1: addr <0x%x> size <%d> byte_en<0x%x> data<0x%llx>\n",
getName(), addr, size, be,*(uint64_t*)data);
// Change requester ID to bridge's ID for the handling in pcieBus::busif_access():
ret = secBusIf->busif_access(PCIE_CFG, wr, addr, (uint64_t *)data, length, be, getId(), tType, id, args);
if(!wr)
debug_more("%s:conf rd xactn type 1: addr <0x%x> size <%d> byte_en<0x%x> data<0x%llx>\n",
getName(), addr, size, be, *(uint64_t*)data);
if(debug_level >= 2) printf("\n");
return ret;
} else {
bool ret;
if(id)
*id = samId;
if (addr >= 0x1000) {
debug_err("Config address higher than 4K!\n");
return pcieCompleter(UR,getId());
}
if(wr){
*(uint64_t*)data &= 0xffffffff;
l_buf = *(uint64_t*)data;
if(size == 4){
*(uint64_t*)data = swap_word(l_buf);
}else if(size == 2){
*(uint64_t*)data = swap_hword(l_buf);
}else if (size == 1)
*(uint64_t*)data = l_buf;
debug_more("%s:conf xactn type 0: addr <0x%x> wr size <%d> byte_en<0x%x> data<0x%llx>\n",
getName(), addr,size, be,*(uint64_t*)data);
}
ret = confSpace->confAccessSize(addr, wr, (uint64_t *)data, size);
if(!wr){
l_buf = *(uint64_t*)data;
if(size == 4){
*(uint64_t*)data = swap_word(l_buf & 0xFFFFFFFF);
}else if(size == 2){
*(uint64_t*)data = swap_hword(l_buf & 0xFFFF);
}else if (size == 1)
*(uint64_t*)data = l_buf & 0xFF;
debug_more("%s:conf xactn type 0: addr <0x%x> rd size <%d> byte_en<0x%x> data<0x%llx>\n",
getName(), addr, size, be, *(uint64_t*)data);
if(debug_level >= 2) printf("\n");
}
devif_confAccessCb(wr,addr,be);
return (ret ? pcieCompleter(SC,getId()) : pcieCompleter(CA,getId()));
}
}
pcieCompleter
PcieBridge::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 *id) {
direction_t direct = direction(busIf->busif_getBusno(), reqId);
debug_more("%s: %s %s %s access at <0x%llx> of length <%4d> byte_en <0x%x> \n",
getName(),
direct == downstream ? "downstream":"upstream ",
mode == mem_addr32 ? "mem32" : "mem64",
wr ? "wr":"rd",
addr,
length, be);
if ((direct == downstream) && (addr >= mem32_base && addr < mem32_limit || addr >= mem64_base && addr < mem64_limit)) {
return secBusIf->busif_access(PCIE_MEM, wr, addr, (uint64_t *)data, length, be, reqId, mode, id, args);
} else if ((direct == upstream) && ((addr < mem32_base || addr >= mem32_limit ) && (addr < mem64_base || addr >= mem64_limit))) {
return busIf->busif_access(PCIE_MEM, wr, addr, (uint64_t *)data, length, be, reqId, mode, id, args);
} else
return pcieCompleter(UR,getId());
}
pcieCompleter
PcieBridge::devif_ioAccess(bool wr, uint64_t addr, void * data, uint8_t be, uint16_t reqId, uint16_t length, tlp_X args, SAM_DeviceId *id) {
direction_t direct = direction(busIf->busif_getBusno(), reqId);
debug_more("%s: %s %s %s access at <0x%llx> length <%d> be <0x%x> \n",
getName(), direct == downstream ? "downstream":"upstream ",
"IO", wr ? "wr":"rd", addr, length, be);
if ((direct == downstream) && addr >= io_base && addr < io_limit) {
return secBusIf->busif_access(PCIE_IO, wr, addr, (uint64_t *)data, length, be, reqId, mem_addr32, id, args);
} else if ((direct == upstream) && (addr < io_base || addr >= io_limit)) {
return busIf->busif_access(PCIE_IO, wr, addr, (uint64_t *)data, length, be, reqId, mem_addr32, id, args);
} else
return pcieCompleter(UR,getId());
}
pcieCompleter
PcieBridge::devif_msgAccess(uint8_t messageCode, msgRouting route, uint64_t tarIdOrAddr, uint16_t reqId, void * data, uint16_t length, uint16_t vendorId, uint32_t vendor_data, tlp_X args, SAM_DeviceId *id){
switch(route){
case routed_to_RC:
case gathered_routed_to_RC:
return busIf->busif_msgAccess(messageCode,route,reqId,id,tarIdOrAddr,data,length,vendorId,
vendor_data, args);
break;
case local:
// intx message from downstream device or port.
if(messageCode >= MSG_Assert_INTA && messageCode <= MSG_Assert_INTD)
return assertIntx((pciExpMsgCode)messageCode, reqId, id);
else if(messageCode >= MSG_Deassert_INTA && messageCode <= MSG_Deassert_INTD)
return deassertIntx((pciExpMsgCode)messageCode, reqId, id);
else{
debug_err("%s: don;t know how to handle message 0x%x\n", getName(), messageCode);
return pcieCompleter(SIM_FAIL);
}
break;
case broadcast_from_RC:
return secBusIf->busif_msgAccess(messageCode,route,reqId,id, tarIdOrAddr,data,length,vendorId,vendor_data, args);
break;
case routed_by_addr:
debug_err("%s: address routing unsupported\n", getName());
break;
case routed_by_id:
debug_err("%s: ID routing unsupported\n", getName());
break;
default:
debug_err("%s: unknown message routing type %x\n",getName(),route);
return pcieCompleter(SIM_FAIL);
}
return pcieCompleter(SIM_OK);
}
void PcieBridge::handle_ui(int argc, char * argv[]){
if(argc == 1){
ui_cmd_usage();
return;
}else if(!strcmp(argv[1],"dump")){
char * dumpDir;
char buf[1024];
dumpDir = getcwd(buf,1024);
assert( errno != ERANGE);
genericPcieDev::dump (dumpDir, argv[2]);
}else if(!strcmp(argv[1],"restore")){
if(argv[2]){
char *dumpDir;
char buf[1024];
dumpDir = getcwd(buf,1024);
assert( errno != ERANGE);
genericPcieDev::restore (dumpDir, argv[2]);
}else
printf("%s restore: no restore filename specified\n",getName());
}else if(!strcmp(argv[1],"debug")){
if(argv[2]){
debug_level = atoi(argv[2]);
confSpace->set_debug_level(debug_level);
printf("%s: set debug level to %d\n",getName(),debug_level);
}else
printf("%s: current debug level %d\n",getName(),debug_level);
}else
debug_err("%s: unsupported UI command <%s>\n",getName(),argv[1]);
return;
}