// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: itl.cpp
// Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
// 4150 Network Circle, Santa Clara, California 95054, U.S.A.
// * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 2 of the License.
// This 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 program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// For the avoidance of doubt, and except that if any non-GPL license
// choice is available it will apply instead, Sun elects to use only
// the General Public License version 2 (GPLv2) at this time for any
// software where a choice of GPL license versions is made
// available with the language indicating that GPLv2 or any later version
// may be used, or where a choice of which version of the GPL is applied is
// otherwise unspecified.
// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
// CA 95054 USA or visit www.sun.com if you need additional information or
// ========== Copyright Header End ============================================
#include "pcie_common/logger.hpp"
* This thread receives TLPs from the DLL and enqueues them into fc_q for credit processing.
* Post processing, this TLP is forwarded to the ILU interface for delivery.
LOG_INFO
<< "ITL: execute begin...";
d_in_port
.get_packet(next_pkt
);
LOG_INFO
<< "ITL: Get Packet " << next_pkt
->getPacketId() << "\n";
//cout << sc_time_stamp() << " ITL: Recieved TLP " << next_pkt->getPacketId() << " from DLL." << endl;
//cout << sc_time_stamp() << " ITL: Sending TLP " << next_pkt->getPacketId() << " to ILU_INTF." << endl;
d_out_port
.send_packet(next_pkt
);
LOG_WARNING
<< "ITL: Dropping packet ...";
LOG_WARNING
<<"ITL: Out of execute thread!";
* This thread (i) updates credit counters, (ii) checks for overflows, (iii) checks for malformed
* TLPs and (iv) checks for valid CMPLs with the RSB.
LOG_INFO
<<"ITL: update_ica begin...";
sc_uint
<64> ici_val
, ica_val
;
bool log_rcv_ueh
= false;
sc_uint
<64> peu_diag_reg
= csr_port
.read_csr(PEU_CSR_A_TLU_DIAG_HW_ADDR
);
if( (GET_TLP_EP(in_pkt
) == 1) &&
((in_pkt
->get_byte(TLP_HDR_START
) == tlp_MWr_32
) ||
(in_pkt
->get_byte(TLP_HDR_START
) == tlp_MWr_64
) ||
// (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgRd0) ||
// (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgRd1) ||
// (in_pkt->get_byte(TLP_HDR_START) == tlp_IORd) ||
(in_pkt
->get_byte(TLP_HDR_START
) == tlp_CplD
) )){
LOG_WARNING
<< "TL: Warning: Ingr TLP(MWr32, MWr64, CplD) is POISONed.";
write_error_csr(UE
,12,44,"pp");
log_rcv_ueh
= true; //Log rcv header
} else if( (GET_TLP_EP(in_pkt
) == 1) &&
(in_pkt
->get_byte(TLP_HDR_START
) == tlp_IOWr
||
in_pkt
->get_byte(TLP_HDR_START
) == tlp_CfgWr0
||
in_pkt
->get_byte(TLP_HDR_START
) == tlp_CfgWr1
// || (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgRd0) || (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgRd1)
LOG_WARNING
<< "TL: Warning: Ingr TLP (IOWr, CfgWr0, CfgWr1) is POISONed.";
write_error_csr(UE
,12,44,"pp");
write_error_csr(UE
,20,52,"ur");
log_rcv_ueh
= true; //Log rcv header
} else if( (in_pkt
->get_byte(TLP_HDR_START
) == tlp_IORd
) ||
(in_pkt
->get_byte(TLP_HDR_START
) == tlp_IOWr
) ||
(in_pkt
->get_byte(TLP_HDR_START
) == tlp_MRdLk_32
) ||
(in_pkt
->get_byte(TLP_HDR_START
) == tlp_MRdLk_64
) ||
(in_pkt
->get_byte(TLP_HDR_START
) == tlp_CfgRd0
) ||
(in_pkt
->get_byte(TLP_HDR_START
) == tlp_CfgRd1
) ||
(in_pkt
->get_byte(TLP_HDR_START
) == tlp_CfgWr0
) ||
(in_pkt
->get_byte(TLP_HDR_START
) == tlp_CfgWr1
) ) {
LOG_WARNING
<< "TL: Warning: Ingr TLP is UR. ";
write_error_csr(UE
,20,52,"ur");
log_rcv_ueh
= true; //Log rcv header
ici_val
= csr_port
.read_csr(PEU_CSR_A_TLU_ICI_HW_ADDR
);
ica_val
= csr_port
.read_csr(PEU_CSR_A_TLU_ICA_HW_ADDR
);
rsb_out_port
->transport(in_pkt
,rs2it_err
);
LOG_WARNING
<< "Warning: Error in CMPL.";
icc_val(CHC
) = (sc_uint
<8>)icc_val(CHC
) + 1;
icc_val(CDC
) = (sc_uint
<12>)icc_val(CDC
) + 1;
LOG_DEBUG
<< "ICC Reg : CHC = " << (sc_uint
<8>)icc_val(CHC
) << ", CDC = " << (sc_uint
<12>)icc_val(CDC
);
LOG_DEBUG
<< "ICA Reg : CHC = " << (sc_uint
<8>)ica_val(CHC
) << ", CDC = " << (sc_uint
<12>)ica_val(CDC
);
} else if (in_pkt
->isPosted()) {
//Posted Handling//////////////////////////////////
if(GET_TLP_FMT(in_pkt
)==3 && GET_TLP_TYPE(in_pkt
)>=0x10)
LOG_WARNING
<< "Warning : MsgD TLP received.";
write_error_csr(UE
,20,52,"ur");
log_rcv_ueh
= true; //Log rcv header
in_pkt
->set_control(DROP_TLP_ILUINTF_RECOVER_CREDITS
);//To indicate that this packet is to be dropped by the ilu_intf
} else if(GET_TLP_FMT(in_pkt
)==1 && GET_TLP_TYPE(in_pkt
)>=0x10) {
if(GET_TLP_TC(in_pkt
)!=0){
LOG_WARNING
<< "Warning: Msg TLP received, but TC!=0...";
write_error_csr(UE
,18,50,"mfp");
log_rcv_ueh
= true; //Log rcv header
if(in_pkt
->isMalformed(peu_diag_reg
)) {
LOG_WARNING
<< "TL: Warning: Malformed TLP.";
write_error_csr(UE
,18,50,"mfp");
log_rcv_ueh
= true; //Log rcv header
icc_val(PHC
) = (sc_uint
<8>)icc_val(PHC
) + 1;
if(peu_diag_reg
.range(38,38)!=1 && ( (ica_val(PHC
)-icc_val(PHC
)) % 256 >= 128) && ici_val(PHC
)!=0) {
LOG_WARNING
<< "**TL : Warning: Overflow in PHC**";
write_error_csr(UE
,17,49,"rof");
icc_val(PHC
) = (sc_uint
<8>)icc_val(PHC
) - 1;
if(in_pkt
->isMalformed(peu_diag_reg
)) {
LOG_WARNING
<< "TL: Malformed TLP.";
write_error_csr(UE
,18,50,"mfp");
log_rcv_ueh
= true; //Log rcv header
icc_val(PHC
) = (sc_uint
<8>)icc_val(PHC
) + 1;
if(peu_diag_reg
.range(38,38)!=1 && ( (ica_val(PHC
)-icc_val(PHC
)) % 256 >= 128) && ici_val(PHC
)!=0){
LOG_WARNING
<< "**TL : Warning: Overflow in PHC**";
write_error_csr(UE
,17,49,"rof");
icc_val(PHC
) = (sc_uint
<8>)icc_val(PHC
) - 1;
else if (in_pkt
->hasData()) {
sc_uint
<12> cred
= (GET_TLP_LEN(in_pkt
))/4;
if((GET_TLP_LEN(in_pkt
))%4 != 0) cred
++;
icc_val(PDC
) = (sc_uint
<12>)icc_val(PDC
) + cred
;
if(peu_diag_reg
.range(38,38)!=1 && ((ica_val(PDC
)-icc_val(PDC
)) % 4096 >= 2048) && ici_val(PDC
)!=0){
LOG_WARNING
<< "**TL : Warning: Overflow in PDC**";
write_error_csr(UE
,17,49,"rof");
icc_val(PDC
) = (sc_uint
<12>)icc_val(PDC
) - cred
;
LOG_DEBUG
<< "ICC Reg : PHC = " << (sc_uint
<8>)icc_val(PHC
) << ", PDC = " << (sc_uint
<12>)icc_val(PDC
);
LOG_DEBUG
<< "ICA Reg : PHC = " << (sc_uint
<8>)ica_val(PHC
) << ", PDC = " << (sc_uint
<12>)ica_val(PDC
);
//Non-posted Handling//////////////////////////////////////
if(in_pkt
->isMalformed(peu_diag_reg
)) {
LOG_WARNING
<< "TL: Warning: Malformed TLP.";
write_error_csr(UE
,18,50,"mfp");
log_rcv_ueh
= true; //Log rcv header
icc_val(NHC
) = (sc_uint
<8>)icc_val(NHC
) + 1;
if(peu_diag_reg
.range(38,38)!=1 && ( (ica_val(NHC
)-icc_val(NHC
)) % 256 >= 128) && ici_val(NHC
)!=0){
LOG_WARNING
<< "**TL : Warning: Overflow in NHC**";
write_error_csr(UE
,17,49,"rof");
icc_val(NHC
) = (sc_uint
<8>)icc_val(NHC
) - 1;
else if (in_pkt
->hasData()) {
sc_uint
<12> cred
= (GET_TLP_LEN(in_pkt
))/4;
if((GET_TLP_LEN(in_pkt
))%4 != 0) cred
++;
icc_val(NDC
) = (sc_uint
<12>)icc_val(NDC
) + cred
;
if(peu_diag_reg
.range(38,38)!=1 && ( (ica_val(NDC
)-icc_val(NDC
)) % 4096 >= 2048) && ici_val(NDC
)!=0){
LOG_WARNING
<< "**TL : Warning: Overflow in NDC**";
write_error_csr(UE
,17,49,"rof");
icc_val(NDC
) = (sc_uint
<12>)icc_val(NDC
) - cred
;
LOG_DEBUG
<< "ICC Reg : NHC = " << (sc_uint
<8>)icc_val(NHC
) << ", NDC = " << (sc_uint
<12>)icc_val(NDC
);
LOG_DEBUG
<< "ICA Reg : NHC = " << (sc_uint
<8>)ica_val(NHC
) << ", NDC = " << (sc_uint
<12>)ica_val(NDC
);
} //end if() Header Processing
csr_port
.write_csr(PEU_CSR_A_TLU_ICR_HW_ADDR
,icc_val
);
sc_uint
<64> peu_rcv_ueh1_log_reg
; //PEU Recv Uncorrectable Event Header1 Log Register
sc_uint
<64> peu_rcv_ueh2_log_reg
; //PEU Recv Uncorrectable Event Header2 Log Register
peu_rcv_ueh1_log_reg(63,56) = in_pkt
->get_byte(TLP_HDR_START
+ 0);
peu_rcv_ueh1_log_reg(55,48) = in_pkt
->get_byte(TLP_HDR_START
+ 1);
peu_rcv_ueh1_log_reg(47,40) = in_pkt
->get_byte(TLP_HDR_START
+ 2);
peu_rcv_ueh1_log_reg(39,32) = in_pkt
->get_byte(TLP_HDR_START
+ 3);
peu_rcv_ueh1_log_reg(31,24) = in_pkt
->get_byte(TLP_HDR_START
+ 4);
peu_rcv_ueh1_log_reg(23,16) = in_pkt
->get_byte(TLP_HDR_START
+ 5);
peu_rcv_ueh1_log_reg(15, 8) = in_pkt
->get_byte(TLP_HDR_START
+ 6);
peu_rcv_ueh1_log_reg( 7, 0) = in_pkt
->get_byte(TLP_HDR_START
+ 7);
peu_rcv_ueh2_log_reg(63,56) = in_pkt
->get_byte(TLP_HDR_START
+ 8);
peu_rcv_ueh2_log_reg(55,48) = in_pkt
->get_byte(TLP_HDR_START
+ 9);
peu_rcv_ueh2_log_reg(47,40) = in_pkt
->get_byte(TLP_HDR_START
+10);
peu_rcv_ueh2_log_reg(39,32) = in_pkt
->get_byte(TLP_HDR_START
+11);
if(GET_TLP_FMT(in_pkt
) == 1 || GET_TLP_FMT(in_pkt
) == 3)
peu_rcv_ueh2_log_reg(31,24) = in_pkt
->get_byte(TLP_HDR_START
+12);
peu_rcv_ueh2_log_reg(23,16) = in_pkt
->get_byte(TLP_HDR_START
+13);
peu_rcv_ueh2_log_reg(15, 8) = in_pkt
->get_byte(TLP_HDR_START
+14);
peu_rcv_ueh2_log_reg( 7, 0) = in_pkt
->get_byte(TLP_HDR_START
+15);
csr_port
.write_csr(PEU_CSR_A_RUE_HDR1_HW_ADDR
,peu_rcv_ueh1_log_reg
);
csr_port
.write_csr(PEU_CSR_A_RUE_HDR2_HW_ADDR
,peu_rcv_ueh2_log_reg
);
LOG_WARNING
<<"ITL: Out of update_ica thread!";
* This function updates the requested UE, CE and OE error bits.
void itl::write_error_csr(uint8 err_type
, uint8 primary
, uint8 secondary
, char field_name
[3]){
sc_uint
<64> orig_csr_val
;
sc_uint
<64> new_csr_val
=0;
LOG_INFO
<< "Setting err bit: " << field_name
;
case OE
: orig_csr_val
= csr_port
.read_csr(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR
);
LOG_INFO
<< "Updating OE CSR (orig val: " << orig_csr_val
<< ")";
log_enable
= csr_port
.read_csr(PEU_CSR_A_OE_LOG_HW_ADDR
);
LOG_INFO
<< "OE Log enable : " << log_enable
<< ")";
case UE
: orig_csr_val
= csr_port
.read_csr(PEU_CSR_A_UE_ERR_RW1C_ALIAS_HW_ADDR
);
LOG_INFO
<< "Updating UE CSR (orig val: " << orig_csr_val
<< ")";
log_enable
= csr_port
.read_csr(PEU_CSR_A_UE_LOG_HW_ADDR
);
LOG_INFO
<< "UE Log Enable : " << log_enable
<< ")";
case CE
: orig_csr_val
= csr_port
.read_csr(PEU_CSR_A_CE_ERR_RW1C_ALIAS_HW_ADDR
);
LOG_INFO
<< "Updating CE CSR (orig val: " << orig_csr_val
<< ")";
log_enable
= csr_port
.read_csr(PEU_CSR_A_CE_LOG_HW_ADDR
);
LOG_INFO
<< "CE Log Enable : " << log_enable
<< ")";
default: LOG_ERROR
<< "Warning: undefined error type!";
if(log_enable
.range(primary
,primary
)==1)
if(orig_csr_val
.range(primary
,primary
)!=1)
new_csr_val
.range(primary
,primary
)=1;
else if(orig_csr_val
.range(secondary
,secondary
)!=1)
new_csr_val
.range(secondary
,secondary
)=1;
LOG_WARNING
<< "Warning: Both PRIMARY and SECONDARY of " << field_name
<< "are set.";
case OE
: csr_port
.write_csr(PEU_CSR_A_OE_ERR_RW1S_ALIAS_HW_ADDR
,new_csr_val
);
LOG_INFO
<< "Updating OE CSR (new val : " << new_csr_val
<< ")";
case UE
: csr_port
.write_csr(PEU_CSR_A_UE_ERR_RW1S_ALIAS_HW_ADDR
,new_csr_val
);
LOG_INFO
<< "Updating UE CSR (new val : " << new_csr_val
<< ")";
case CE
: csr_port
.write_csr(PEU_CSR_A_CE_ERR_RW1S_ALIAS_HW_ADDR
,new_csr_val
);
LOG_INFO
<< "Updating CE CSR (new val : " << new_csr_val
<< ")";
* This thread handles reset behavior of the module. On the arrival of a reset global event,
* it issue termination requests to threads in this module. Following the reset exit global event
* it invokes init() to re-spawn terminated threads.
void itl::reset_handler(){
switch(*global_event_type
){
LOG_INFO
<< "\tITL: WMR/POR_RESET enter signal...";
//Notify wait()'s in ITL thread
//Wait for all thread to terminate
if(execute_ph
.terminated() && update_ica_ph
.terminated()) break;
wait(execute_ph
.terminated_event()|update_ica_ph
.terminated_event());
LOG_WARNING
<< "ITL: WMR/POR Reset threads terminated";
while(!fc_q
.empty()) fc_q
.pop();
LOG_WARNING
<< "ITL: WMR/POR Reset dbs cleared";
LOG_INFO
<< "\tITL: WMR/POR_RESET exit signal...";
csr_port
.write_csr(PEU_CSR_A_TLU_ICR_HW_ADDR
,icc_val
);
LOG_INFO
<<"ITL: SW_RESET_EXIT";
* This method initializes module registers and flags.
* It also spawns threads that handle module operation.
execute_ph
= sc_spawn(sc_bind(&itl::execute
,this));
update_ica_ph
= sc_spawn(sc_bind(&itl::update_ica
,this));
LOG_INFO
<< "ITL: SW Reset : threads spawned";