// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: sam_piu.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 "dev_registry.h"
extern devRegistry
* samDevs
;
static const char *n2piu_help
= "SAM N2 NCU module\n\
sysconf n2_piu <instance_name> ncu=<ncu name>\n\
For UI help type <instance name>\n\
For module specific info type \"modinfo <instance name>\"";
static int access_piu(uint32_t cpuid
, void* obj
, uint64_t paddr
, mmi_bool_t wr
, \
uint32_t size
, uint64_t* buf
, uint8_t bytemask
){
samPiu
* sp
= (samPiu
*)obj
;
return sp
->handlePio(cpuid
,paddr
,wr
,size
,buf
,bytemask
);
int n2piu_ui_cmd(void * obj
, int argc
, char * argv
[]){
samPiu
* i
= (samPiu
*)obj
;
i
->handle_ui(argc
, argv
);
Module
* Module::create(const char *_modname
, const char *_instance_name
){
return new samPiu(_modname
, _instance_name
);
samPiu::samPiu(const char *_modname
, const char *_instance_name
)
: Module(_modname
, _instance_name
){
piuModel
.proc_type_namep
= strdup("n2");
piuModel
.config_devp
= 0;
piuModel
.config_procp
= 0;
piuModel
.sam_piu
= (void*)this;
* init PIU CSR with power on reset
* init error lookup table
subordinate_bus_no
= 0xff;
N2_PIU_VERSION
= strdup("1.0");
for(int i
= 0; i
< 64; i
++)
assert(pthread_mutex_init(&intxMutex
,NULL
)==0);
assert(pthread_mutex_init(&pendIntMutex
,NULL
)==0);
assert(pthread_mutex_init(&piuMutex
,NULL
)==0);
for (int i
= 0; i
< 32; i
++)
assert(pthread_mutex_init(&msiMutex
[i
],NULL
)==0);
mmi_register_instance_cmd(getInstance(),n2piu_help
,n2piu_ui_cmd
);
assert(pthread_mutex_init(&ncuMutex
,NULL
)==0);
const char * Module::get_help_string(){
const char * samPiu::get_help(){
return Module::get_help_string();
const char * samPiu::get_version(){
printf("SAM-Legion PIU module\n");
printf("IOMAP a) base<%llx> size<%llx>\n",PIU_CSR_BASE
,PIU_CSR_SIZE
);
printf(" b) base<%llx> size<%llx>\n",PIU_PCIE_BASE
,PIU_PCIE_SIZE
);
printf("pri_bus <%d>, sec_bus<%d>, device<%d>, function<%d>\n",\
primary_bus_no
, secondary_bus_no
, device
, function
);
bool samPiu::parse_arg(const char *arg
){
if (argval("bus", arg
, &bus
)){
debug_more("%s: bus = %s\n", instance_name
, bus
);
}else if (argval("ncu", arg
, &ncu
)){
debug_more("%s: ncu = %s\n", instance_name
, ncu
);
bool samPiu::check_args(){
debug_err("%s: ERROR: must specify downstream pcie bus name\n",getName());
void samPiu::module_added(mmi_instance_t i
, const char *target_name
){
if(bus
&& !strcmp(target_name
,bus
)){
busIf
= (pcieBusIf
*)mmi_get_interface(i
,PCIE_BUS_INTERFACE
);
debug_err("%s: FATAL ERROR, could not get bus interface for %s\n",getName
,bus
);
busIf
->setBridgeIf((genericPcieDevIf
*)this);
}else if(ncu
&& !strcmp(ncu
,target_name
)){
ncuIf
= (n2Ncu
*)mmi_get_interface(i
,"ncu interface");
debug_err("%s: FATAL ERROR, could not get ncu interface for %s\n",getName
,ncu
);
void samPiu::module_deleted(mmi_instance_t i
, const char *target_name
){
if(bus
&& !strcmp(bus
,target_name
)){
void *samPiu::get_interface(const char *name
){
// no one should be calling this interface, since the bus's bridge interface
// is set by the bridge itself (for PIU in module_added)
if( !strcmp(name
,GENERIC_PCIE_DEV_INTERFACE
) )
return (genericPcieDevIf
*)this;
void samPiu::init_done(){
mmi_map_physio(PIU_CSR_BASE
,PIU_CSR_SIZE
,(void*)this,access_piu
);
mmi_map_physio(PIU_PCIE_BASE
,PIU_PCIE_SIZE
,(void*)this,access_piu
);
mmi_register_event(1000,samPiu_1ms_callback
,(void*)this,0);
void samPiu::timer_callback(){
// register a callback that fires every 10ms. Looks for any nacked
// interrupt by NCU and sends it if one exists. If the interrupt is
// nacked again, try it again later.
pthread_mutex_lock(&ncuMutex
);
VCPU_InterruptRequest
* ir
= irql
.front();
int stat
= ncuIf
->sendPiuMondo(ir
);
// don't really expect this to happen, but if it does, just try again
debug_more("%s:interrupt nacked by NCU after 1ms delay !!\n",getName());
debug_more("%s 1ms cb: sent interrupt to itid %d\n",getName(),irql
.front()->itid
);
// remove the irq and delete it since the interrupt has been sent
event_fire_time
= mmi_get_time()+1000;
mmi_register_event(event_fire_time
,samPiu_1ms_callback
,(void*)this,0);
pthread_mutex_unlock(&ncuMutex
);
void samPiu_1ms_callback(void * obj
, void * ){
samPiu
* t
= (samPiu
*) obj
;
pcieCompleter
samPiu::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
){
// XXX place the dma record identifier 'id' here XXX //
dev_access_t type
= wr
?DA_Store
:DA_Load
;
dev_mode_t md
= mode
== mem_addr32
?PCIE_IS32
:PCIE_IS64
;
for(int i
= 0; i
< 8; i
++)
count
+= (length
- 2) * 4;
uint8_t * data_ptr
= (uint8_t*)data
;
//debug_more("%s:devif_memAccess %s,length 0x%x, be 0x%x, count 0x%x\n", \
getName(),wr
?"write":"read",length
,be
,count
);
debug_more("%s: device %s DMA %s 0x%x bytes\n",getName(),samDevs
->getName(*id
),wr
?"out":"in",count
);
// break down the requests on 8K boundary (smallest page size)
int bytes_in_page
= (8*1024) - addr
% (8*1024);
int bytes_to_transfer
= count
> bytes_in_page
? bytes_in_page
:count
;
ret
&= piu_dma_access(&piuModel
,addr
,data_ptr
,bytes_to_transfer
,reqId
,type
,md
,*id
);
addr
+= bytes_to_transfer
;
data_ptr
+= bytes_to_transfer
;
count
-= bytes_to_transfer
;
return pcieCompleter(SC
,getReqId());
return pcieCompleter(CA
,getReqId()); // XXX ???
pcieCompleter
samPiu::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
){
// XXX create trace records for device 'id' INTX interrupts here XXX //
debug_more("%s: device %s interrupt %s\n",getName(),samDevs
->getName(*id
),messageCode
<=MSG_Assert_INTD
? "assert":"deassert");
setIntx(reqId
& 0xff, 0, true);
piu_assert_intx(&piuModel
,0,reqId
>> 3 & 0x1f);
setIntx(reqId
& 0xff, 1, true);
piu_assert_intx(&piuModel
,1,reqId
>> 3 & 0x1f);
setIntx(reqId
& 0xff, 2, true);
piu_assert_intx(&piuModel
,2,reqId
>> 3 & 0x1f);
setIntx(reqId
& 0xff, 3, true);
piu_assert_intx(&piuModel
,3,reqId
>> 3 & 0x1f);
setIntx(reqId
& 0xff, 0, false);
piu_deassert_intx(&piuModel
,0,reqId
>> 3 & 0x1f);
setIntx(reqId
& 0xff, 1, false);
piu_deassert_intx(&piuModel
,1,reqId
>> 3 & 0x1f);
setIntx(reqId
& 0xff, 2, false);
piu_deassert_intx(&piuModel
,2,reqId
>> 3 & 0x1f);
setIntx(reqId
& 0xff, 3, false);
piu_deassert_intx(&piuModel
,3,reqId
>> 3 & 0x1f);
debug_err("%s:devif_msgAccess: message code %x not supported yet\n", \
int samPiu::handlePio(uint32_t cpuid
,uint64_t paddr
, mmi_bool_t wr
, \
uint32_t size
, uint64_t* buf
, uint8_t bytemask
){
memop
= (MACCESS
)(memop
| MA_Ld
);
memop
= (MACCESS
)(memop
| MA_St
);
if(wr
&& (paddr
== PIU_CSR_BASE
+ PIU_DMU_PCIE_CONFREG_OFFSET
)){
secondary_bus_no
= (*buf
) >> 24 & 0xff;
primary_bus_no
= (*buf
) >> 8 & 0xff;
device
= (*buf
) >> 3 & 0x1f;
// hook for target of the PIO
s
= piu_cpu_access(&piuModel
,paddr
,memop
,buf
,&target
);
debug_more("%s: accessed %s at 0x%llx\n",getName(),samDevs
->getName(target
),paddr
);
void samPiu::sendMondo(pcie_mondo_t
*m
){
// assume only a single cpu (64 strand) configuration.
int stat
= ncuIf
->sendPiuMondo(&r
);
debug_more("%s:interrupt nacked by NCU\n",getName());
pthread_mutex_lock(&ncuMutex
);
VCPU_InterruptRequest
*ir
= new VCPU_InterruptRequest
;
pthread_mutex_unlock(&ncuMutex
);
debug_more("%s: sent interrupt to strand %d, return stat %d\n",getName(),m
->thread_id
,stat
);
//printf("%s: sent interrupt to strand %d, return stat %d\n",getName(),m->thread_id,stat);
void samPiu::handle_ui(int argc
, char * argv
[]){
}else if(!strcmp(argv
[1],"dump")){
printf("%s dump: error opening file <%s>\n",getName(),argv
[2]);
}else if(!strcmp(argv
[1],"restore")){
printf("%s restore: error opening file <%s>\n",getName(),argv
[2]);
printf("%s restore: no restore filename specified\n",getName());
}else if(!strcmp(argv
[1],"debug")){
debug_level
= atoi(argv
[2]);
printf("%s: set debug level to %d\n",getName(),debug_level
);
printf("%s: current debug level %d\n",getName(),debug_level
);
debug_err("%s: unsupported UI command <%s>\n",getName(),argv
[1]);