Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / pcie_dev.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: pcie_dev.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.h"
#include "arg.h"
genericPcieDev::genericPcieDev(confHeaderType htype){
confSpace = new pciConfSpace(0x1000);
//initConf(htype);
busName = 0;
busIf = 0;
device = -1;
function = -1;
msiCapOffset = -1;
pciExpCapOffset = -1;
aerCapOffset = -1;
aerCapable = false;
msgDB = new pciExpMsgUtility();
errDB = new pciExpErrUtility();
}
genericPcieDev::genericPcieDev(){
confSpace = new pciConfSpace(0x1000);
busName = 0;
busIf = 0;
device = -1;
function = -1;
msiCapOffset = -1;
pciExpCapOffset = -1;
aerCapOffset = -1;
aerCapable = false;
msgDB = new pciExpMsgUtility();
errDB = new pciExpErrUtility();
}
bool genericPcieDev::mapSpace(pcie_space space, uint64_t base, uint64_t size){
assert(busIf);
return busIf->busif_map(devif_getName(),space, base, size);
}
bool genericPcieDev::unmapSpace(pcie_space space,uint64_t base){
assert(busIf);
return busIf->busif_unmap(devif_getName(),space, base);
}
pcieCompleter genericPcieDev::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){
if(id)
*id = (dynamic_cast<Module*>(this))->samId;
return pcieCompleter(UR,getId());
}
pcieCompleter genericPcieDev::devif_ioAccess(bool wr, uint32_t addr, void * data, uint8_t be, \
uint16_t reqId, uint16_t length, tlp_X args, SAM_DeviceId *id){
if(id)
*id = (dynamic_cast<Module*>(this))->samId;
return pcieCompleter(UR,getId());
}
pcieCompleter genericPcieDev::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 = (dynamic_cast<Module*>(this))->samId;
return pcieCompleter(UR,getId());
}
pcieCompleter genericPcieDev::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 *id){
assert(offset <= 0xfff);
assert((be & 0xf0) == 0);
assert(length == 1);
if(id)
*id = (dynamic_cast<Module*>(this))->samId;
confSpace->confAccessByteE(offset, wr, (uint64_t *)data, be);
devif_confAccessCb(wr,offset,be);
return pcieCompleter(SC,getId());
}
// parse the busname, device, functions args
bool genericPcieDev::dev_parse_arg(const char *arg){
if (argval("bus", arg, &busName)) {
Debug_more("%s: bus=<%s>\n", Here, busName);
} else if (argval("dev", arg, &device)) {
Debug_more("%s: dev=%d\n", Here, device);
} else if (argval("fun", arg, &function)) {
Debug_more("%s: fun=%d\n", Here, function);
}else{
Debug_err("%s: WARNING: unrecognized arg '%s'\n", Here, arg);
return false;
}
return true;
}
bool
genericPcieDev::dev_check_args(){
if (!busName) {
Debug_err("%s: ERROR: must specify a PCI bus\n",devif_getName());
return false;
}else if(device == -1){
Debug_err("%s: ERROR: must specify device number\n", devif_getName());
return false;
}else if(function == -1){
Debug_err("%s: ERROR: must specify function number\n", devif_getName());
return false;
}
return true;
}
void
genericPcieDev::dev_init_done(int dl){
confSpace->set_debug_level(dl);
pciDebug::set_debug_level(dl);
if(aerCapOffset != -1)
aerCapable = true;
}
void genericPcieDev::pcieDevInfo(){
printf("bus=<%s> dev=%d fun=%d\n",busName,device,function);
printf("configuration space reg info:\n");
confSpace->print();
}
// XXX the functions below "may" need some changes depending upon specific
// PCIE needs. Need to do more research to be sure.
bool genericPcieDev::dump(const char * dirname,const char *file){
char *filename;
FILE *fp;
if(file){
filename = new char[strlen(dirname) + strlen(file) + 6];
sprintf(filename,"%s/%s.pcie",dirname,file);
fp = fopen(filename,"w");
if(!fp){
Debug_err("%s pci dump. fopen failed for %s\n",devif_getName(), filename);
return false;
}
}else
fp = stderr;
pciConfReg * cr;
for(int offset = 0; offset < 0x1000;){
if(offset == PCI_CONF_COMM){
offset += 2;
continue;
}
cr = confSpace->getConfReg(offset);
if(!cr) // hole
offset++;
else{
if (cr->size == 8) {
assert(offset >= PCI_CONF_BASE0 && offset <= PCI_CONF_BASE5);
pcieBaseAddrReg *bar = (pcieBaseAddrReg *)cr;
fprintf(fp,"0x%08lx 0x%08lx 0x%08lx 0x%x %s %s\n",\
offset,bar->getVal(),bar->getMask(),4,bar->name, "Low");
fprintf(fp,"0x%08lx 0x%08lx 0x%08lx 0x%x %s %s\n",\
offset+4,bar->val_32To63,bar->mask_32To63,4,bar->name, "High");
}
else {
fprintf(fp,"0x%08lx 0x%08lx 0x%08lx 0x%x %s\n",\
offset,cr->getVal(),cr->getMask(),cr->size,cr->name);
}
offset += cr->size;
}
}
cr = confSpace->getConfReg(PCI_CONF_COMM);
fprintf(fp,"0x%08lx 0x%08lx 0x%08lx 0x%x %s\n",\
PCI_CONF_COMM,cr->getVal(),cr->getMask(),cr->size,cr->name);
if(fp != stderr)
fclose(fp);
return true;
}
bool
genericPcieDev::dev_module_added(const char *target_name){
if (busName && !strcmp(busName, target_name)) {
busName = target_name;
mmi_instance_t mod = mmi_get_instance(busName);
busIf = (pcieBusIf*)mmi_get_interface(mod, PCIE_BUS_INTERFACE);
if (!busIf) {
Debug_err("%s: ERROR: can't find interface for PCIE bus <%s>\n", Here, busName);
return false;
}else if(!busIf->busif_addDevice(devif_getName(), device, function)) {
Debug_err("%s: ERROR: could not add tp PCIE bus <%s>\n", Here, busName);
return false;
}else{
Debug_info("%s: bus <%s> connected: busif=%p\n", Here, busName, busIf);
}
}
return true;
}
bool
genericPcieDev::dev_module_deleted(const char *target_name){
if (busName && !strcmp(busName, target_name)) {
busName = 0;
busIf = 0;
Debug_info("%s: bus <%s> disconnected\n", Here, busName);
}
return true;
}
// to be called after initPci() has been called
bool genericPcieDev::restore(const char * dirname,const char * file){
char *filename = new char[strlen(dirname) + strlen(file) + 6];
sprintf(filename,"%s/%s.pcie",dirname,file);
char name[128];
char buf[1024];
int off, size;
uint32_t val;
FILE *fp = fopen(filename,"r");
if(!fp){
Debug_err("%s pci restore. fopen failed for %s\n",devif_getBusName(), filename);
return false;
}
pciConfReg * cr;
char str[100];
bool is_commd = false;
for(uint32_t offset = 0; offset < 0x1000;){
if(offset == PCI_CONF_COMM){
offset += 2;
continue;
}
cr = confSpace->getConfReg(offset);
if(!cr) // hole
offset++;
else{
uint8_t byte_offset = 0;
do {
fgets(buf,1024,fp);
char * csr_offset = strtok(buf," ");
off = strtoul(csr_offset,0,0);
char * csr_value = strtok(0," ");
val = strtoul(csr_value,0,0);
if (off != offset) {
// if mis-match, it must be restoring from an old chechpoint,
// and this must be the command register, which always comes last.
assert(off == PCI_CONF_COMM);
printf("can't find PCIE register (offset = 0x%u) in %s.pcie, default value is used\n", offset, file);
is_commd = true;
break;
}
char * csr_mask = strtok(0," ");
char * csr_size = strtok(0," ");
size = strtoul(csr_size,0,0);
cr->write(val,byte_offset,size);
devif_confAccessCb(true,offset,size);
offset += size;
byte_offset += size;
} while (byte_offset < cr->size);
if (is_commd)
break;
}
}
// restore the command register
cr = confSpace->getConfReg(PCI_CONF_COMM);
if (!is_commd)
fscanf(fp,"0x%x\t0x%x\t%s\n",&off,&val,name);
cr->write(val,0,cr->size);
devif_confAccessCb(true,PCI_CONF_COMM,cr->size);
fclose(fp);
return true;
}
void genericPcieDev::addMsiCap(uint8_t next_ptr, uint16_t offset, uint16_t reset_val){
//if(msiCapOffset != -1){
// printf("can;t have more than 1 MSI capability/function");
// return;
//}
msiCapOffset = offset;
confSpace->addConfReg(new pciConfReg(" msi cap id ", 1, msiCapId, 0x0, 0x0), offset);
confSpace->addConfReg(new pciConfReg(" msi next ptr ", 1, next_ptr, 0x0,0x0), offset + MSI_NEXTPTR_OFFSET);
confSpace->addConfReg(new msiCapMsgCntrl(reset_val),offset + MSI_MSGCNTRL_OFFSET);
confSpace->addConfReg(new pciConfReg(" msi addr0 ", 4, 0x0, 0xfffffffc, 0), offset + MSI_MSGADDR0_OFFSET);
bool is64bit = (reset_val >> msiCapMsgCntrl::is64bitAddrCapable_bp) & 1;
if(is64bit){
confSpace->addConfReg(new pciConfReg(" msi addr1 ", 4, 0x0, 0xffffffff), offset + MSI_MSGADDR1_OFFSET);
confSpace->addConfReg(new pciConfReg(" msi data ", 2, 0x0, 0xffff), offset + MSI_MSGDATA64_OFFSET);
}else
confSpace->addConfReg(new pciConfReg(" msi data ", 2, 0x0, 0xffff), offset + MSI_MSGDATA32_OFFSET);
return;
}
void genericPcieDev::addAERCap(uint16_t capOffset, uint16_t nexCapPtr){
char reg_descr[100];
aerCapOffset = capOffset;
snprintf(reg_descr,100,"%s pciExpEnhncdCapHdr",devif_getName());
confSpace->addConfReg(new pciExpEnhncdCapHdr(0x10001 | nexCapPtr << pciExpEnhncdCapHdr::nxtCapOffset_rbp,0x0,0x0,reg_descr),capOffset);// AER capability, next ptr = 0, version = 1;
confSpace->addConfReg(new pciExpAER_UnCorrErrStatReg(),capOffset + UNCORR_ERR_STAT_OFFSET);
confSpace->addConfReg(new pciConfReg("pciExpAER_UnCorrErrMask",4,0x0,aerUncorrErrBitMask,0x0), capOffset + UNCORR_ERR_MASK_OFFSET);
confSpace->addConfReg(new pciConfReg("pciExpAER_UnCorrErrSev",4,0x0,aerUncorrErrBitMask,0x0), capOffset + UNCORR_ERR_SEVERITY_OFFSET);
confSpace->addConfReg(new pciExpAER_CorrErrStatReg(), capOffset + CORR_ERR_STAT_OFFSET);
confSpace->addConfReg(new pciConfReg("pciExpAER_CorrErrMask",4, 0x0, aerCorrErrBitMask,0x0),capOffset + CORR_ERR_MASK_OFFSET);
confSpace->addConfReg(new pciExpAER_ErrCapCntrlReg(0x1e0), capOffset + ADVANCED_ERR_CAPCNTRL_OFFSET);
confSpace->addConfReg(new pciConfReg("header log0",4,0x0,0xffffffff,0x0),capOffset + HDR_LOG_OFFSET);
confSpace->addConfReg(new pciConfReg("header log1",4,0x0,0xffffffff,0x0),capOffset + HDR_LOG_OFFSET + 4);
confSpace->addConfReg(new pciConfReg("header log2",4,0x0,0xffffffff,0x0),capOffset + HDR_LOG_OFFSET + 8);
confSpace->addConfReg(new pciConfReg("header log3",4,0x0,0xffffffff,0x0),capOffset + HDR_LOG_OFFSET + 12);
}
pcieCompleter genericPcieDev::routeMsg(pciExpMsgCode code){
msgRouting r = msgDB->msgCode2Routing(code);
assert( r != routed_by_addr);
assert( r != routed_by_id);
// bridges should not use this function anymore. Only leaf devices are
// allowed.
SAM_DeviceId myId = (dynamic_cast<Module*>(this))->samId;
return busIf->busif_msgAccess((uint8_t)code, r, getId(),&myId);
}
// 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. the routine sets the error bits and sends error messages
// as applicable. This routine also takes care of AER regs if implemented
// it is assumed that this device is not a root port
pcieCompleter genericPcieDev::processErrorRcvrCmpltr(pciExp_Error error, uint32_t * header){
// implement the flow chart section 6.2.5 of rev 1.0a
pciExpErrorType errType = errDB->error2DfltErrType(error);
pciConfReg * devStatReg = confSpace->getConfReg(pciExpCapOffset + PCI_EXP_DEV_STAT_OFFSET);
pciConfReg * devCntrlReg = confSpace->getConfReg(pciExpCapOffset + PCI_EXP_DEV_CTRL_OFFSET);
pciConfReg * cmdReg = confSpace->getConfReg(PCI_CONF_COMM);
pciConfReg * statReg = confSpace->getConfReg(PCI_CONF_STAT);
if(errType == errCorrectable){
// correctable errors
devStatReg->setBit(pciExpDevStatReg::corrErrDet_bp);
if(aerCapable){
pciConfReg * corrErrStatReg = confSpace->getConfReg(aerCapOffset + CORR_ERR_STAT_OFFSET);
corrErrStatReg->setBit(errDB->error2RegBitPos(error));
pciConfReg * corrErrMaskReg = confSpace->getConfReg(aerCapOffset + CORR_ERR_MASK_OFFSET);
bool errorIsMasked = corrErrMaskReg->getBit(errDB->error2RegBitPos(error));
if(errorIsMasked)
return pcieCompleter(SIM_OK);
}
if(devCntrlReg->getBit(pciExpDevCntrlReg::corrErrRepEn_bp))
return routeMsg(MSG_ERR_COR);
else
return pcieCompleter(SIM_OK);
}else{
// un correctable errors
// get the severity from severity register if aer is supported
// else get the defualt severity for this error.
uint8_t severityFatal;
if(aerCapable){
pciConfReg * unCorrSevReg = confSpace->getConfReg(aerCapOffset + UNCORR_ERR_SEVERITY_OFFSET);
severityFatal = unCorrSevReg->getBit(errDB->error2RegBitPos(error));
}else
severityFatal = errType == errUnCorrectable_fatal ? true:false;
if(severityFatal)
devStatReg->setBit(pciExpDevStatReg::ftlErrDet_bp);
else
devStatReg->setBit(pciExpDevStatReg::nonFtlErrDet_bp);
// set the bits in dev stat reg in case its a UR
if(error == unsupportedRequest)
devStatReg->setBit(pciExpDevStatReg::unSprtdReqDet_bp);
if(error == poisonedTLP)
statReg->setBit(pcieStatusReg::DETECTED_PARITY_ERROR);
if(error == completerAbort)
statReg->setBit(pcieStatusReg::SIGNALED_TARGET_ABORT);
if(aerCapable){
pciConfReg * unCorrErrStatReg = confSpace->getConfReg(aerCapOffset + UNCORR_ERR_STAT_OFFSET);
uint32_t unCorrErrStatOldVal = unCorrErrStatReg->getVal();
unCorrErrStatReg->setBit(errDB->error2RegBitPos(error));
pciConfReg * unCorrErrMaskReg = confSpace->getConfReg(aerCapOffset + UNCORR_ERR_MASK_OFFSET);
bool errorIsMasked = unCorrErrMaskReg->getBit(errDB->error2RegBitPos(error));
if(errorIsMasked)
return pcieCompleter(SIM_OK);
if(unCorrErrStatOldVal == 0){
// error is unmasked and this is the first error, set the
// first error pointer bit field
pciConfReg * capCtrlReg = confSpace->getConfReg(aerCapOffset + ADVANCED_ERR_CAPCNTRL_OFFSET);
capCtrlReg->setRange(pciExpAER_ErrCapCntrlReg::firstErrPointer_lbp, \
pciExpAER_ErrCapCntrlReg::firstErrPointer_rbp,errDB->error2RegBitPos(error));
// need to log the header as well
assert(header);
for(int i = 0; i < 4; i++)
confSpace->getConfReg(aerCapOffset + HDR_LOG_OFFSET + i * 4)->setVal(*(header + i));
}
}
// handle UR seperately
if(error == unsupportedRequest){
if(devCntrlReg->getBit(pciExpDevCntrlReg::unsprtdReqRepEn_bp) == 0)
return pcieCompleter(SIM_OK);
else if(severityFatal)
return routeMsg(MSG_ERR_FATAL);
else
return routeMsg(MSG_ERR_NONFATAL);
}
int serrEnable = cmdReg->getBit(pcieCommandReg::SERR_ENABLE);
if(serrEnable){
statReg->setBit(pcieStatusReg::SIGNALED_SYSTEM_ERROR);
}
if(serrEnable || devCntrlReg->getBit(pciExpDevCntrlReg::fatalErrRepEn_bp))
if(severityFatal)
return routeMsg(MSG_ERR_FATAL);
if(serrEnable || devCntrlReg->getBit(pciExpDevCntrlReg::nonFatalErrRepEn_bp ))
if(!severityFatal)
return routeMsg(MSG_ERR_NONFATAL);
return pcieCompleter(SIM_OK);
}
}
// return 0 on success, -1 on error
int genericPcieDev::handleCompletion(pcieCompleter C){
pciConfReg * statReg = confSpace->getConfReg(PCI_CONF_STAT);
if(C.status == SIM_OK)// non posted requests
return 0;
else if(C.status == SC)
return 0;
else if(C.status == UR)
statReg->setBit(pcieStatusReg::RECEIVED_MASTER_ABORT);
else if(C.status == CA)
statReg->setBit(pcieStatusReg::RECEIVED_TARGET_ABORT);
// the next two are not part of specs. the target returns it
// so as to aid functional simulation (eg there is no way to timeout
// in the initiator in this kind of model)
else if(C.status == CMPL_TO)
processErrorRcvrCmpltr(completionTimeout);
else if(C.status == CMPL_POISONED){
pciConfReg * cmdReg = confSpace->getConfReg(PCI_CONF_COMM);
if(cmdReg->getBit(pcieCommandReg::PARITY_ERR_EN))
statReg->setBit(pcieStatusReg::MASTER_DATA_PARITY_ERROR);
}
else if(C.status == SIM_FAIL){
printf("ERROR: internal error in the simulator. returned SIM_FAIL\n");
return -1;
}else{
printf("ERROR: unknow completion <%d >received\n", C.status);
return -1;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
/*****************base address register*********/
pcieBaseAddrReg::pcieBaseAddrReg(const char * name, genericPcieDev * d,uint64_t spaceSize,pcie_space sp , bool ismem32, bool isPrefetch): \
pciConfReg(name,4,0,0 ,(void*)d){
if(d == 0){
printf("baseAddrReg constructor error: must provide pointer to genericPciDev\n");
return;
}
if(spaceSize < 16){
printf("baseAddrReg constructor error: size must be greater than or equal 16\n");
return;
}
int first_set_bit = ffs((uint32_t)spaceSize);
if(first_set_bit == 0){
first_set_bit = ffs((uint32_t) (spaceSize >> 32));
mask = 0;
mask_32To63 = (uint32_t)-1 << (first_set_bit - 1);
}else{
mask_32To63 = 0xffffffff;
mask = (uint32_t)-1 << (first_set_bit - 1);
}
this->space = sp;
this->isPrefetchable = isPrefetch;
this->mapSize = spaceSize;
isMapped = false;
val_32To63 = 0;
mask_32To63 = 0xffffffff;
if(space == PCIE_MEM){
if(ismem32)
bartype = MEM32;
else{
bartype = MEM64;
size = 8;
}
}else
bartype = IO;
switch(space){
case PCIE_MEM:
switch(isPrefetchable){
case true:
val = bartype | PREFETCH;
break;
case false:
val = bartype;
break;
}
break;
case PCIE_IO:
val = IO;
break;
}
return;
}
uint8_t pcieBaseAddrReg::write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
// simpler assumption for now of whole reg reads.
// if assert ever fails then add support for (bytes_to_write <= 4 == true) etc.
assert(bytes_to_write == 4);
assert(byte_offset == 0 or byte_offset == 4);
oldVal = val | (uint64_t)val_32To63 << 32;
if(byte_offset > 3){
if(debug_level >= 2)
printf("Name<%s>,size<0x%x>offset<0x4>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,val_32To63,buf & mask_32To63);
val_32To63 = buf & mask_32To63;
}else
pciConfReg::write(buf, byte_offset, bytes_to_write);
reMap();
return 4;
}
void pcieBaseAddrReg::reMap(){
//read the command register
uint32_t commandRegVal;
pciConfReg * confReg;
confReg = ((genericPcieDev*)data)->confSpace->getConfReg(PCI_CONF_COMM);
if(confReg){
confReg->read(&commandRegVal,confReg->size);
if(space == PCIE_MEM){
bool space_enabled = commandRegVal & 1 << pcieCommandReg::MEM_SPACE;
if(!space_enabled)
return;
if(isMapped)
((genericPcieDev*)data)->unmapSpace(PCIE_MEM,oldVal & ~0xf);
if(bartype == MEM32)
((genericPcieDev*)data)->mapSpace(PCIE_MEM,val&~0xf,mapSize);
else
((genericPcieDev*)data)->mapSpace(PCIE_MEM,(val|(uint64_t)val_32To63 << 32) &~0xf ,mapSize);
}else if(space == PCIE_IO){
bool space_enabled = (commandRegVal & 1 << pcieCommandReg::IO_SPACE);
if(!space_enabled)
return;
if(isMapped)
((genericPcieDev*)data)->unmapSpace(PCIE_IO,oldVal & ~0xf);
((genericPcieDev*)data)->mapSpace(PCIE_IO,val & ~0xf , mapSize);
}
}
}
bool pcieBaseAddrReg::map(){
assert(!isMapped);
//isMapped = true;
if(bartype == MEM64)
isMapped = ((genericPcieDev*)data)->mapSpace(space,(val|(uint64_t)val_32To63 << 32) & ~0xf , mapSize);
else
isMapped = ((genericPcieDev*)data)->mapSpace(space,val & ~0xf , mapSize);
return isMapped;
}
bool pcieBaseAddrReg::unmap(){
assert(isMapped);
//isMapped = false;
if(bartype == MEM64)
isMapped = ((genericPcieDev*)data)->unmapSpace(space,(val|(uint64_t)val_32To63 << 32) & ~0xf);
else
isMapped = ((genericPcieDev*)data)->unmapSpace(space,val & ~0xf);
return isMapped;
}
/********************Command reg************************/
uint8_t pcieCommandReg::write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
assert(byte_offset == 0);
uint8_t ret;
if(bytes_to_write <= 2)
ret = bytes_to_write;
else
ret = 2;
buf &= ~((int32_t)-1 << ret * 8);
//uint32_t changed_bits = val ^ (mask & buf);
uint32_t new_val = val | (mask & buf);
uint32_t changed_bits = new_val ^ val;
if(debug_level >= 2)
printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,val,new_val);
val = new_val;
if(changed_bits & 1 << IO_SPACE){ //I/O space map bit has changed
if(val & 1 << IO_SPACE) //bit set to 1
mapSpace(PCIE_IO);
else
unMapSpace(PCIE_IO); //bit set to 0
}
if(changed_bits & 1 << MEM_SPACE){
if(val & 1 << MEM_SPACE){ //bit set to 1
mapSpace(PCIE_MEM);
}else{
unMapSpace(PCIE_MEM);
}
}
return ret;
}
void pcieCommandReg::mapSpace(pcie_space spc){
//base address regs range from 0x10 to 0x24
pcieBaseAddrReg * baseAddr;
for(int i = 0x10; i < 0x28; i+=4){
baseAddr = dynamic_cast<pcieBaseAddrReg*>(((genericPcieDev*)data)->confSpace->getConfReg(i));
if(baseAddr && baseAddr->space == spc){
baseAddr->map();
if(baseAddr->bartype == pcieBaseAddrReg::MEM64)
i+=4;
}
}
}
void pcieCommandReg::unMapSpace(pcie_space spc){
//base address regs range from 0x10 to 0x24
pcieBaseAddrReg * baseAddr;
for(int i = 0x10; i < 0x28; i+=4){
baseAddr = dynamic_cast<pcieBaseAddrReg*>(((genericPcieDev*)data)->confSpace->getConfReg(i));
if(baseAddr && baseAddr->space == spc){
baseAddr->unmap();
if(baseAddr->bartype == pcieBaseAddrReg::MEM64)
i+=4;
}
}
}