Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / model / pcie / tl / itl.cpp
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: itl.cpp
4// Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
5// 4150 Network Circle, Santa Clara, California 95054, U.S.A.
6//
7// * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8//
9// This program is free software; you can redistribute it and/or modify
10// it under the terms of the GNU General Public License as published by
11// the Free Software Foundation; version 2 of the License.
12//
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21//
22// For the avoidance of doubt, and except that if any non-GPL license
23// choice is available it will apply instead, Sun elects to use only
24// the General Public License version 2 (GPLv2) at this time for any
25// software where a choice of GPL license versions is made
26// available with the language indicating that GPLv2 or any later version
27// may be used, or where a choice of which version of the GPL is applied is
28// otherwise unspecified.
29//
30// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
31// CA 95054 USA or visit www.sun.com if you need additional information or
32// have any questions.
33//
34// ========== Copyright Header End ============================================
35#include "itl.hpp"
36#include "pcie_common/logger.hpp"
37
38namespace pcie {
39
40 /**
41 * This thread receives TLPs from the DLL and enqueues them into fc_q for credit processing.
42 * Post processing, this TLP is forwarded to the ILU interface for delivery.
43 */
44 void itl::execute(void){
45 LOG_INFO << "ITL: execute begin...";
46
47 RefPciePacket next_pkt;
48 try{
49 while(1){
50 d_in_port.get_packet(next_pkt);
51 LOG_INFO << "ITL: Get Packet " << next_pkt->getPacketId() << "\n";
52 //cout << sc_time_stamp() << " ITL: Recieved TLP " << next_pkt->getPacketId() << " from DLL." << endl;
53 fc_q.push(next_pkt);
54 inPkt_ev.notify();
55
56 WAIT(fcComp_ev);
57
58 if(!DROP){
59 //cout << sc_time_stamp() << " ITL: Sending TLP " << next_pkt->getPacketId() << " to ILU_INTF." << endl;
60 d_out_port.send_packet(next_pkt);
61 }
62 else {
63 LOG_WARNING << "ITL: Dropping packet ...";
64 DROP = false;
65 }
66 } //end while
67 }//end try
68 catch (sc_exception &e){
69 LOG_WARNING<<"ITL: Out of execute thread!";
70 }
71 }//end execute()
72
73 /**
74 * This thread (i) updates credit counters, (ii) checks for overflows, (iii) checks for malformed
75 * TLPs and (iv) checks for valid CMPLs with the RSB.
76 */
77 void itl::update_ica(){
78 LOG_INFO<<"ITL: update_ica begin...";
79
80 RefPciePacket in_pkt;
81 sc_uint<64> ici_val, ica_val;
82 bool log_rcv_ueh = false;
83
84 icc_val = 0x00;
85
86 try{
87 while (1){
88 WAIT(inPkt_ev);
89
90 in_pkt = fc_q.front();
91 fc_q.pop();
92
93 sc_uint<64> peu_diag_reg = csr_port.read_csr(PEU_CSR_A_TLU_DIAG_HW_ADDR);
94
95 if( (GET_TLP_EP(in_pkt) == 1) &&
96 ((in_pkt->get_byte(TLP_HDR_START) == tlp_MWr_32) ||
97 (in_pkt->get_byte(TLP_HDR_START) == tlp_MWr_64) ||
98 // (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgRd0) ||
99 // (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgRd1) ||
100 // (in_pkt->get_byte(TLP_HDR_START) == tlp_IORd) ||
101 (in_pkt->get_byte(TLP_HDR_START) == tlp_CplD) )){
102 LOG_WARNING << "TL: Warning: Ingr TLP(MWr32, MWr64, CplD) is POISONed.";
103 write_error_csr(UE,12,44,"pp");
104 log_rcv_ueh = true; //Log rcv header
105 DROP=true;
106 } else if( (GET_TLP_EP(in_pkt) == 1) &&
107 (in_pkt->get_byte(TLP_HDR_START) == tlp_IOWr ||
108 in_pkt->get_byte(TLP_HDR_START) == tlp_CfgWr0 ||
109 in_pkt->get_byte(TLP_HDR_START) == tlp_CfgWr1
110 // || (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgRd0) || (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgRd1)
111 )){
112 LOG_WARNING << "TL: Warning: Ingr TLP (IOWr, CfgWr0, CfgWr1) is POISONed.";
113 write_error_csr(UE,12,44,"pp");
114 write_error_csr(UE,20,52,"ur");
115 log_rcv_ueh = true; //Log rcv header
116 DROP=true;
117 } else if( (in_pkt->get_byte(TLP_HDR_START) == tlp_IORd) ||
118 (in_pkt->get_byte(TLP_HDR_START) == tlp_IOWr) ||
119 (in_pkt->get_byte(TLP_HDR_START) == tlp_MRdLk_32) ||
120 (in_pkt->get_byte(TLP_HDR_START) == tlp_MRdLk_64) ||
121 (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgRd0) ||
122 (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgRd1) ||
123 (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgWr0) ||
124 (in_pkt->get_byte(TLP_HDR_START) == tlp_CfgWr1) ) {
125 LOG_WARNING << "TL: Warning: Ingr TLP is UR. ";
126 write_error_csr(UE,20,52,"ur");
127 log_rcv_ueh = true; //Log rcv header
128 } else {
129 ici_val = csr_port.read_csr(PEU_CSR_A_TLU_ICI_HW_ADDR);
130 ica_val = csr_port.read_csr(PEU_CSR_A_TLU_ICA_HW_ADDR);
131
132 if (in_pkt->isCmpl()) {
133 bool rs2it_err;
134 rsb_out_port->transport(in_pkt,rs2it_err);
135 if(rs2it_err){
136 LOG_WARNING << "Warning: Error in CMPL.";
137 DROP=true;
138 } else {
139 icc_val(CHC) = (sc_uint<8>)icc_val(CHC) + 1;
140 if (in_pkt->hasData()) {
141 icc_val(CDC) = (sc_uint<12>)icc_val(CDC) + 1;
142 }
143 LOG_DEBUG << "ICC Reg : CHC = " << (sc_uint<8>)icc_val(CHC) << ", CDC = " << (sc_uint<12>)icc_val(CDC);
144 LOG_DEBUG << "ICA Reg : CHC = " << (sc_uint<8>)ica_val(CHC) << ", CDC = " << (sc_uint<12>)ica_val(CDC);
145 }
146 } else if (in_pkt->isPosted()) {
147 //Posted Handling//////////////////////////////////
148 if(GET_TLP_FMT(in_pkt)==3 && GET_TLP_TYPE(in_pkt)>=0x10)
149 {
150 LOG_WARNING << "Warning : MsgD TLP received.";
151 write_error_csr(UE,20,52,"ur");
152 log_rcv_ueh = true; //Log rcv header
153 //DROP=true;
154 in_pkt->set_control(DROP_TLP_ILUINTF_RECOVER_CREDITS);//To indicate that this packet is to be dropped by the ilu_intf
155 } else if(GET_TLP_FMT(in_pkt)==1 && GET_TLP_TYPE(in_pkt)>=0x10) {
156 //Msg TLp Recvd
157 if(GET_TLP_TC(in_pkt)!=0){
158 LOG_WARNING << "Warning: Msg TLP received, but TC!=0...";
159 write_error_csr(UE,18,50,"mfp");
160 log_rcv_ueh = true; //Log rcv header
161 DROP=true;
162 } else {
163 if(in_pkt->isMalformed(peu_diag_reg)) {
164 LOG_WARNING << "TL: Warning: Malformed TLP.";
165 write_error_csr(UE,18,50,"mfp");
166 log_rcv_ueh = true; //Log rcv header
167 DROP=true;
168 } else {
169 icc_val(PHC) = (sc_uint<8>)icc_val(PHC) + 1;
170 if(peu_diag_reg.range(38,38)!=1 && ( (ica_val(PHC)-icc_val(PHC)) % 256 >= 128) && ici_val(PHC)!=0) {
171 LOG_WARNING << "**TL : Warning: Overflow in PHC**";
172 write_error_csr(UE,17,49,"rof");
173 icc_val(PHC) = (sc_uint<8>)icc_val(PHC) - 1;
174 DROP=true;
175 }
176 }
177 }
178 } else {
179 if(in_pkt->isMalformed(peu_diag_reg)) {
180 LOG_WARNING << "TL: Malformed TLP.";
181 write_error_csr(UE,18,50,"mfp");
182 log_rcv_ueh = true; //Log rcv header
183 DROP=true;
184 } else {
185 icc_val(PHC) = (sc_uint<8>)icc_val(PHC) + 1;
186 if(peu_diag_reg.range(38,38)!=1 && ( (ica_val(PHC)-icc_val(PHC)) % 256 >= 128) && ici_val(PHC)!=0){
187 LOG_WARNING << "**TL : Warning: Overflow in PHC**";
188 write_error_csr(UE,17,49,"rof");
189 icc_val(PHC) = (sc_uint<8>)icc_val(PHC) - 1;
190 DROP=true;
191 }
192 else if (in_pkt->hasData()) {
193 sc_uint<12> cred = (GET_TLP_LEN(in_pkt))/4;
194 if((GET_TLP_LEN(in_pkt))%4 != 0) cred++;
195 icc_val(PDC) = (sc_uint<12>)icc_val(PDC) + cred;
196 if(peu_diag_reg.range(38,38)!=1 && ((ica_val(PDC)-icc_val(PDC)) % 4096 >= 2048) && ici_val(PDC)!=0){
197 LOG_WARNING << "**TL : Warning: Overflow in PDC**";
198 DROP=true;
199 write_error_csr(UE,17,49,"rof");
200 icc_val(PDC) = (sc_uint<12>)icc_val(PDC) - cred;
201 }
202 }
203 }
204 }
205 LOG_DEBUG << "ICC Reg : PHC = " << (sc_uint<8>)icc_val(PHC) << ", PDC = " << (sc_uint<12>)icc_val(PDC);
206 LOG_DEBUG << "ICA Reg : PHC = " << (sc_uint<8>)ica_val(PHC) << ", PDC = " << (sc_uint<12>)ica_val(PDC);
207 } else {
208 //Non-posted Handling//////////////////////////////////////
209 if(in_pkt->isMalformed(peu_diag_reg)) {
210 LOG_WARNING << "TL: Warning: Malformed TLP.";
211 write_error_csr(UE,18,50,"mfp");
212 log_rcv_ueh = true; //Log rcv header
213 DROP=true;
214 } else {
215 icc_val(NHC) = (sc_uint<8>)icc_val(NHC) + 1;
216 if(peu_diag_reg.range(38,38)!=1 && ( (ica_val(NHC)-icc_val(NHC)) % 256 >= 128) && ici_val(NHC)!=0){
217 LOG_WARNING << "**TL : Warning: Overflow in NHC**";
218 write_error_csr(UE,17,49,"rof");
219 icc_val(NHC) = (sc_uint<8>)icc_val(NHC) - 1;
220 DROP=true;
221 }
222 else if (in_pkt->hasData()) {
223 sc_uint<12> cred = (GET_TLP_LEN(in_pkt))/4;
224 if((GET_TLP_LEN(in_pkt))%4 != 0) cred++;
225 icc_val(NDC) = (sc_uint<12>)icc_val(NDC) + cred;
226 if(peu_diag_reg.range(38,38)!=1 && ( (ica_val(NDC)-icc_val(NDC)) % 4096 >= 2048) && ici_val(NDC)!=0){
227 LOG_WARNING << "**TL : Warning: Overflow in NDC**";
228 DROP=true;
229 write_error_csr(UE,17,49,"rof");
230 icc_val(NDC) = (sc_uint<12>)icc_val(NDC) - cred;
231 }
232 }
233 }
234 LOG_DEBUG << "ICC Reg : NHC = " << (sc_uint<8>)icc_val(NHC) << ", NDC = " << (sc_uint<12>)icc_val(NDC);
235 LOG_DEBUG << "ICA Reg : NHC = " << (sc_uint<8>)ica_val(NHC) << ", NDC = " << (sc_uint<12>)ica_val(NDC);
236 } //end if() Header Processing
237 //Update Credits Recvd
238 csr_port.write_csr(PEU_CSR_A_TLU_ICR_HW_ADDR,icc_val);
239 }//end else not UR
240
241 if(log_rcv_ueh){
242 sc_uint<64> peu_rcv_ueh1_log_reg; //PEU Recv Uncorrectable Event Header1 Log Register
243 sc_uint<64> peu_rcv_ueh2_log_reg; //PEU Recv Uncorrectable Event Header2 Log Register
244 peu_rcv_ueh1_log_reg(63,56) = in_pkt->get_byte(TLP_HDR_START+ 0);
245 peu_rcv_ueh1_log_reg(55,48) = in_pkt->get_byte(TLP_HDR_START+ 1);
246 peu_rcv_ueh1_log_reg(47,40) = in_pkt->get_byte(TLP_HDR_START+ 2);
247 peu_rcv_ueh1_log_reg(39,32) = in_pkt->get_byte(TLP_HDR_START+ 3);
248 peu_rcv_ueh1_log_reg(31,24) = in_pkt->get_byte(TLP_HDR_START+ 4);
249 peu_rcv_ueh1_log_reg(23,16) = in_pkt->get_byte(TLP_HDR_START+ 5);
250 peu_rcv_ueh1_log_reg(15, 8) = in_pkt->get_byte(TLP_HDR_START+ 6);
251 peu_rcv_ueh1_log_reg( 7, 0) = in_pkt->get_byte(TLP_HDR_START+ 7);
252
253 peu_rcv_ueh2_log_reg(63,56) = in_pkt->get_byte(TLP_HDR_START+ 8);
254 peu_rcv_ueh2_log_reg(55,48) = in_pkt->get_byte(TLP_HDR_START+ 9);
255 peu_rcv_ueh2_log_reg(47,40) = in_pkt->get_byte(TLP_HDR_START+10);
256 peu_rcv_ueh2_log_reg(39,32) = in_pkt->get_byte(TLP_HDR_START+11);
257 if(GET_TLP_FMT(in_pkt) == 1 || GET_TLP_FMT(in_pkt) == 3)
258 {
259 peu_rcv_ueh2_log_reg(31,24) = in_pkt->get_byte(TLP_HDR_START+12);
260 peu_rcv_ueh2_log_reg(23,16) = in_pkt->get_byte(TLP_HDR_START+13);
261 peu_rcv_ueh2_log_reg(15, 8) = in_pkt->get_byte(TLP_HDR_START+14);
262 peu_rcv_ueh2_log_reg( 7, 0) = in_pkt->get_byte(TLP_HDR_START+15);
263 }
264 csr_port.write_csr(PEU_CSR_A_RUE_HDR1_HW_ADDR,peu_rcv_ueh1_log_reg);
265 csr_port.write_csr(PEU_CSR_A_RUE_HDR2_HW_ADDR,peu_rcv_ueh2_log_reg);
266
267 log_rcv_ueh = false;
268 }
269 fcComp_ev.notify();
270 } // while (1)
271 }//end try
272 catch (sc_exception &e){
273 LOG_WARNING<<"ITL: Out of update_ica thread!";
274 }
275 } // update_ica()
276
277 /**
278 * This function updates the requested UE, CE and OE error bits.
279 */
280 void itl::write_error_csr(uint8 err_type, uint8 primary, uint8 secondary, char field_name[3]){
281 sc_uint<64> orig_csr_val;
282 sc_uint<64> new_csr_val=0;
283 sc_uint<64> log_enable;
284
285 LOG_INFO << "Setting err bit: " << field_name;
286
287 switch(err_type){
288 case OE: orig_csr_val = csr_port.read_csr(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR);
289 LOG_INFO << "Updating OE CSR (orig val: " << orig_csr_val << ")";
290 log_enable = csr_port.read_csr(PEU_CSR_A_OE_LOG_HW_ADDR);
291 LOG_INFO << "OE Log enable : " << log_enable << ")";
292 break;
293 case UE: orig_csr_val = csr_port.read_csr(PEU_CSR_A_UE_ERR_RW1C_ALIAS_HW_ADDR);
294 LOG_INFO << "Updating UE CSR (orig val: " << orig_csr_val << ")";
295 log_enable = csr_port.read_csr(PEU_CSR_A_UE_LOG_HW_ADDR);
296 LOG_INFO << "UE Log Enable : " << log_enable << ")";
297 break;
298 case CE: orig_csr_val = csr_port.read_csr(PEU_CSR_A_CE_ERR_RW1C_ALIAS_HW_ADDR);
299 LOG_INFO << "Updating CE CSR (orig val: " << orig_csr_val << ")";
300 log_enable = csr_port.read_csr(PEU_CSR_A_CE_LOG_HW_ADDR);
301 LOG_INFO << "CE Log Enable : " << log_enable << ")";
302 break;
303 default: LOG_ERROR << "Warning: undefined error type!";
304 return;
305 }
306
307 if(log_enable.range(primary,primary)==1)
308 {
309 if(orig_csr_val.range(primary,primary)!=1)
310 new_csr_val.range(primary,primary)=1;
311 else if(orig_csr_val.range(secondary,secondary)!=1)
312 new_csr_val.range(secondary,secondary)=1;
313 else
314 LOG_WARNING << "Warning: Both PRIMARY and SECONDARY of " << field_name << "are set.";
315 }
316
317 switch(err_type){
318 case OE: csr_port.write_csr(PEU_CSR_A_OE_ERR_RW1S_ALIAS_HW_ADDR,new_csr_val);
319 LOG_INFO << "Updating OE CSR (new val : " << new_csr_val << ")";
320 break;
321 case UE: csr_port.write_csr(PEU_CSR_A_UE_ERR_RW1S_ALIAS_HW_ADDR,new_csr_val);
322 LOG_INFO << "Updating UE CSR (new val : " << new_csr_val << ")";
323 break;
324 case CE: csr_port.write_csr(PEU_CSR_A_CE_ERR_RW1S_ALIAS_HW_ADDR,new_csr_val);
325 LOG_INFO << "Updating CE CSR (new val : " << new_csr_val << ")";
326 break;
327 }
328 return;
329 }//end write_csr_error
330
331 /**
332 * This thread handles reset behavior of the module. On the arrival of a reset global event,
333 * it issue termination requests to threads in this module. Following the reset exit global event
334 * it invokes init() to re-spawn terminated threads.
335 */
336 void itl::reset_handler(){
337 while(1){
338 wait(*parent_global_ev);
339 switch(*global_event_type){
340 case POR_RESET_ENTER:
341 case WMR_RESET_ENTER:
342 LOG_INFO << "\tITL: WMR/POR_RESET enter signal...";
343 POR_RESET=true;
344 //Notify wait()'s in ITL thread
345 reset_ev.notify();
346 //Wait for all thread to terminate
347 while(1){
348 if(execute_ph.terminated() && update_ica_ph.terminated()) break;
349 wait(execute_ph.terminated_event()|update_ica_ph.terminated_event());
350 }
351 LOG_WARNING << "ITL: WMR/POR Reset threads terminated";
352 while(!fc_q.empty()) fc_q.pop();
353 DROP=false;
354 LOG_WARNING << "ITL: WMR/POR Reset dbs cleared";
355 break;
356
357 case POR_RESET_EXIT:
358 case WMR_RESET_EXIT:
359 LOG_INFO << "\tITL: WMR/POR_RESET exit signal...";
360 init();
361 csr_port.write_csr(PEU_CSR_A_TLU_ICR_HW_ADDR,icc_val);
362 break;
363
364 case SW_RESET_EXIT:
365 LOG_INFO<<"ITL: SW_RESET_EXIT";
366 icc_val=0;
367 break;
368 }
369 }//end while(1)
370 }
371
372 /**
373 * This method initializes module registers and flags.
374 * It also spawns threads that handle module operation.
375 */
376 void itl::init(){
377 DROP = false;
378 POR_RESET = false;
379 icc_val = 0x0;
380 execute_ph = sc_spawn(sc_bind(&itl::execute,this));
381 update_ica_ph = sc_spawn(sc_bind(&itl::update_ica,this));
382 LOG_INFO << "ITL: SW Reset : threads spawned";
383 }
384} //namepsace(pcie)