Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: etl.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 "etl.hpp" | |
36 | #include "pcie_common/logger.hpp" | |
37 | ||
38 | namespace pcie { | |
39 | ||
40 | /** | |
41 | * This method initializes module registers and flags. | |
42 | * It also spawns threads that handle module operation. | |
43 | */ | |
44 | void etl::init(){ | |
45 | POR_RESET = false; | |
46 | execute_ph = sc_spawn(sc_bind(&etl::execute,this)); | |
47 | req_handler_ph = sc_spawn(sc_bind(&etl::req_handler,this)); | |
48 | cmpl_handler_ph = sc_spawn(sc_bind(&etl::cmpl_handler,this)); | |
49 | ecl_update_ph = sc_spawn(sc_bind(&etl::ecl_update,this)); | |
50 | LOG_INFO << "ETL: SW Reset : threads spawned"; | |
51 | } | |
52 | ||
53 | /** | |
54 | * This thread forwards TLPs in the egress_q to DLL. Non-posted requests are also | |
55 | * forwarded to the RSB. | |
56 | */ | |
57 | void etl::execute(void) { | |
58 | LOG_INFO<<"ETL: execute begin..."; | |
59 | ecc=0; | |
60 | csr_port.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR, ecc); | |
61 | RefPciePacket next_pkt; | |
62 | try{ | |
63 | while(1){ | |
64 | while (!egress_q.empty()){ | |
65 | next_pkt = egress_q.front(); | |
66 | egress_q.pop(); | |
67 | ||
68 | LOG_INFO << "ETL: Send Packet " << next_pkt->getPacketId() << "\n"; | |
69 | //cout << sc_time_stamp() << "\t\t\t\t\t| ETL: Send Packet " << next_pkt->getPacketId() << " to DLL." << endl; | |
70 | if((!next_pkt->isPosted()) && (!next_pkt->isCmpl())) | |
71 | eg_etl_rsb_port.send_packet(next_pkt); | |
72 | dout_port.send_packet(next_pkt); | |
73 | } | |
74 | WAIT(epktRdy_ev); | |
75 | } //end while(1) | |
76 | }//end try | |
77 | catch(sc_exception &e){ | |
78 | LOG_WARNING << "ETL: Out of execute"; | |
79 | } | |
80 | }//end execute() | |
81 | ||
82 | /** | |
83 | * This thread receives TLPs from the ILU interface and enqueues them into | |
84 | * the egress_q, once credit is available. | |
85 | */ | |
86 | void etl::req_handler() { | |
87 | LOG_INFO<<"ETL: req_handler begin..."; | |
88 | RefPciePacket new_pkt; | |
89 | try{ | |
90 | while (1) { | |
91 | req_port.get_packet(new_pkt); | |
92 | //cout<< sc_time_stamp() <<"\t\t\t\t\t| ETL: Recvd Req TLP " <<new_pkt->getPacketId() << " from ilu_intf" <<endl; | |
93 | if (new_pkt->isPosted()) | |
94 | get_p_credit(new_pkt); | |
95 | else | |
96 | get_np_credit(new_pkt); | |
97 | egress_q.push(new_pkt); | |
98 | epktRdy_ev.notify(); | |
99 | } | |
100 | } | |
101 | catch(sc_exception &e){ | |
102 | LOG_WARNING << "ETL: Out of req_handler"; | |
103 | } | |
104 | } | |
105 | ||
106 | /** | |
107 | * This thread receives CMPL TLPs from the ILU interface and enqueues them into | |
108 | * the egress_q, once credit is available. | |
109 | */ | |
110 | void etl::cmpl_handler() { | |
111 | LOG_INFO<<"ETL: cmpl_handler begins..."; | |
112 | try{ | |
113 | RefPciePacket new_pkt; | |
114 | while (1) { | |
115 | cmpl_port.get_packet(new_pkt); | |
116 | //cout<< sc_time_stamp() <<"\t\t\t\t\t| ETL: Recvd Cpl TLP " <<new_pkt->getPacketId() << " from ilu_intf" <<endl; | |
117 | get_cmpl_credit(new_pkt); | |
118 | egress_q.push(new_pkt); | |
119 | epktRdy_ev.notify(); | |
120 | } | |
121 | } | |
122 | catch(sc_exception &e){ | |
123 | LOG_WARNING << "ETL: Out of cmpl_handler"; | |
124 | } | |
125 | } | |
126 | ||
127 | /** | |
128 | * This thread monitors the egress credit limit CSR register and provides updates | |
129 | * to any waiting out-going TLPs. | |
130 | */ | |
131 | void etl::ecl_update() { | |
132 | LOG_INFO << "ETL: ecl_update begins..."; | |
133 | try{ | |
134 | while (1) { | |
135 | WAIT(ecl_ev); | |
136 | ecl = csr_port.read_csr(PEU_CSR_A_TLU_ECL_HW_ADDR); | |
137 | ecl_event.notify(); | |
138 | } | |
139 | } | |
140 | catch(sc_exception &e){ | |
141 | LOG_WARNING << "ETL: Out of ecl_update"; | |
142 | } | |
143 | } | |
144 | ||
145 | /** | |
146 | * This blocking thread waits for available posted credits for out-going TLPs. | |
147 | */ | |
148 | void etl::get_p_credit(RefPciePacket& p) { | |
149 | bool hcAvail = false; | |
150 | bool dcAvail = false; | |
151 | sc_uint<12> cred = (GET_TLP_LEN(p))/4; | |
152 | if((GET_TLP_LEN(p))%4 != 0) cred++; | |
153 | ||
154 | while(1){ | |
155 | ecc = csr_port.read_csr(PEU_CSR_A_TLU_ECC_HW_ADDR); | |
156 | if(ecc[60] == 0x1) | |
157 | hcAvail = true; | |
158 | else if(ecc(19,12)==ecl(19,12)) | |
159 | hcAvail = false; | |
160 | else | |
161 | hcAvail = true; | |
162 | ||
163 | if(p->hasData()){ | |
164 | if(ecl[60] == 0x1) | |
165 | dcAvail = true; | |
166 | else if( (ecl(11,0)-((sc_uint<12>)ecc(11,0)+cred)) %4096 > 2048 ) | |
167 | dcAvail=false; | |
168 | else | |
169 | dcAvail = true; | |
170 | } | |
171 | else | |
172 | dcAvail=true; | |
173 | ||
174 | if(hcAvail && dcAvail){ | |
175 | ecc(19,12) = (sc_uint<8>)ecc(19,12) + 1; | |
176 | if(p->hasData()) ecc(11,0) = (sc_uint<12>)ecc(11,0) + cred; | |
177 | if(p->hasData()) | |
178 | LOG_DEBUG << "ETL: PH consumed (+1) = " << ecc(19,12) << " PD consumed (+" << cred << ") = " << ecc(11,0) ; | |
179 | else | |
180 | LOG_DEBUG << "ETL: PH consumed (+1) = " << ecc(19,12) << " PD consumed (+0) = " << ecc(11,0) ; | |
181 | csr_port.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR, ecc); | |
182 | break; | |
183 | } | |
184 | WAIT(ecl_event); | |
185 | } | |
186 | return; | |
187 | }//end get_p_credit | |
188 | ||
189 | /** | |
190 | * This blocking thread waits for available non-posted credits for out-going TLPs. | |
191 | */ | |
192 | void etl::get_np_credit(RefPciePacket& p) { | |
193 | bool hcAvail = false; | |
194 | bool dcAvail = false; | |
195 | sc_uint<12> cred = (GET_TLP_LEN(p))/4; | |
196 | if((GET_TLP_LEN(p))%4 != 0) cred++; | |
197 | ||
198 | while(1){ | |
199 | ecc = csr_port.read_csr(PEU_CSR_A_TLU_ECC_HW_ADDR); | |
200 | if(ecc[61] == 0x1) | |
201 | hcAvail = true; | |
202 | else if(ecc(39,32)==ecl(39,32)) | |
203 | hcAvail = false; | |
204 | else | |
205 | hcAvail = true; | |
206 | ||
207 | if(p->hasData()){ | |
208 | if(ecl[61] == 0x1) | |
209 | dcAvail = true; | |
210 | else if( (ecl(31,20)-((sc_uint<12>)ecc(31,20)+cred)) %4096 > 2048 ) | |
211 | dcAvail=false; | |
212 | else | |
213 | dcAvail = true; | |
214 | } | |
215 | else | |
216 | dcAvail=true; | |
217 | ||
218 | if(hcAvail && dcAvail){ | |
219 | ecc(39,32) = (sc_uint<8>)ecc(39,32) + 1; | |
220 | if(p->hasData()) ecc(31,20) = (sc_uint<12>)ecc(31,20) + cred; | |
221 | if(p->hasData()) | |
222 | LOG_DEBUG << "ETL: NPH consumed (+1) = " << ecc(39,32) << " NPD consumed (+" << cred << ") = " << ecc(31,20) ; | |
223 | else | |
224 | LOG_DEBUG << "ETL: NPH consumed (+1) = " << ecc(39,32) << " NPD consumed (+0) = " << ecc(31,20) ; | |
225 | csr_port.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR, ecc); | |
226 | break; | |
227 | } | |
228 | WAIT(ecl_event); | |
229 | } | |
230 | return; | |
231 | }//end get_np_credit | |
232 | ||
233 | /** | |
234 | * This blocking thread waits for available cmpl credits for out-going TLPs. | |
235 | */ | |
236 | void etl::get_cmpl_credit(RefPciePacket& p) { | |
237 | bool hcAvail = false; | |
238 | bool dcAvail = false; | |
239 | sc_uint<12> cred = (GET_TLP_LEN(p))/4; | |
240 | if((GET_TLP_LEN(p))%4 != 0) cred++; | |
241 | ||
242 | while(1){ | |
243 | ecc = csr_port.read_csr(PEU_CSR_A_TLU_ECC_HW_ADDR); | |
244 | if(ecc[62] == 0x1) | |
245 | hcAvail = true; | |
246 | else if(ecc(59,52)==ecl(59,52)) | |
247 | hcAvail = false; | |
248 | else | |
249 | hcAvail = true; | |
250 | ||
251 | if(p->hasData()){ | |
252 | if(ecl[62] == 0x1) | |
253 | dcAvail = true; | |
254 | else if( (ecl(51,40)-((sc_uint<12>)ecc(51,40)+cred)) %4096 > 2048 ) | |
255 | dcAvail=false; | |
256 | else | |
257 | dcAvail = true; | |
258 | } | |
259 | else | |
260 | dcAvail=true; | |
261 | ||
262 | if(hcAvail && dcAvail){ | |
263 | ecc(59,52) = (sc_uint<8>)ecc(59,52) + 1; | |
264 | if(p->hasData()) ecc(51,40) = (sc_uint<12>)ecc(51,40) + cred; | |
265 | if(p->hasData()) | |
266 | LOG_DEBUG << "ETL: CH consumed (+1) = " << ecc(59,52) << " CD consumed (+" << cred << ") = " << ecc(51,40) ; | |
267 | else | |
268 | LOG_DEBUG << "ETL: CH consumed (+1) = " << ecc(59,52) << " CD consumed (+0) = " << ecc(51,40) ; | |
269 | csr_port.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR, ecc); | |
270 | break; | |
271 | } | |
272 | WAIT(ecl_event); | |
273 | } | |
274 | return; | |
275 | }//end get_cmpl_credit | |
276 | ||
277 | /** | |
278 | * This thread handles reset behavior of the module. On the arrival of a reset global event, | |
279 | * it issue termination requests to threads in this module. Following the reset exit global event | |
280 | * it invokes init() to re-spawn terminated threads. | |
281 | */ | |
282 | void etl::reset_handler(){ | |
283 | csr_port.set_notify_event(PEU_CSR_A_TLU_ECL_HW_ADDR, &ecl_ev); | |
284 | while(1){ | |
285 | wait(*parent_global_ev); | |
286 | switch(*global_event_type){ | |
287 | case POR_RESET_ENTER: | |
288 | case WMR_RESET_ENTER: | |
289 | LOG_WARNING << "\tETL: WMR/POR_RESET enter signal..."; | |
290 | POR_RESET=true; | |
291 | reset_ev.notify(); | |
292 | while(1){ | |
293 | if(execute_ph.terminated() && req_handler_ph.terminated() && cmpl_handler_ph.terminated() && ecl_update_ph.terminated()) break; | |
294 | wait(execute_ph.terminated_event()|req_handler_ph.terminated_event()|cmpl_handler_ph.terminated_event()|ecl_update_ph.terminated_event()); | |
295 | } | |
296 | LOG_WARNING << "ETL: WMR/POR Reset threads terminated"; | |
297 | while(!egress_q.empty()) egress_q.pop(); | |
298 | LOG_INFO << "ETL: WMR/POR Reset dbs cleared"; | |
299 | break; | |
300 | ||
301 | case POR_RESET_EXIT: | |
302 | case WMR_RESET_EXIT: | |
303 | POR_RESET=false; | |
304 | LOG_INFO << "\tETL: WMR/POR_RESET exit signal..."; | |
305 | init(); | |
306 | break; | |
307 | } | |
308 | } //end while(1) | |
309 | }//end reset_handler() | |
310 | } |