970ac989be4ca32fca7741e2ce33020e2f54b64a
// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: pci_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 ============================================
/*****************base address register*********/
baseAddrReg::baseAddrReg(const char * name
, genericPciDev
* d
,uint64_t spaceSize
,pci_space_t sp
, bool isPrefetch
):\
pciConfReg(name
,4,0,0 ,(void*)d
){
printf("baseAddrReg constructor error: must provide pointer to genericPciDev\n");
printf("baseAddrReg constructor error: size must be greater than or equal 16\n");
int first_set_bit
= ffs((uint32_t)spaceSize
);
first_set_bit
= ffs((uint32_t) (spaceSize
>> 32));
mask_32To63
= (uint32_t)-1 << (first_set_bit
- 1);
mask_32To63
= 0xffffffff;
mask
= (uint32_t)-1 << (first_set_bit
- 1);
this->isPrefetchable
= isPrefetch
;
this->mapSize
= spaceSize
;
mask_32To63
= 0xffffffff;
uint8_t baseAddrReg::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;
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
;
pciConfReg::write(buf
, byte_offset
, bytes_to_write
);
void baseAddrReg::reMap(){
//read the command register
confReg
= ((genericPciDev
*)data
)->confSpace
->getConfReg(PCI_CONF_COMM
);
confReg
->read(&commandRegVal
,confReg
->size
);
if(space
== PCI_MEM32
&& (commandRegVal
& 1 << pciCommandReg::MEM_SPACE
)){
((genericPciDev
*)data
)->unMapBar(PCI_MEM32
,oldVal
& ~0xf);
((genericPciDev
*)data
)->mapBar(PCI_MEM32
,val
& ~0xf , mapSize
);
}else if(space
== PCI_MEM64
&& (commandRegVal
& 1 << pciCommandReg::MEM_SPACE
)){
((genericPciDev
*)data
)->unMapBar(PCI_MEM64
,oldVal
& ~0xf);
((genericPciDev
*)data
)->mapBar(PCI_MEM64
,val
& ~0xf , mapSize
);
}else if(space
== PCI_IO
&& (commandRegVal
& 1 << pciCommandReg::IO_SPACE
)){
((genericPciDev
*)data
)->unMapBar(PCI_IO
,oldVal
& ~0xf);
((genericPciDev
*)data
)->mapBar(PCI_IO
,val
& ~0xf , mapSize
);
//printf("internal error base address reg remap()\n");
isMapped
= ((genericPciDev
*)data
)->mapBar(space
,val
& ~0xf , mapSize
);
bool baseAddrReg::unmap(){
isMapped
= ((genericPciDev
*)data
)->unMapBar(space
,val
& ~0xf);
/********************Command reg************************/
uint8_t pciCommandReg::write(uint32_t buf
, uint8_t byte_offset
, uint8_t bytes_to_write
){
assert(byte_offset
== 0);
assert(bytes_to_write
== 2);
//uint32_t changed_bits = val ^ (mask & buf);
uint32_t new_val
= val
| (mask
& buf
);
uint32_t changed_bits
= new_val
^ val
;
printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name
,size
,mask
,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
unMapSpace(PCI_IO
); //bit set to 0
if(changed_bits
& 1 << MEM_SPACE
){
if(val
& 1 << MEM_SPACE
){ //bit set to 1
unMapSpace(PCI_MEM64
); //bit set to 0
void pciCommandReg::mapSpace(pci_space_t spc
){
//base address regs range from 0x10 to 0x24
for(int i
= 0x10; i
< 0x28; i
+=4){
baseAddr
= dynamic_cast<baseAddrReg
*>(((genericPciDev
*)data
)->confSpace
->getConfReg(i
));
if(baseAddr
&& baseAddr
->space
== spc
){
void pciCommandReg::unMapSpace(pci_space_t spc
){
//base address regs range from 0x10 to 0x24
for(int i
= 0x10; i
< 0x28; i
+=4){
baseAddr
= dynamic_cast<baseAddrReg
*>(((genericPciDev
*)data
)->confSpace
->getConfReg(i
));
if(baseAddr
&& baseAddr
->space
== spc
){
/***************************************************************************************************/
genericPciDev::genericPciDev(confHeaderType htype
){
confSpace
= new pciConfSpace(htype
);
for(int i
= 0; i
< 3; i
++){
int_pin_status
[i
] = false;
//////////////////////functions exported to pci bus
pciXactnStatus
genericPciDev::devif_access_w_size(pci_space_t space
, uint64_t paddr
, uint64_t offset
, bool_t wr
, uint64_t* buf
, uint8_t size
, SAM_DeviceId
* id
){
*id
= (dynamic_cast<Module
*>(this))->samId
;
offset
-= device
<< 11 | function
<< 8;
ret
= confSpace
->confAccessSize(offset
,wr
,buf
,size
);
return SIM_INTERNAL_ERROR
;
pciDev_confAccessCb(wr
,offset
,size
);
return pciTarget_ioaccess(offset
,wr
,buf
,size
);
return pciTarget_mem32access(offset
,wr
,buf
,size
);
return pciTarget_mem64access(offset
,wr
,buf
,size
);
printf("Unknown PCI space %d\n",space
);
return SIM_INTERNAL_ERROR
;
pciXactnStatus
genericPciDev::devif_access_w_byte_enable(pci_space_t
, uint64_t paddr
, uint64_t offset
, bool_t wr
, uint64_t* buf
, uint8_t byte_enable
, SAM_DeviceId
* id
){
*id
= (dynamic_cast<Module
*>(this))->samId
;
printf("INTERNAL ERROR : byte enable access not yet supported \n");
/////////////////////////functions to implement device access as target
// generic device does not respond to any access over the bus. hence
// the access terminates in master abort.
// specific devices must override only those access functions, which correspond to
// implemented behaviour.
pciXactnStatus
genericPciDev::pciTarget_ioaccess(uint64_t offset
, bool wr
,uint64_t * buf
, uint8_t size
){
Debug_err("%s: accessing unimplemented address space %s\n", pciDev_getName(), "PCI_IO");
pciXactnStatus
genericPciDev::pciTarget_mem32access(uint64_t offset
, bool wr
,uint64_t * buf
, uint8_t size
){
Debug_err("%s: accessing unimplemented address space %s\n", pciDev_getName(), "PCI_MEM32");
pciXactnStatus
genericPciDev::pciTarget_mem64access(uint64_t offset
, bool wr
,uint64_t * buf
, uint8_t size
){
Debug_err("%s: accessing unimplemented address space %s\n", pciDev_getName(), "PCI_MEM64");
pciXactnStatus
genericPciDev::pciTarget_special_cycle(uint16_t mssg
, uint16_t data
){
pciXactnStatus
genericPciDev::pciTarget_intr_ack(uint64_t *data
){
////////////////////////////////initialization and module related fns
void genericPciDev::pciDevInfo(){
printf("bus=<%s> dev=%d fun=%d\n",busName
,device
,function
);
printf("configuration space reg info:\n");
genericPciDev::dev_module_added(const char *target_name
)
if (busName
&& !strcmp(busName
, target_name
)) {
mmi_instance_t mod
= mmi_get_instance(busName
);
busIf
= (pciBusIf
*)mmi_get_interface(mod
, PCI_BUS_INTERFACE
);
Debug_err("%s: ERROR: can't find interface for PCI bus <%s>\n", Here
, busName
);
}else if(!busIf
->busif_add_device(pciDev_getName(), device
, function
)) {
Debug_err("%s: ERROR: could not add tp PCI bus <%s>\n", Here
, busName
);
ui
->verbose("%s: bus <%s> connected: busif=%p\n", Here
, busName
, busIf
);
if(!interrupt_added
&& busIf
&& (busIf
->busif_add_interrupt(device
,dev_type
, slot_irl
,isMultiFunction
) != -1))
genericPciDev::dev_module_deleted(const char *target_name
){
if (busName
&& !strcmp(busName
, target_name
)) {
Debug_info("%s: bus <%s> disconnected\n", Here
, busName
);
genericPciDev::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
);
Debug_err("%s: WARNING: unrecognized arg '%s'\n", Here
, arg
);
genericPciDev::dev_check_args(){
Debug_err("%s: ERROR: must specify a PCI bus\n", pciDev_getName());
Debug_err("%s: ERROR: must specify device number\n", pciDev_getName());
genericPciDev::dev_init_done(int debug_level
){
int ret
= busIf
->busif_add_interrupt(device
, 0, slot_irl
);
Debug_err("%s:ERROR: failed to be assingned interrupt\n", pciDev_getName());
confSpace
->set_debug_level(debug_level
);
pciDebug::set_debug_level(debug_level
);
/////////////////////////////////functions to called by specific PCI device when acting as bus master
genericPciDev::pciMaster_set_int(int line
, bool raise
){
Module
* m
= dynamic_cast<Module
*>(this);
SAM_DeviceId id
= m
->samId
;
if (line
< 0 || 4 <= line
) {
Debug_err("%s: ERROR: dev_set_int_pin: pin=%d: should be 0..3\n", pciDev_getName(), line
);
if (int_pin_status
[line
] != raise
) {
int_pin_status
[line
] = raise
;
if (busIf
&& interrupt_added
){
busIf
->busif_interrupt_in(raise
,device
, line
,&id
);
pciXactnStatus
genericPciDev::pciMaster_dma(bool wr
, uint64_t vaddr
, void *data
, long count
){
Module
* m
= dynamic_cast<Module
*>(this);
SAM_DeviceId id
= m
->samId
;
return busIf
->busif_dma(wr
,vaddr
, data
, count
,&id
);
Debug_err("%s: ERROR: no bus interface <%s> \n",pciDev_getName());
return SIM_INTERNAL_ERROR
;
pciXactnStatus
genericPciDev::pciMaster_intr_ack_cycle(uint64_t * data
){
return busIf
->busif_intr_ack(data
);
Debug_err("%s: ERROR: no bus interface <%s>\n",pciDev_getName());
return SIM_INTERNAL_ERROR
;
pciXactnStatus
genericPciDev::pciMaster_special_cycle(uint16_t mssg
, uint16_t data
){
return busIf
->busif_special_cycle(mssg
, data
);
Debug_err("%s: ERROR: no bus interface <%s>\n",pciDev_getName());
return SIM_INTERNAL_ERROR
;
pciXactnStatus
genericPciDev::pciMaster_bus_access_w_size(pci_space_t space
, uint64_t paddr
, uint64_t offset
, bool_t wr
, uint64_t* buf
, uint8_t size
){
return busIf
->busif_access_w_size(space
,paddr
,offset
,wr
,buf
,size
);
Debug_err("%s: ERROR: no bus interface <%s>\n",pciDev_getName());
return SIM_INTERNAL_ERROR
;
pciXactnStatus
genericPciDev::pciMaster_bus_access_w_byte_enable(pci_space_t space
, uint64_t paddr
, uint64_t offset
, bool_t wr
, uint64_t* buf
, uint8_t byte_enable
){
return busIf
->busif_access_w_byte_enables(space
,paddr
,offset
,wr
,buf
,byte_enable
);
Debug_err("%s: ERROR: no bus interface <%s>\n",pciDev_getName());
return SIM_INTERNAL_ERROR
;
/////////////////////////////////
bool genericPciDev::dump(const char * dirname
,const char *file
){
char *filename
= new char[strlen(dirname
) + strlen(file
) + 6];
sprintf(filename
,"%s/%s.pci",dirname
,file
);
FILE *fp
= fopen(filename
,"w");
Debug_err("%s pci dump. fopen failed for %s\n",pciDev_getName(), filename
);
for(int offset
= 0; offset
< 0x100;){
if(offset
== PCI_CONF_COMM
){
cr
= confSpace
->getConfReg(offset
);
else if(cr
->isRO()) // Read only register. no need to save
fprintf(fp
,"0x%x\t0x%x\n",offset
,cr
->getVal());
cr
= confSpace
->getConfReg(PCI_CONF_COMM
);
fprintf(fp
,"0x%x\t0x%x\n",PCI_CONF_COMM
,cr
->getVal());
// to be called after initPci() has been called
bool genericPciDev::restore(const char * dirname
,const char * file
){
char *filename
= new char[strlen(dirname
) + strlen(file
) + 6];
sprintf(filename
,"%s/%s.pci",dirname
,file
);
FILE *fp
= fopen(filename
,"r");
Debug_err("%s pci restore. fopen failed for %s\n",pciDev_getName(), filename
);
for(int offset
= 0; offset
< 0x100;){
if(offset
== PCI_CONF_COMM
){
cr
= confSpace
->getConfReg(offset
);
else if(cr
->isRO()) // Read only register. no need to restore
fscanf(fp
,"0x%x\t0x%x\n",&off
,&val
);
cr
->write(val
,0,cr
->size
);
pciDev_confAccessCb(true,offset
,cr
->size
);
// restore the command register
cr
= confSpace
->getConfReg(PCI_CONF_COMM
);
fscanf(fp
,"0x%x\t0x%x\n",&off
,&val
);
cr
->write(val
,0,cr
->size
);
pciDev_confAccessCb(true,PCI_CONF_COMM
,cr
->size
);