Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / bridge / bridge.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: 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 "bridge.h"
#include <unistd.h>
#include <assert.h>
#include <errno.h>
static const char * pcieToPciBridge_help = "\n\
SAM model for Intel 41210 Serial to Parallel PCIE-PCI bridge\n\
Sysconf format is:\n\
sysconf bridge <instance name> bus=<primary bus> dev=<device> fun=<function> secbus=<secondary bus>\n\
<instance name> is any user specified name for the module\n\
<primary bus> is the instance name of the upstream pcie bus module\n\
<device> is the device number of bridge on upstream pcie bus\n\
<function> is the function number of bridge on upstream pcie bus\n\
<secondary bus> is the instance name of the downstream pci bus module\n\
For UI help type <instance name>\n\
For module specific info type \'modinfo <instance name>\'";
pcieToPciBridge_ui_cmd (void * obj, int argc, char * argv[]){
pcieToPciBridge * i = dynamic_cast<pcieToPciBridge*>((Module *)obj);
i->handle_ui(argc, argv);
return 0;
}
#define BRIDGE_CAP_STRUCT_ADDR 0x44
#define BRIDGE_MSI_CAP_ADDR 0x5c
#define BRIDGE_POWER_CAP_ADDR 0x6c
#define BRIDGE_PCIX_CAP_ADDR 0xd8
#define BRIDGE_AER_CAP_OFFSET 0x100
#define BRIDGE_POWER_BUDGET_CAP_OFFSET 0x300
const char *
Module::get_help_string(){
return pcieToPciBridge_help;
}
Module *
Module::create(const char *_modname, const char *_instance_name){
return new pcieToPciBridge(_modname, _instance_name);
}
pcieToPciBridge::pcieToPciBridge(const char* modname, const char * instance_name)
: Module(modname, instance_name){
debug_info("Pcie bridge: creating instance %s\n", instance_name);
mem32_base = mem32_limit = 0;
mem64_base = mem64_limit = 0;
io_base = io_limit = 0;
bCR = 0;
mmi_register_instance_cmd(getInstance(),pcieToPciBridge_help,pcieToPciBridge_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
}
pcieToPciBridge::~pcieToPciBridge(){
debug_info("%s: destructor\n", HERE);
}
const char *
pcieToPciBridge::get_help(){
return Module::get_help_string();
}
void
pcieToPciBridge::initPci(){
char reg_descr[100];
snprintf(reg_descr, 100, "%s-%s Vender ID", devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr, 2,0x8086,0x0,0x0),PCI_CONF_VENID);
snprintf(reg_descr, 100, "%s-%s Device ID", devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr, 2,function?0x0341:0x0340,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,0x10,0xf900),PCI_CONF_STAT);//write mask = 0xf900
// 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,0x0,0x0,0x0),PCI_CONF_REVID);// rev id = 0x00, 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,0x81,0x00),PCI_CONF_HEADER);
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 Master Latency Timer",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x40,0xf8),PCI_BCNF_LATENCY_TIMER);//0x40, rw
snprintf(reg_descr,100,"%s-%s I/O Base",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xf0),PCI_BCNF_IO_BASE_LOW);//0x00, rw
snprintf(reg_descr,100,"%s-%s I/O Limit",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xf0),PCI_BCNF_IO_LIMIT_LOW);//0x00, rw
snprintf(reg_descr,100,"%s-%s Secondary Status",devif_getName(),busName);
confSpace->addConfReg(new pciSecondaryStatusReg(0x2a,0xf900,0,reg_descr),PCI_BCNF_SEC_STATUS);//0x2a, rw
snprintf(reg_descr,100,"%s-%s Memory Base",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x00,0xfff0),PCI_BCNF_MEM_BASE);//0x00, 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,0x01,0xfff0),PCI_BCNF_PF_BASE_LOW);//0x01, 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,0x0,0x0),PCI_BCNF_IO_BASE_HI); //0x0, RO
snprintf(reg_descr,100,"%s-%s I/O Limit High",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0x0),PCI_BCNF_IO_LIMIT_HI); //0x0, RO
snprintf(reg_descr,100,"%s-%s Capabilities List Pointer",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x44,0x0),PCI_BCNF_CAP_PTR); //0x44, 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,0x0,0x0),PCI_BCNF_IPIN); //0x0, RO
snprintf(reg_descr,100,"%s-%s Bridge control",devif_getName(),busName);
confSpace->addConfReg(new pciBridgeControlReg(0x0,0xf7f,0x0,reg_descr),PCI_BCNF_BCNTRL); //0x0, RW
snprintf(reg_descr,100,"%s-%s Bridge configuration",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x2880,0x4683),PCI_BCNF_BCNF); //0x2880, RW
snprintf(reg_descr,100,"%s-%s Multi-Transaction Timer",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xf8),PCI_BCNF_MTT); //0x0, RW
snprintf(reg_descr,100,"%s-%s PCI Clock Control",devif_getName(),busName);
confSpace->addConfReg(new pciConfReg(reg_descr,1,0xdf,0x7f),PCI_BCNF_PCLKC); //0xdf, RW
snprintf(reg_descr,100,"%s PCI Express Capability Identifier",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x10,0x00),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_CAP_ID_OFFSET);//ro
snprintf(reg_descr,100,"%s Next Item Pointer",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,BRIDGE_MSI_CAP_ADDR,0x0),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_NXT_CAP_PTR_OFFSET);//, ro
snprintf(reg_descr,100,"%s PCI Express Capability",getName());
confSpace->addConfReg(new pciExpCapReg(0x71,0x0,0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_CAP_REG_OFFSET);//0x1
snprintf(reg_descr,100,"%s PCI Express Device Capabilities Register",getName());
confSpace->addConfReg(new pciExpDevCapReg(0x1,0x0,0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_DEV_CAP_OFFSET);//
snprintf(reg_descr,100,"%s PCI Express Device Control Register",getName());
confSpace->addConfReg(new pciExpDevCntrlReg(0x2000,0xf0ef,0,reg_descr),BRIDGE_CAP_STRUCT_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_CAP_STRUCT_ADDR + PCI_EXP_DEV_STAT_OFFSET);//
snprintf(reg_descr,100,"%s PCI Express Link Capabilities Register",getName());
confSpace->addConfReg(new pciExpLnkCapReg(0x3e481,0x0,0x0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_LINK_CAP_OFFSET);//
snprintf(reg_descr,100,"%s PCI Express Link Control Register",getName());
confSpace->addConfReg(new pciExpLnkCntrlReg(0x0,0xc3,0x0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_LINK_CONT_OFFSET);//
snprintf(reg_descr,100,"%s PCI Express Link Status Register",getName());
confSpace->addConfReg(new pciExpLnkStatReg(0x1081,0x0,0x0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_LINK_STAT_OFFSET);//
addMsiCap(BRIDGE_POWER_CAP_ADDR, BRIDGE_MSI_CAP_ADDR, 0x80);
addAERCap(BRIDGE_AER_CAP_OFFSET,BRIDGE_POWER_BUDGET_CAP_OFFSET);
// pcix power management registers
snprintf(reg_descr,100,"%s PM_CAPID",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x1,0x0),0x6c);
snprintf(reg_descr,100,"%s PM_NXTP",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0xd8,0x0),0x6d);
snprintf(reg_descr,100,"%s PM_PMC",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,2,0xc802,0x0),0x6e);
snprintf(reg_descr,100,"%s PM_PMCSR",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0x3),0x70);
snprintf(reg_descr,100,"%s PM_BSE",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),0x72);
snprintf(reg_descr,100,"%s PM_DATA",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),0x73);
// pcix capability id
snprintf(reg_descr,100,"%s PM_CAPID",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x7,0x0),0xd8);
snprintf(reg_descr,100,"%s PM_NXTP",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),0xd9);
// pcix registers
snprintf(reg_descr,100,"%s PX_SSTS",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x3,0x0),0xda);
snprintf(reg_descr,100,"%s PX_BSTS",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0xdc);
snprintf(reg_descr,100,"%s PX_USTC",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0xffffffff,0xffff0000),0xe0);
snprintf(reg_descr,100,"%s PX_DSTC",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0xffffffff,0xffff0000),0xe4);
snprintf(reg_descr,100,"%s BINIT",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x3,0x1f),0xfc);
// pcix error registers
snprintf(reg_descr,100,"%s PCIXERRUNC_PTR",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0x0),0x138);
snprintf(reg_descr,100,"%s PCIEXERRUNC_SEV",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0xffff),0x134);
snprintf(reg_descr,100,"%s PCIEXRRUNC_MSK",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x20,0xffff),0x130);
snprintf(reg_descr,100,"%s PCIXERRUNC_STS",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0xffff),0x12c);
snprintf(reg_descr,100,"%s PCIXHDR_LOG0",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0x13c);
snprintf(reg_descr,100,"%s PCIXHDR_LOG1",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0x140);
snprintf(reg_descr,100,"%s PCIXHDR_LOG2",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0x144);
snprintf(reg_descr,100,"%s PCIXHDR_LOG3",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0x148);
snprintf(reg_descr,100,"%s ARB_CNTRL",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,2,0xff,0xffff),0x16a);
snprintf(reg_descr,100,"%s SSR",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0x0),0x170);
snprintf(reg_descr,100,"%s PREFCTRL-Lower",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x5060,0x3f0770),0x178);
snprintf(reg_descr,100,"%s PREFCTRL-Upper",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x4000,0xc00),0x17c);
// power budgeting registers.
snprintf(reg_descr,100,"%s power budgeting enhanced cap hdr",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x10004,0x0),0x300);
snprintf(reg_descr,100,"%s power budgeting data select",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xff),0x304);
snprintf(reg_descr,100,"%s power budgeting data register",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0x308);
}
void
pcieToPciBridge::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
pcieToPciBridge::module_added(mmi_instance_t target, const char *target_name){
if (secBusName && !strcmp(target_name,secBusName)){
secBusIf = (pciBusIf*)mmi_get_interface(target, PCI_BUS_INTERFACE);
}
if(busName && !strcmp(target_name, busName)){
busIf = (pcieBusIf*)mmi_get_interface(target, PCIE_BUS_INTERFACE);
}
dev_module_added(target_name);
}
void
pcieToPciBridge::module_deleted(mmi_instance_t target, const char *target_name){
dev_module_deleted(target_name);
}
void
pcieToPciBridge::modinfo(){
printf("%s is a Intel pcie-pci bridge device\n",getName());
printf("device id <0x%lx>, vendor id <0x%lx>\n",confSpace->readConf(PCI_CONF_VENID),\
confSpace->readConf(PCI_CONF_DEVID));
printf("it's primary pcie bus is <%s>, secondary pci bus is <%s>\n",busName,secBusName);
printf("to display pcie config regs, type \'%s dump\'\n",getName());
}
bool
pcieToPciBridge::parse_arg(const char *arg){
if(argval("secbus",arg,&secBusName)){
debug_more("%s:secondary bus = %s\n",getName(),secBusName);
return true;
}else
return dev_parse_arg(arg);
}
bool
pcieToPciBridge::check_args(){
if(!secBusName){
debug_err("%s: ERROR: must specify a secondary PCI bus\n", getName());
return false;
}else
return dev_check_args();
}
void*
pcieToPciBridge::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;
}
pciExpMsgCode
pcieToPciBridge::map_pin_vpin(int device, int line, bool ast) {
int vpin = (device % 4 + line) % 4;
if (ast)
switch (vpin) {
case 0: return MSG_Assert_INTA;
case 1: return MSG_Assert_INTB;
case 2: return MSG_Assert_INTC;
case 3: return MSG_Assert_INTD;
default: assert(0);
}
else
switch (vpin) {
case 0: return MSG_Deassert_INTA;
case 1: return MSG_Deassert_INTB;
case 2: return MSG_Deassert_INTC;
case 3: return MSG_Deassert_INTD;
default: assert(0);
}
}
int
pcieToPciBridge::busif_interrupt_in(bool set, mmi_instance_t busMod, int device, int line, SAM_DeviceId *id) {
pciExpMsgCode vpin = map_pin_vpin(device, line, set);
int ret;
if(set)
ret = handleCompletion(assertIntx(vpin,device,id));
else
ret = handleCompletion(deassertIntx(vpin, device,id));
if (!ret)
return 0;
else {
debug_err("ERROR: PCI/X device %d, pin %d INT assertion failed!\n", device, line);
return -1;
}
}
int
pcieToPciBridge::busif_free_interrupt(mmi_instance_t busMod, int dev_number) {
debug_more("%s: free interrupt\n",getName());
return 0;
}
int
pcieToPciBridge::busif_dma_out(uint64_t vaddr, void *data, long count, mmi_instance_t caller,uint16_t requesterId,SAM_DeviceId *id) {
int length = (count - 1)/4 + 1;
uint8_t be;
// assume contiguous byte access.
if(count <= 4){
be = pcie_countToBe(count);
}else if(count <= 8){
be = pcie_countToBe(count);
}else{
if((count % 4) == 0 ) be = 0xff;
else{
be = pcie_countToBe(count % 4) << 4;
be |= 0xf;
}
}
debug_more("%s: busif_dma_out:byte count 0x%llx,pcie tlp length 0x%lx,pcie tlp be 0x%x\n",getName(),count,length,be);
busIf->busif_access(PCIE_MEM, true, vaddr, data, length, be, PCIE_REQUESTER_ID(busIf->busif_getBusno(),0,0), mem_addr32,id);
return 0;
}
int
pcieToPciBridge::busif_dma_in(uint64_t vaddr, void *data, long count, mmi_instance_t caller,uint16_t requesterId, SAM_DeviceId *id) {
int length = (count - 1)/4 + 1;
uint8_t be;
// assume contiguous byte access.
if(count <= 4){
be = pcie_countToBe(count);
}else if(count <= 8){
be = pcie_countToBe(count);
}else{
if((count % 4) == 0 ) be = 0xff;
else{
be = pcie_countToBe(count % 4) << 4;
be |= 0xf;
}
}
debug_more("%s: busif_dma_in:bytecount 0x%llx,pcie tlp length 0x%lx,pcie tlp be 0x%x\n",getName(),count,length,be);
busIf->busif_access(PCIE_MEM, false, vaddr, data, length, be, PCIE_REQUESTER_ID(busIf->busif_getBusno(),0,0) , mem_addr32,id);
return 0;
}
int
pcieToPciBridge::busif_add_interrupt(mmi_instance_t busMod,int device,int dev_type, int slot_irl[],bool isMulti = false) {
debug_more("%s:ADD INT\n",getName());
return 0;
}
/* PCI Express Enhanced Configuration address to conventional PCI
Configuration address translation (type 1 to type 0) */
uint32_t
pcieToPciBridge::pcie_eh1_pci0_translation(uint32_t addr) {
uint16_t dev_fun, reg; uint32_t bus, ret;
bus = addr >> busShift & 0xff;
dev_fun = addr >> funShift & 0xff;
reg = addr & 0xff;
ret = bus << 16 | dev_fun << 8 | reg;
return ret;
}
void
pcieToPciBridge::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 + 1);
}
}
break;
case PCI_BCNF_IO_BASE_LOW:
case PCI_BCNF_IO_LIMIT_LOW:
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("Bridge remap: IO [%lx %lx]\n", io_base, io_limit);
mapSpace(PCIE_IO, io_base, io_limit - io_base + 1);
}
}
break;
default:
return;
}
return;
}
pcieCompleter
pcieToPciBridge::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) {
int size = byteEnabletoSize(be); // length is the number of words
if (tType == conf_type1) {
pciXactnStatus status;
addr = pcie_eh1_pci0_translation(addr);
if(wr){
*(uint64_t*)data &= 0xffffffff;
uint32_t 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 wr xactn type 1: addr <0x%x> size<%d> be<0x%x> data<0x%llx>\n",
getName(), addr, size, be,*(uint64_t*)data);
}
status = secBusIf->busif_access_w_size(PCI_CFG, addr, addr, wr, (uint64_t *)data, size,id);
if(!wr){
uint32_t 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 rd xactn type 1: addr <0x%x> size<%d> be<0x%x> data<0x%llx>\n",
getName(), addr, size, be, *(uint64_t*)data);
if(debug_level >= 2) printf("\n");
}
if ( status == SUCCESS )
return pcieCompleter(SC,getId());
else if( status == MASTER_ABORT)
return pcieCompleter(CA,getId());
else
return pcieCompleter(UR,getId());
} else {
bool ret;
if(id)
*id = samId;
if(wr){
*(uint64_t*)data &= 0xffffffff;
uint32_t 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> be<0x%x> data<0x%llx>\n",
getName(), addr, size, be,*(uint64_t*)data);
}
ret = confSpace->confAccessSize(addr, wr, (uint64_t *)data, size);
if(wr && debug_level >= 2) printf("\n");
if(!wr){
uint32_t 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> be<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
pcieToPciBridge::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) {
int size = byteEnabletoSize(be);
if (addr >= mem32_base && addr < mem32_limit || addr >= mem64_base && addr < mem64_limit) {
if(wr)
debug_more("%s downstream wr mem access: addr <0x%x> size<%d> be<0x%x> data<0x%llx>\n",
getName(), addr, size, be, *(uint64_t*)data);
secBusIf->busif_access_w_size(mode == mem_addr64 ? PCI_MEM64 : PCI_MEM32, addr, addr, wr, (uint64_t *)data, size,id);
if(!wr)
debug_more("%s downstream rd mem access: addr <0x%x> size<%d> be<0x%x> data<0x%llx>\n",
getName(), addr, size, be, *(uint64_t*)data);
return pcieCompleter(SC, getId());
} else{
if(id) *id = samId;
return pcieCompleter(UR, getId());
}
}
pcieCompleter
pcieToPciBridge::devif_ioAccess(bool wr, uint64_t addr, void * data, uint8_t be, uint16_t reqId, \
uint16_t length, tlp_X args, SAM_DeviceId *id) {
if(id)
*id = samId;
return pcieCompleter(UR, getId());
}
pcieCompleter
pcieToPciBridge::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){
if(id)
*id = samId;
return pcieCompleter(UR,getId());
}
bool pcieToPciBridge::dump (FILE * fp){
const int bufsize = 64 * 1024;
char buf[bufsize];
char tbuf[bufsize];
char *dumpDir = DR_get_dir();
assert(dumpDir);
bool ret = genericPcieDev::dump (dumpDir, getName());
// intx interrupts
// dump the device numbers of downstream devices
fprintf(fp,"%s\n",current_dump_version);
fprintf(fp,"downstream 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 pcieToPciBridge::restore (FILE * fp){
const int bufsize = 64 * 1024;
char buf[bufsize];
char *dumpDir = DR_get_dir();
assert(dumpDir);
bool ret = genericPcieDev::restore (dumpDir, getName());
// 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 pcieToPciBridge::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;
}