Commit | Line | Data |
---|---|---|
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 | ||
38 | namespace 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) |