Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / n2_ncu / include / ncu.h
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: ncu.h
* 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 ============================================
*/
#ifndef __NCU_H__
#define __NCU_H__
/*
* this is the niagara2 ncu module. the original source is taken from legion
* with minor/cosmetic modifications. The name of the relevent functions is
* kept same as in legion so as to allow easy updates.
*
* The original source has related CSRs, which are not needed for this
* module, but are still added(though incomplete in certain instances) in case
* we need it in future.
*/
#include "pthread.h"
#include <assert.h>
#include "module.h"
#include "types.h"
#include "vcpu.h"
#include "cpu_interface.h"
static const char* piu_regions[] = {"cfgio","mem32","mem64","piu_8mb","unknown"};
extern "C"{
static int access_ncu(uint32_t cpuid, void* obj, uint64_t paddr, mmi_bool_t wr, uint32_t size, uint64_t* buf, uint8_t bytemask);
int n2ncu_ui_cmd(void*, int argc, char * argv[]);
}
class n2Ncu:public Module{
public:
#define MASK64( _high, _low ) ( ( (uint64_t)((~(uint64_t)0)>>(63-(_high))) ) & ( (uint64_t)( (~(uint64_t)0)<<(_low)) ) )
#define GETMASK64(x, hi, lo) (((uint64_t)(x) & MASK64((hi), (lo)))>>(lo))
/* src/procs/sunsparc/libniagara2/include/niagara2_device.h */
static const uint64_t NCU_CSR_BASE = 0x8000000000;
static const uint64_t NCU_CSR_SIZE = 0x100000000;
static const uint64_t PIU_MAX_REGION = 4;
static const uint64_t NCU_REG_MASK = 0x4ffff;
static const uint64_t NCU_TARGETS = 64; /* number of virtual cores */
static const uint64_t NCU_DEV_MAX = 128; /* max number of device Ids */
static const uint64_t NCU_DEV_ERR = 1; /* device Id for ECC error */
static const uint64_t NCU_DEV_SSI = 2; /* device Id for SSI interrupt */
static const uint64_t NCU_DEV_NIU_LB = 64; /* device Id range for NIU interrupt */
static const uint64_t NCU_DEV_NIU_UB = NCU_DEV_MAX-1;
static const uint64_t NCU_MONDO_INT_MASK = 0x40fff;
static const uint64_t NCU_MONDO_INT_BUSY = MASK64(6,6);
static const uint64_t NCU_SOC_MASK = MASK64(42,40)|MASK64(38,37)|MASK64(35,34)|MASK64(32,31)|MASK64(29,0);
static const uint64_t NCU_INT_MAN_MASK = NCU_DEV_MAX*8;
uint64_t NCU_INT_MAN_CPUID(uint64_t n){ return ((n&MASK64(13,8))>>8); }
static const uint64_t NCU_INT_ACK = 0;
static const uint64_t NCU_INT_NACK = -1;
static const uint64_t PIU_REGION_OFFSET_MASK = MASK64(35,24);
static const uint64_t PIU_REGION_OFFSET_MASK_HI = MASK64(39,36);
struct ncu_reg_t{
uint64_t int_man[NCU_DEV_MAX];
uint64_t mondo_int_vec;
uint64_t ser_num;
uint64_t efu_stat;
uint64_t bank_enb;
uint64_t bank_enb_stat;
uint64_t l2_idx_hash_en;
uint64_t l2_idx_hash_en_stat;
uint64_t pcie_a_mem32_offset_base;
uint64_t pcie_a_mem32_offset_mask;
uint64_t pcie_a_mem64_offset_base;
uint64_t pcie_a_mem64_offset_mask;
uint64_t pcie_a_iocon_offset_base;
uint64_t pcie_a_iocon_offset_mask;
uint64_t pcie_a_fsh;
uint64_t soc_esr;
uint64_t soc_log_enb;
uint64_t soc_intr_enb;
uint64_t soc_err_inject;
uint64_t soc_fatal_enb;
uint64_t soc_sii_err_syndrome;
uint64_t soc_ncu_err_syndrome;
uint64_t mondo_int_data0[NCU_TARGETS];
uint64_t mondo_int_data1[NCU_TARGETS];
uint64_t mondo_int_busy[NCU_TARGETS];
};
struct map_info_t{
uint64_t base;
uint64_t mask;
uint64_t size;
int func;
bool enable;
uint8_t priority;
int align_size;
int reverse_endian;
void info(){
printf("base<%llx>size<%llx>mask<%llx>en<%d>\n",base,size,mask,enable);
}
};
enum piu_region_t{
PIU_REGION_CFGIO = 0,
PIU_REGION_MEM32 = 1,
PIU_REGION_MEM64 = 2,
PIU_REGION_8MB = 3,
PIU_REGION_UNMAPPED
};
enum ncu_reg_offset_t{
INT_MAN = 0x00000,
MONDO_INT_VEC = 0x00a00,
SER_NUM = 0x01000,
EFU_STAT = 0x01008,
CORE_AVAIL = 0x01010,/* same as ASI_CORE_AVAILABLE */
BANK_AVAIL = 0x01018,
BANK_ENABLE = 0x01020,
BANK_ENABLE_STATUS = 0x01028,
L2_IDX_HASH_EN = 0x01030,
L2_IDX_HASH_EN_STATUS = 0x01038,
PCIE_A_MEM32_OFFSET_BASE = 0x02000,
PCIE_A_MEM32_OFFSET_MASK = 0x02008,
PCIE_A_MEM64_OFFSET_BASE = 0x02010,
PCIE_A_MEM64_OFFSET_MASK = 0x02018,
PCIE_A_IOCON_OFFSET_BASE = 0x02020,
PCIE_A_IOCON_OFFSET_MASK = 0x02028,
PCIE_A_FSH = 0x02030,
SOC_ESR = 0x03000,
SOC_LOG_ENABLE = 0x03008,
SOC_INTERRUPT_ENABLE = 0x03010,
SOC_ERROR_INJECTION = 0x03018,
SOC_FATAL_ERROR_ENABLE = 0x03020,
SOC_PENDING_ERROR_STATUS = 0x03028,/* same as SOC_ESR */
SOC_SII_ERROR_SYNDROME = 0x03030,
SOC_NCU_ERROR_SYNDROME = 0x03038,
MONDO_INT_DATA0 = 0x40000,
MONDO_INT_DATA1 = 0x40200,
MONDO_INT_ADATA0 = 0x40400,
MONDO_INT_ADATA1 = 0x40600,
MONDO_INT_BUSY = 0x40800,
MONDO_INT_ABUSY = 0x40a00
};
/*
* XXX need an interface to read asi registers from vonk to add support for
* ASI registers available through NCU
*/
/*
* a list of registers that will be dumped and restored by this module.
* in case more registers are added, or some offsets change or any
* incompatible change happens, and there exist dumps with old format that need to be
* supported, then create a new dumpRegsV2[]. The restore
* function should be able to differtiate and handle correctly the
* different versions. Otherwise just modify the V1 array and dump/restore
* functions as needed.
*/
static const uint64_t dumpRegsV1[25];
private:
const char * current_dump_version;
bool UINT64_RANGE_CHECK(uint64_t _low, uint64_t _val, uint64_t _high){
return ((_val - _low) < (_high - _low));
}
void ASSIGN_NCU(uint64_t& _n,uint64_t _m,uint64_t val, uint64_t offset){
_n = val;
if(0LL != (val & ~(_m)))
debug_err("%s: WARNING: attempt to write to reserved field in NCU\n"
" Write 0x%llx to register %s (offset %llx)\n",
getName(), val, ncu_reg_name(offset),offset);
debug_more("%s: assigned %llx to register %s\n",getName(),val,ncu_reg_name(offset));
}
const char *ncu_reg_name(uint64_t reg);
void niagara2_pcie_mapping(piu_region_t region);
public: // external interface fns. that can be called by other modules/system
int access_regs(uint32_t cpuid, uint64_t paddr, mmi_bool_t wr, uint32_t size,\
uint64_t* buf, uint8_t bytemask);
const map_info_t* getMap(piu_region_t region){ return &map[region]; }
// send mondo to target strand. return either ACK = 0, or NACK = -1
int sendPiuMondo(VCPU_InterruptRequest * r){
extern Vcpu *g_vcpu[NCPU_MAX];
debug_more("%s:sending interrupt to strand %x\n",getName(),r->itid);
int vector = regs.mondo_int_vec & 0x3f;
int target = r->itid;
int busy = regs.mondo_int_busy[target] >> 6 & 0x1;
if(busy)
return NCU_INT_NACK;
regs.mondo_int_data0[target] = r->data[0];
regs.mondo_int_data1[target] = r->data[1];
regs.mondo_int_busy[target] = 1 << 6;
r->data[7] = vector;
Vcpu *vcpu = get_vcpu(target);
if (!vcpu)
return NCU_INT_NACK;
vcpu->interrupt(r);
return NCU_INT_ACK;
}
int sendNiuMondo(VCPU_InterruptRequest * r){
extern Vcpu *g_vcpu[NCPU_MAX];
int vector = regs.int_man[r->isid] & 0x3f;
int target = r->itid;
r->data[7] = vector;
debug_more("%s:sending NIU interrupt tid:%x sid/ldg:%x vector:0x%x\n",getName(),r->itid, r->isid, vector);
Vcpu *vcpu = get_vcpu(target);
if (!vcpu)
return NCU_INT_NACK;
vcpu->interrupt(r);
return NCU_INT_ACK;
}
void handle_ui(int argc, char * argv[]);
void ui_cmd_usage(){
printf("ui format: %s <command> <command args> ... \n",getName());
printf("%s supports following UI commands\n",getName());
printf(" dump [<filename>]\n\
dump the CSR contents to \'filename\' \n\
default is stderr\n\
dump format is: <csr name> <csr offset> <csr value>\n");
printf(" restore <filename>\n\
restore the CSR contents from \'filename\' \n\
restore file format is same as dump file format\n");
printf(" debug [<level>]\n\
set the debug level for debug prints to \'level\'\n\
if \'level\' not provided, print current debug level\n\
\'level\' = [0|1|2]\n");
}
public: // module interface
const char *get_help(){ return Module::get_help_string(); }
bool parse_arg(const char *){ return true; }
bool check_args(){return true; }
void init_done(){
mmi_map_physio(NCU_CSR_BASE,NCU_CSR_SIZE,(void*)this,access_ncu);
return;
}
void module_added(mmi_instance_t, const char*){ return; }
void module_deleted(mmi_instance_t, const char*){ return; }
void modinfo(){
printf("%s: N2 NCU module\n"
"iomap base<%llx size<%llx>\n",getName(), NCU_CSR_BASE,NCU_CSR_SIZE);
printf("PCIE MAP -->\n");
for(int i = 0; i < 3; i++){
printf("%s",piu_regions[i]);
map[i].info();
}
}
void *get_interface(const char*){ return (void*)this; }
const char *get_version(){ return "1.0"; }
bool dump(FILE *fp);
bool dump_v1(FILE *fp);
bool restore(FILE *fp);
bool restore_v1(FILE *fp);
n2Ncu(const char *_modname, const char *_instance_name);
~n2Ncu(){}
private:
ncu_reg_t regs;
map_info_t map[PIU_MAX_REGION];
int node_id;
pthread_mutex_t ncu_lock;
void ncu_init();
};
#endif // __NCU_H__