| 1 | // ========== Copyright Header Begin ========================================== |
| 2 | // |
| 3 | // OpenSPARC T2 Processor File: niu_txport_cb.vr |
| 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 "niu_tx_descp.vrh" |
| 36 | #include "dmc_memory_map.vri" |
| 37 | #include "txc_memory_map.vri" |
| 38 | extern mbox_class mbox_id; |
| 39 | #include "cMesg.vrh" |
| 40 | extern Mesg be_msg; |
| 41 | |
| 42 | // To Support MAC Loop back mode |
| 43 | #include "niu_rxtoken.vrh" |
| 44 | |
| 45 | #include "niu_cbclass.vrh" |
| 46 | #include "niu_txcbmgr.vrh" |
| 47 | #include "hostRdCbMgr.vrh" |
| 48 | extern CHostRdCbMgr hostRdCbMgr; |
| 49 | #define TIME {get_time(HI), get_time(LO)} |
| 50 | |
| 51 | |
| 52 | #define HOSTMTU 64 // TMP ONLY |
| 53 | class CTxSemId { |
| 54 | integer id; |
| 55 | integer port_id; |
| 56 | integer noOfReqs; |
| 57 | integer noOfResp; |
| 58 | integer trans_id; |
| 59 | bit[63:0] address[15]; // 15 gathers |
| 60 | integer length[15]; // 15 gathers |
| 61 | integer NoofGathers; |
| 62 | |
| 63 | task SetCb() ; |
| 64 | task spawm_mini_cbs(bit[63:0] address, integer no_of_chunks, integer semId); |
| 65 | task WaitForRelease(integer semId, integer InitialNoOfReqs); |
| 66 | |
| 67 | task new(integer i) { |
| 68 | noOfReqs = -1; |
| 69 | port_id = i; |
| 70 | } |
| 71 | } |
| 72 | task CTxSemId::spawm_mini_cbs(bit[63:0] address, integer no_of_chunks, integer semId){ |
| 73 | |
| 74 | CcbMem cb; |
| 75 | integer i; |
| 76 | bit[63:0] address_incr; |
| 77 | |
| 78 | for(i=0;i<no_of_chunks;i++) { |
| 79 | cb = new(semId); |
| 80 | address_incr = address + HOSTMTU *i; |
| 81 | printf("spawm_mini_cbs - Address - %x i - %d SemId 0 %d \n",address_incr,i,semId); |
| 82 | cb.set(address_incr,GOOD_PACKET) ; |
| 83 | hostRdCbMgr.setCallBack(cb); |
| 84 | } |
| 85 | |
| 86 | } |
| 87 | |
| 88 | task CTxSemId::SetCb() { |
| 89 | // for each address/length - split them into MTU chunks and |
| 90 | // set the callback |
| 91 | |
| 92 | integer i; |
| 93 | integer semId; |
| 94 | integer no_of_chunks; |
| 95 | bit[63:0] adjusted_address[15]; |
| 96 | bit[63:0] adjusted_length[15]; |
| 97 | integer InitialNoOfReqs; |
| 98 | |
| 99 | // This code applicable for N2 only - |
| 100 | for(i=0;i<NoofGathers;i++) { |
| 101 | adjusted_address[i] = (address[i] >>6 )<<6; // 64 bytes aligned |
| 102 | adjusted_length[i] = length[i] + ( address[i] & 6'h3f ); // extra offset due to alignment |
| 103 | } |
| 104 | |
| 105 | noOfReqs = 0; |
| 106 | for(i=0;i<NoofGathers;i++) { |
| 107 | no_of_chunks = adjusted_length[i]/ HOSTMTU + ( (adjusted_length[i]%HOSTMTU) ? 1:0); |
| 108 | noOfReqs+=no_of_chunks; |
| 109 | } |
| 110 | semId = alloc(SEMAPHORE,0,1,0); |
| 111 | printf("After alloc - %d id - %d\n",noOfReqs,semId); |
| 112 | noOfReqs = 0; |
| 113 | |
| 114 | for(i=0;i<NoofGathers;i++) { |
| 115 | no_of_chunks = adjusted_length[i]/ HOSTMTU + ( (adjusted_length[i]%HOSTMTU) ? 1:0); |
| 116 | spawm_mini_cbs(adjusted_address[i],no_of_chunks,semId); |
| 117 | noOfReqs+=no_of_chunks; |
| 118 | printf(" SetCb no_of_chunks - %d \n",no_of_chunks); |
| 119 | } |
| 120 | InitialNoOfReqs = noOfReqs; |
| 121 | printf("InitialNoOfReqs - %d\n",InitialNoOfReqs); |
| 122 | fork { |
| 123 | WaitForRelease(semId, InitialNoOfReqs); |
| 124 | } join none |
| 125 | |
| 126 | |
| 127 | } |
| 128 | task CTxSemId::WaitForRelease(integer semId, integer InitialNoOfReqs) { |
| 129 | |
| 130 | printf("WaitForRelease noOfReqs - %d SemId - %d \n",InitialNoOfReqs,semId); |
| 131 | |
| 132 | @(posedge CLOCK); |
| 133 | while(semaphore_get(WAIT,semId,InitialNoOfReqs) != 1 ) { |
| 134 | repeat(100) @(posedge CLOCK); |
| 135 | } |
| 136 | printf("before mailbox WaitForRelease noOfReqs - %d SemId - %d \n",noOfReqs,semId); |
| 137 | // free this id and send the appropriate message further |
| 138 | mailbox_put(mbox_id.niu_tx_cb[port_id], this.trans_id); |
| 139 | |
| 140 | } |
| 141 | |
| 142 | class CTxPortCbMgr { |
| 143 | integer port_id; |
| 144 | integer cb_enable; |
| 145 | |
| 146 | VeraList_CTxToken PortTxTokenList; |
| 147 | event lock_for_mark; |
| 148 | event freeze_token_list; |
| 149 | |
| 150 | CTxSemId TxSemId[]; |
| 151 | CTxToken TxTokenReqs[]; |
| 152 | CcbTxIdMgr cbTxIdMgr; |
| 153 | CcbTxIdMgr cbTxReqIdMgr; |
| 154 | event lock_port_queue; |
| 155 | task new(integer i=0); |
| 156 | task pushToPortTokenList(CTxToken TxToken); |
| 157 | function integer PullPortTokenList(var CTxToken TxToken) ; |
| 158 | local function integer isQueEmpty() ; |
| 159 | local function integer isQueHeadValid(); |
| 160 | local task forward_token() ; |
| 161 | local task checkForSemRelease(); |
| 162 | local task MarkTokens(integer trans_id); |
| 163 | local task free_transid(integer trans_id); |
| 164 | local task free_req_transid(integer trans_id) ; |
| 165 | local task SetCb(CTxToken TxToken) ; |
| 166 | task CheckReqCbs(CTxToken TxToken) ; |
| 167 | task FreezeCurrentTokenList(); |
| 168 | |
| 169 | |
| 170 | } |
| 171 | |
| 172 | task CTxPortCbMgr::CheckReqCbs(CTxToken TxToken) { |
| 173 | |
| 174 | integer trans_id; |
| 175 | bit[39:0] address; |
| 176 | integer semId; |
| 177 | CcbMem cb; |
| 178 | CTxToken txtoken; |
| 179 | |
| 180 | if(cb_enable) { |
| 181 | fork { |
| 182 | |
| 183 | while(!cbTxReqIdMgr.isAvailable() ) { |
| 184 | repeat(10) @(posedge CLOCK); |
| 185 | } |
| 186 | |
| 187 | trans_id = cbTxReqIdMgr.getTransId(); // tmp for now |
| 188 | address=TxToken.xlate_gather_address[0]; |
| 189 | TxTokenReqs[trans_id] = TxToken; |
| 190 | |
| 191 | semId = alloc(SEMAPHORE,0,1,0); |
| 192 | cb = new(semId); |
| 193 | address = (address >>6 )<<6; // 64 bytes aligned |
| 194 | cb.set(address,READ_REQUEST) ; |
| 195 | hostRdCbMgr.setCallBack(cb); |
| 196 | |
| 197 | while(semaphore_get(WAIT,semId,1) != 1 ) { |
| 198 | repeat(100) @(posedge CLOCK); |
| 199 | } |
| 200 | |
| 201 | txtoken = TxTokenReqs[trans_id]; |
| 202 | txtoken.pgToken.tx_request_seen = 1; |
| 203 | printf("CheckReqCbs:: TX REQUEST SEEN FOR ADDRESS - %x ID - %d\n", address,txtoken.pgToken.gId); |
| 204 | free_req_transid(trans_id); |
| 205 | |
| 206 | } join none |
| 207 | } |
| 208 | |
| 209 | } |
| 210 | |
| 211 | task CTxPortCbMgr::FreezeCurrentTokenList() { |
| 212 | |
| 213 | VeraListIterator_CTxToken item, next_item; |
| 214 | CTxToken Entry; |
| 215 | integer i; |
| 216 | sync(ALL,lock_for_mark); |
| 217 | trigger(OFF,freeze_token_list); |
| 218 | |
| 219 | if(PortTxTokenList.size() ==1) { |
| 220 | Entry = PortTxTokenList.back(); |
| 221 | Entry.CannotTouch = 1; |
| 222 | PortTxTokenList.pop_back(); |
| 223 | PortTxTokenList.push_back(Entry); |
| 224 | } else if(PortTxTokenList.size() >1) { |
| 225 | item = PortTxTokenList.start(); |
| 226 | while( item.neq(PortTxTokenList.finish())) { |
| 227 | Entry = item.data(); |
| 228 | printf("CTxPortCbMgr::FreezeCurrentTokenList Freezing Entry: Token id - %d Size - %d Address - %x \n",Entry.id,PortTxTokenList.size(),Entry.xlate_gather_address[0]); |
| 229 | next_item = PortTxTokenList.erase(item); |
| 230 | Entry.CannotTouch = 1; |
| 231 | PortTxTokenList.insert(next_item,Entry); |
| 232 | item = next_item; |
| 233 | } |
| 234 | } |
| 235 | trigger(ON,freeze_token_list); |
| 236 | } |
| 237 | |
| 238 | task CTxPortCbMgr::pushToPortTokenList(CTxToken TxToken) { |
| 239 | // Look at the addresses, length set the call back table etc here |
| 240 | CTxToken tmp; |
| 241 | |
| 242 | // TxToken.port_data_valid = 0; |
| 243 | if(TxToken.CallBackPending) { |
| 244 | printf("DEBUG Added : cb pending pushToPortTokenList id - %d Size - %d Time - %d \n",TxToken.id,PortTxTokenList.size(),TIME); |
| 245 | } else { |
| 246 | printf("DEBUG Added : cb to be set pushToPortTokenList id - %d Size - %d Time - %d \n",TxToken.id,PortTxTokenList.size(),TIME); |
| 247 | } |
| 248 | if(TxToken.CallBackPending==0) { |
| 249 | fork { |
| 250 | SetCb(TxToken); |
| 251 | } join none |
| 252 | TxToken.CallBackPending = 1; |
| 253 | } |
| 254 | sync(ALL,lock_for_mark); |
| 255 | PortTxTokenList.push_back(TxToken); |
| 256 | tmp = PortTxTokenList.back(); |
| 257 | printf("DEBUG trans_id Added Address - %x Size - %d Time - %d \n",tmp.xlate_gather_address[0],PortTxTokenList.size(),TIME); |
| 258 | |
| 259 | |
| 260 | } |
| 261 | function integer CTxPortCbMgr::PullPortTokenList(var CTxToken TxToken) { |
| 262 | sync(ALL,lock_for_mark); |
| 263 | sync(ALL,freeze_token_list); |
| 264 | if(PortTxTokenList.size()==0) { |
| 265 | PullPortTokenList = 0; |
| 266 | } else { |
| 267 | TxToken = PortTxTokenList.back(); |
| 268 | if(TxToken.CannotTouch) { |
| 269 | PullPortTokenList = 0; |
| 270 | } else { |
| 271 | printf("PullPortTokenList: DEBUG trans_id - Size -%d Address - %x Time - %d id - %d \n",PortTxTokenList.size(),TxToken.xlate_gather_address[0],TIME,TxToken.id); |
| 272 | PortTxTokenList.pop_back(); |
| 273 | PullPortTokenList = 1; |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | task CTxPortCbMgr::SetCb(CTxToken TxToken) { |
| 279 | |
| 280 | CTxSemId TxSemIdlocal; |
| 281 | integer i; |
| 282 | integer trans_id; |
| 283 | |
| 284 | while(!cbTxIdMgr.isAvailable() ) { |
| 285 | repeat(10) @(posedge CLOCK); |
| 286 | } |
| 287 | TxToken.call_back_set = 1; |
| 288 | |
| 289 | TxSemIdlocal= new(port_id); |
| 290 | // TxSemIdlocal.semId = cbTxIdMgr.getSemId(); |
| 291 | // trans_id = cbTxIdMgr.getTransId(); |
| 292 | trans_id = cbTxIdMgr.getTransId(); // tmp for now |
| 293 | TxSemIdlocal.trans_id = trans_id; |
| 294 | |
| 295 | // TxSemId.NoofGathers = TxToken.getNoofGathers(); |
| 296 | TxSemIdlocal.NoofGathers = TxToken.NoofGathers; |
| 297 | |
| 298 | for(i=0;i<TxSemIdlocal.NoofGathers;i++) { |
| 299 | TxSemIdlocal.address[i] = TxToken.xlate_gather_address[i]; |
| 300 | TxSemIdlocal.length[i] = TxToken.gather_pkt_length[i] ; |
| 301 | |
| 302 | } |
| 303 | |
| 304 | TxSemId[trans_id] = new TxSemIdlocal; |
| 305 | for(i=0;i<TxSemId[trans_id].NoofGathers;i++) { |
| 306 | printf("SetCb: DEBUG trans_id - %d Address - %x i = %d \n",trans_id,TxSemId[trans_id].address[i],i); |
| 307 | printf("Token: DEBUG trans_id - %d Address - %x i = %d \n",trans_id,TxToken.xlate_gather_address[i],i); |
| 308 | } |
| 309 | |
| 310 | TxSemId[trans_id].SetCb(); |
| 311 | } |
| 312 | |
| 313 | task CTxPortCbMgr::new(integer i=0) { |
| 314 | port_id = i; |
| 315 | PortTxTokenList = new(); |
| 316 | trigger(ON,lock_port_queue); |
| 317 | trigger(ON,lock_for_mark); |
| 318 | trigger(ON,freeze_token_list); |
| 319 | |
| 320 | if (get_plus_arg(CHECK, "SIU_CB_ENABLE")) { |
| 321 | cb_enable = 1; |
| 322 | } else { |
| 323 | cb_enable = 0; |
| 324 | } |
| 325 | |
| 326 | cbTxIdMgr = new(1000); |
| 327 | cbTxReqIdMgr = new(5000); |
| 328 | fork{ |
| 329 | forward_token(); |
| 330 | } join none |
| 331 | fork { |
| 332 | checkForSemRelease(); |
| 333 | } join none |
| 334 | } |
| 335 | function integer CTxPortCbMgr::isQueEmpty() { |
| 336 | if(PortTxTokenList.size()) { |
| 337 | isQueEmpty = 0; |
| 338 | } else { |
| 339 | isQueEmpty = 1; |
| 340 | } |
| 341 | } |
| 342 | function integer CTxPortCbMgr::isQueHeadValid() { |
| 343 | CTxToken TxToken; |
| 344 | printf("CTxPortCbMgr::isQueHeadValid Size - %d \n",PortTxTokenList.size()); |
| 345 | if(PortTxTokenList.size()==0) isQueHeadValid=0; |
| 346 | else { |
| 347 | TxToken = PortTxTokenList.front(); |
| 348 | isQueHeadValid = TxToken.port_data_valid; |
| 349 | printf("CTxPortCbMgr::isQueHeadValid Valid - %d Address - %x \n",isQueHeadValid,TxToken.xlate_gather_address[0]); |
| 350 | |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | task CTxPortCbMgr::checkForSemRelease() { |
| 355 | integer trans_id; |
| 356 | integer no_of_entries; |
| 357 | while(1) { |
| 358 | @(posedge CLOCK); |
| 359 | no_of_entries = mailbox_get(WAIT,mbox_id.niu_tx_cb[port_id], trans_id); |
| 360 | printf("Before Sync ALL Time - %d \n",TIME); |
| 361 | sync(ALL,lock_port_queue); |
| 362 | printf("After Sync ALL Time - %d \n",TIME); |
| 363 | |
| 364 | printf("checkForSemRelease releasing %d \n",trans_id); |
| 365 | sync(ALL,freeze_token_list); |
| 366 | trigger(OFF,lock_for_mark); |
| 367 | MarkTokens(trans_id); |
| 368 | trigger(ON,lock_for_mark); |
| 369 | } |
| 370 | } |
| 371 | task CTxPortCbMgr::MarkTokens(integer trans_id) { |
| 372 | bit[63:0] packet_address; |
| 373 | VeraListIterator_CTxToken item, next_item; |
| 374 | CTxToken Entry; |
| 375 | bit match; |
| 376 | integer status; |
| 377 | integer i; |
| 378 | |
| 379 | packet_address = TxSemId[trans_id].address[0]; |
| 380 | for(i=0;i<TxSemId[trans_id].NoofGathers;i++) { |
| 381 | printf("MarkTokens DEBUG trans_id - %d Address - %x i = %d Size - %d Time - %d \n",trans_id,TxSemId[trans_id].address[i],i,PortTxTokenList.size(),TIME); |
| 382 | } |
| 383 | // scan through the token list for this address and mark it good |
| 384 | match = 0; |
| 385 | item = PortTxTokenList.start(); |
| 386 | while(!match & item.neq(PortTxTokenList.finish())) { |
| 387 | Entry = item.data(); |
| 388 | printf("DEBUG packet_address - %x Entry.xlate_gather_address[0] - %x \n",packet_address,Entry.xlate_gather_address[0]); |
| 389 | if(Entry.xlate_gather_address[0] == packet_address) { |
| 390 | next_item = PortTxTokenList.erase(item); |
| 391 | Entry.port_data_valid = 1; |
| 392 | printf(" CTxPortCbMgr::MarkTokens Validating Entry: Token id - %d Size - %d Address - %x \n",Entry.id,PortTxTokenList.size(),packet_address); |
| 393 | PortTxTokenList.insert(next_item,Entry); |
| 394 | match = 1; |
| 395 | } else { |
| 396 | item.next(); |
| 397 | } |
| 398 | } |
| 399 | if(match==0) printf(" SOMETHING WRONG!! CTxPortCbMgr::MarkTokens ERROR Time - %d \n",TIME); |
| 400 | free_transid(trans_id); |
| 401 | |
| 402 | |
| 403 | } |
| 404 | |
| 405 | task CTxPortCbMgr::free_transid(integer trans_id) { |
| 406 | integer status; |
| 407 | status = assoc_index(DELETE,TxSemId,trans_id); |
| 408 | cbTxIdMgr.releaseId(trans_id); |
| 409 | } |
| 410 | task CTxPortCbMgr::free_req_transid(integer trans_id) { |
| 411 | integer status; |
| 412 | status = assoc_index(DELETE,TxTokenReqs,trans_id); |
| 413 | cbTxReqIdMgr.releaseId(trans_id); |
| 414 | } |
| 415 | task CTxPortCbMgr::forward_token() { |
| 416 | CTxToken TxToken; |
| 417 | |
| 418 | while(1) { |
| 419 | while(isQueEmpty()) @(posedge CLOCK); |
| 420 | while(isQueHeadValid()==0) @(posedge CLOCK); |
| 421 | sync(ALL,lock_for_mark); |
| 422 | sync(ALL,freeze_token_list); |
| 423 | TxToken = PortTxTokenList.front(); |
| 424 | printf("DEBUG trans_id Forwarding Token: Address - %x Time - %d id - %d \n",TxToken.xlate_gather_address[0],TIME,TxToken.id); |
| 425 | mailbox_put(mbox_id.mac_opp[this.port_id],TxToken.pgToken); |
| 426 | PortTxTokenList.pop_front(); |
| 427 | } |
| 428 | } |