Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / vera / niu_intr / niu_int_mgr.vr
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: niu_int_mgr.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 <vera_defines.vrh>
36#include "niu_int_dev.vrh"
37#include "niu_int_ldg.vrh"
38#include "niu_int_qmgr.vrh"
39#include "niu_int_sidmgr.vrh"
40#include "pio_driver.vrh"
41#ifdef NEPTUNE
42#include "Pcie_defines.vri"
43#include "Pcie_intr_util.vrh"
44#else
45#endif
46
47extern niu_gen_pio gen_pio_drv;
48#define DEASSERT_SEEN 100
49
50
51
52#ifdef NEPTUNE
53extern Pcie_intr_util pcie_intr_util;
54#else
55#endif
56
57extern CNiuIntrQMgr NiuIntrQ;
58
59class CNiuIntrMgr {
60
61 CSidShadowTab SidTab;
62 CNiuLdg ldg[64];
63 bit [63:0] active_ldg;
64
65 // Neptune Specific
66 // event intx_sync[4];
67 integer INTX_BUG_FIX=0;
68 integer intx_sync[4];
69 bit[63:0] ldg_func_map[4];
70 local integer deasset_mbox[4];
71 integer masks_before_isrs=0;
72
73 task new();
74 task initLdg(bit [63:0] active_list);
75 task SetTmrRes(bit[63:0] wdata);
76 local task spGetIntMsg();
77 local task parseIntx(bit[3:0] assert_msg, bit[3:0] deassert_msg,CniuGenIntrMsg IntrMsg) ;
78 local task procIntDevId(CniuGenIntrMsg IntrMsg) ;
79 local task procIntMsi(CniuGenIntrMsg IntrMsg) ;
80 local task procIntx(integer func,CniuGenIntrMsg IntrMsg) ;
81 local task spawnprocIntx(integer func,CniuGenIntrMsg IntrMsg) ;
82 function integer getFuncionNo(bit[3:0] msg);
83 task bindLdgFunc(bit [63:0] list,integer func);
84 task updateSidTab(integer gid, bit[6:0] sid);
85 task invalidateSidTab(integer gid );
86 function integer get_DevIsr_Cnt(integer group_bind_no, integer dev_id) ;
87 task CheckPendingFlags();
88 function integer CheckDevPendingFlag(integer device_no) ;
89}
90
91// Set up Tasks
92task CNiuIntrMgr::SetTmrRes(bit[63:0] wdata) {
93 bit[63:0] address;
94 address = LDGITMRES;
95 gen_pio_drv.pio_wr(address,wdata);
96}
97
98
99task CNiuIntrMgr::new() {
100 integer i;
101 active_ldg = 0;
102 SidTab = new();
103 for(i=0;i<4;i++) {
104 // trigger(ON,intx_sync[i]);
105 intx_sync[i] = alloc(SEMAPHORE,0,1,0);
106 semaphore_put(intx_sync[i],1);
107
108 ldg_func_map[i] = 0;
109 deasset_mbox[i] = alloc(MAILBOX,0,1);
110 }
111 fork {
112 spGetIntMsg();
113 } join none
114
115 if(get_plus_arg(CHECK,"MASK_BEFORE_ISR")) {
116 masks_before_isrs = 1;
117 }
118 if(get_plus_arg(CHECK,"INTX_BUG_FIX")) {
119 INTX_BUG_FIX = 1;
120 }
121}
122
123
124// SID Setup Tasks
125// LDG Setup Tasks
126task CNiuIntrMgr::initLdg(bit [63:0] active_list) {
127integer i;
128#ifdef NEPTUNE
129 pcie_intr_util.setup_neptune_interrupts();
130#else
131#endif
132 for(i=0;i<64;i++) {
133 if(active_list[i]) {
134 ldg[i] = new(i);
135 active_ldg[i] = 1;
136 }
137 }
138 // bindLdgFunc(active_list,0); // TMP
139}
140task CNiuIntrMgr::invalidateSidTab(integer gid ){
141 SidTab.RemoveSidTab(gid);
142}
143
144task CNiuIntrMgr::updateSidTab(integer gid, bit[6:0] sid){
145 integer func;
146 func = sid[6:5];
147 ldg_func_map[func] =ldg_func_map[func] | ( 1<<gid);
148 if(ldg[gid]==null){
149 printf("ERROR ldg- %d Not active!! Cannot update SID for this group\n",gid);
150 } else {
151 ldg[gid].setSid(sid);
152 }
153 SidTab.pio_writeSidTab(gid,sid);
154
155}
156task CNiuIntrMgr::bindLdgFunc(bit [63:0] list,integer func){
157 ldg_func_map[func] = list;
158 printf("CNiuIntrMgr::bindLdgFunc: list - %x function - %d \n",ldg_func_map[func],func);
159}
160
161// Queue Management tasks
162// - SID Look up tasks
163// - Get LDG Number
164// - Call LDG's ISR
165
166task CNiuIntrMgr::spGetIntMsg() {
167
168CniuGenIntrMsg IntrMsg;
169shadow integer status,gid;
170shadow bit [6:0] sid;
171integer message;
172bit[3:0] assert_msg,deassert_msg;
173shadow integer i;
174integer nep_msi_intr;
175/* free running task */
176
177
178 while(1) {
179 /*Wait for a message in the intrQueue*/
180
181 while(NiuIntrQ.isQEmpty() ) {
182 repeat(10) @(posedge CLOCK);
183 }
184 IntrMsg = NiuIntrQ.getIntrMsg(status);
185 if(status ==0) {
186 printf("spGetIntMsg TB ERROR \n");
187 return;
188 }
189
190 // Parse the message and get the SID information from this
191 assert_msg = 0;
192 deassert_msg = 0;
193 nep_msi_intr =0;
194#ifdef NEPTUNE
195 // First get the type of message
196 message = IntrMsg.int_message;
197 printf(" Message - %x \n",message);
198 if(message == -1) {
199 // not an intx message
200 } else {
201 assert_msg = 0;
202 deassert_msg = 0;
203 nep_msi_intr = 0;
204
205 if(message== PCIE_MSG_CODE_INTX_ASSERT_A) {
206 assert_msg[0] = 1;
207 } else if(message == PCIE_MSG_CODE_INTX_DEASSERT_A) {
208 deassert_msg[0] = 1;
209 } else if(message== PCIE_MSG_CODE_INTX_ASSERT_B) {
210 assert_msg[1] = 1;
211 } else if(message == PCIE_MSG_CODE_INTX_DEASSERT_B) {
212 deassert_msg[1] = 1;
213 } else if(message== PCIE_MSG_CODE_INTX_ASSERT_C) {
214 assert_msg[2] = 1;
215 } else if(message == PCIE_MSG_CODE_INTX_DEASSERT_C) {
216 deassert_msg[2] = 1;
217 } else if(message== PCIE_MSG_CODE_INTX_ASSERT_D) {
218 assert_msg[3] = 1;
219 } else if(message == PCIE_MSG_CODE_INTX_DEASSERT_D) {
220 deassert_msg[3] = 1;
221 } else if(message== PCIE_MSI) {
222 printf("CNiuIntrMgr::spGetIntMsg Received PCIE_MSI Message Vector - %x NoOfIntrs - %d \n",IntrMsg.int_message,IntrMsg.no_of_intr_alloc);
223 nep_msi_intr = 1;
224 } else if(message== PCIE_MSIX) {
225 printf("CNiuIntrMgr::spGetIntMsg Received PCIE_MSIX Message Vector - %x NoOfIntrs - %d \n",IntrMsg.int_message,IntrMsg.no_of_intr_alloc);
226 }
227
228 }
229#else
230#endif
231
232 if(assert_msg|deassert_msg) {
233 // any Intx Message seen
234 parseIntx(assert_msg,deassert_msg,IntrMsg);
235 } else if(nep_msi_intr) {
236 procIntMsi(IntrMsg);
237 } else {
238 procIntDevId(IntrMsg);
239 }
240 } // end while
241}
242function integer CNiuIntrMgr::getFuncionNo(bit[3:0] msg) {
243// According to Babu - IntA is for function0 , IntB for funtion 1 and so on
244
245 if(msg[0])
246 getFuncionNo = 0;
247 else if(msg[1])
248 getFuncionNo = 1;
249 else if(msg[2])
250 getFuncionNo = 2;
251 else if(msg[3])
252 getFuncionNo = 3;
253 else getFuncionNo = -1;
254}
255
256
257task CNiuIntrMgr:: parseIntx(bit[3:0] assert_msg, bit[3:0] deassert_msg,CniuGenIntrMsg IntrMsg) {
258
259 integer func;
260 // get function number based upon the msg
261 func = getFuncionNo(assert_msg | deassert_msg);
262 if(deassert_msg!=0) {
263 mailbox_put(deasset_mbox[func],DEASSERT_SEEN);
264 } else {
265 fork{
266 spawnprocIntx(func,IntrMsg);
267 } join none
268 }
269}
270
271task CNiuIntrMgr:: spawnprocIntx(integer func,CniuGenIntrMsg IntrMsg) {
272
273 integer status, message,end_Intx;
274 end_Intx = 0;
275 while(end_Intx == 0) {
276 procIntx(func,IntrMsg);
277 printf("Done with assert - all Waiting for deassert Function - %d Time - %d\n",func, {get_time(HI), get_time(LO)});
278 repeat(50)@(posedge CLOCK);
279 // Wait for some time to see if deasset was seen, if not continue
280 status = mailbox_get(NO_WAIT, deasset_mbox[func], message);
281 if((status!=0) && (message == DEASSERT_SEEN)) {
282 printf("Done with deassert - Killing spawnprocIntx Function - %d Time - %d\n",func,{get_time(HI), get_time(LO)});
283 end_Intx = 1;
284 }
285 }
286}
287task CNiuIntrMgr:: procIntx(integer func,CniuGenIntrMsg IntrMsg) {
288
289 integer blanket_interrupt;
290 integer fixed_group_no;
291 shadow integer i;
292 // sync(ALL, intx_sync[func]);
293 // trigger(OFF,intx_sync[func]);
294 semaphore_get(WAIT,intx_sync[func],1);
295
296
297 //
298 /* Do we need to disable any more generation of interrupts here*/
299 //
300 blanket_interrupt = 1;
301 printf("CNiuIntrMgr:: procIntx Start Function - %d Time - %d\n",func,{get_time(HI), get_time(LO)});
302
303 if(INTX_BUG_FIX) {
304 fixed_group_no = 16*func;
305 if(masks_before_isrs) {
306 if(active_ldg[fixed_group_no] && ldg_func_map[func][fixed_group_no] && (ldg[fixed_group_no].active_devices!=0) ) {
307 ldg[fixed_group_no].mask_all_devices();
308 }
309 }
310 if(active_ldg[fixed_group_no] && ldg_func_map[func][fixed_group_no] && (ldg[fixed_group_no].active_devices!=0) ) {
311 printf("Start ldgIsr Group - %d \n",fixed_group_no);
312 ldg[fixed_group_no].ldgIsr(blanket_interrupt,IntrMsg);
313 }
314 if(masks_before_isrs) {
315 if(active_ldg[fixed_group_no] && ldg_func_map[func][fixed_group_no] && (ldg[fixed_group_no].active_devices!=0) ) {
316 ldg[fixed_group_no].unmask_all_devices();
317 }
318 }
319 } else {
320 if(masks_before_isrs) {
321 for(i=0;i<64;i++) {
322 if(active_ldg[i] && ldg_func_map[func][i] && (ldg[i].active_devices!=0) ) {
323 ldg[i].mask_all_devices();
324 }
325 }
326 }
327 fork {
328 for(i=0;i<64;i++) {
329 //printf("Start ldgIsr Group xxxxx %d, %d, %d, %d\n", i, active_ldg[i], ldg_func_map[func][i], ldg[i].active_devices);
330 if(active_ldg[i] && ldg_func_map[func][i] && (ldg[i].active_devices!=0) ) {
331 printf("Start ldgIsr Group - %d \n",i);
332 ldg[i].ldgIsr(blanket_interrupt,IntrMsg);
333 }
334 }
335 } join all
336 if(masks_before_isrs) {
337 for(i=0;i<64;i++) {
338 if(active_ldg[i] && ldg_func_map[func][i] && (ldg[i].active_devices!=0) ) {
339 ldg[i].unmask_all_devices();
340 }
341 }
342 }
343 }
344 printf("Done with assert - all Waiting for deassert Time - %d\n",{get_time(HI), get_time(LO)});
345 // trigger(ON,intx_sync[func]);
346 semaphore_put(intx_sync[func],1);
347
348
349}
350task CNiuIntrMgr::procIntMsi(CniuGenIntrMsg IntrMsg) {
351
352bit[6:0] device_id;
353bit[1:0] function_no;
354bit[4:0] sid;
355integer no_of_in_masked;
356bit[6:0] valid_sids[*];
357integer valid_gids[*];
358integer mask,no_of_gids,status;
359integer no_of_bits_valid;
360integer no_of_bits_masked;
361shadow integer gid,i,n;
362integer blanket_interrupt;
363integer no_of_intr_alloc;
364integer no_of_possible_intr;
365
366// In this case, the message contains the no_of_possible interrupts along with the device_id
367// first get the device_id and no_of_interrupts_allocated from this
368
369/* notes:
370 no_of_intr_alloc = 32 - means all bits are valid
371 no_of_intr_alloc = 16 - only 4 lsb are valid, 1 msb is masked out and hence there are 2 possible intr
372 no_of_intr_alloc = 8 - only 3 lsb are valid, 2 msb is masked out and hence there are 4 possible intr
373 no_of_intr_alloc = 4 - only 2 lsb are valid, 3 msb is masked out and hence there are 8 possible intr
374 no_of_intr_alloc = 2 - only 1 lsb are valid, 4 msb is masked out and hence there are 16 possible intr
375 no_of_intr_alloc = 1 - only 0 lsb are valid, 5 msb is masked out and hence there are 32 possible intr
376 no_of_intr_alloc = 0 - illegal case
377
378
379*/
380 device_id = IntrMsg.device_id;
381 no_of_intr_alloc = IntrMsg.no_of_intr_alloc;
382 function_no = device_id[6:5];
383 sid = device_id[4:0];
384 valid_sids = new[32];
385 valid_gids = new[32];
386
387printf("CNiuIntrMgr::procIntMsi IntrMsg.no_of_intr_alloc - %d IntrMsg.device_id - %x \n",IntrMsg.no_of_intr_alloc,IntrMsg.device_id);
388
389// from the no_of_intr_alloc, there are lot more possible SIDs. The top bits from this SID would have been masked
390// off and therefore they need to be tested for valid SID
391 no_of_bits_valid = -1;
392 while(no_of_intr_alloc) {
393 no_of_bits_valid++;
394 no_of_intr_alloc = no_of_intr_alloc>>1;
395 }
396
397 if(( no_of_bits_valid > 5) ) {
398 printf("ERROR CNiuIntrMgr::procIntMsi Incorrect value for IntrMsg.no_of_intr_alloc!! FIX THIS!! - %d\n",IntrMsg.no_of_intr_alloc);
399 }
400 no_of_intr_alloc = IntrMsg.no_of_intr_alloc;
401 if(no_of_intr_alloc==0) {
402 no_of_bits_valid = 0;
403 }
404
405 mask = 0;
406 no_of_bits_masked = 5 - no_of_bits_valid ;
407 no_of_possible_intr = 1<<no_of_bits_masked ;
408
409 for(n=0;n<no_of_bits_valid;n++)
410 mask = mask | (1<<n);
411
412
413 no_of_gids = 0;
414 for(n=0;n<no_of_possible_intr;n++) {
415 valid_sids[n] = ((sid & mask) | ( n << no_of_bits_valid)) | (function_no<<5) ;
416 status = SidTab.getGid(gid,valid_sids[n]);
417 if(status!=0) {
418 valid_gids[no_of_gids++] = gid;
419 }
420 printf("CNiuIntrMgr::procIntMsi n - %d valid_sid - %x valid_gid - %d \n",n,valid_sids[n] ,gid);
421 }
422
423// now that we have all the possible SIDs from where this interrupt would have originated, check for various gids
424// some of these may be invalids too so look for those and spawn off the various ISRs
425
426 if(masks_before_isrs) {
427 for(i=0;i<no_of_gids;i++) {
428 gid = valid_gids[i];
429 if(active_ldg[gid] && (ldg[gid].active_devices!=0) ) {
430 ldg[gid].mask_all_devices();
431 }
432 }
433 }
434 blanket_interrupt = 1;
435 fork {
436 for(i=0;i<no_of_gids;i++) {
437 gid = valid_gids[i];
438 if(active_ldg[gid] && /*ldg_func_map[func][igid] &&*/ (ldg[gid].active_devices!=0) ) {
439 ldg[gid].ldgIsr(blanket_interrupt,IntrMsg);
440 }
441 }
442 } join all
443
444 if(masks_before_isrs) {
445 for(i=0;i<no_of_gids;i++) {
446 gid = valid_gids[i];
447 if(active_ldg[gid] && (ldg[gid].active_devices!=0) ) {
448 ldg[gid].unmask_all_devices();
449 }
450 }
451 }
452
453
454}
455
456task CNiuIntrMgr::procIntDevId(CniuGenIntrMsg IntrMsg) {
457
458integer status,gid;
459bit [6:0] sid;
460
461
462 sid = IntrMsg.device_id[6:0];
463 printf("CNiuIntrMgr::spGetIntMsg: IntrMsg.device_id %x Time - %d \n",IntrMsg.device_id[6:0],{get_time(HI), get_time(LO)});
464 status = SidTab.getGid(gid,sid);
465 printf("CNiuIntrMgr::spGetIntMsg: IntrMsg.sid - %x gid - %x status - %d active - %d Time - %d \n",sid,gid,status,active_ldg[gid],{get_time(HI), get_time(LO)});
466 if(status ==0) {
467 printf("CNiuIntrMgr::spGetIntMsg: Illegal SID from Hardware ERROR \n");
468 return;
469 }
470 // check if this gid is an active one
471 // if not flag errors
472 if(active_ldg[gid]!==1) {
473 printf("CNiuIntrMgr::procIntDevId: LDG Num - %d Not bound TB ERROR \n",gid);
474 return;
475 }
476 // spawn task with ldg to check all the interrupting devices so that
477 // they can run their ISRs
478
479 fork {
480
481 if(masks_before_isrs)
482 ldg[gid].mask_all_devices();
483
484 ldg[gid].ldgIsr(0,IntrMsg);
485
486 if(masks_before_isrs)
487 ldg[gid].unmask_all_devices();
488
489 } join none
490}
491
492function integer CNiuIntrMgr :: get_DevIsr_Cnt(integer group_bind_no, integer dev_id) {
493
494 integer isr_count = 0;
495
496 if(active_ldg[group_bind_no]) {
497 isr_count = ldg[group_bind_no].getDevIsrCnt(dev_id);
498 } else {
499 isr_count = -1;
500 printf("CNiuIntrMgr :: get_DevIsr_Cnt TEST ERROR - Group - %d Not Active!!\n",group_bind_no);
501 }
502
503 get_DevIsr_Cnt = isr_count;
504}
505
506task CNiuIntrMgr :: CheckPendingFlags(){
507shadow integer i;
508bit[63:0] done;
509shadow integer pending_flags;
510bit[63:0] restart_pending_flags;
511bit[63:0] active_grps;
512
513
514for(i=0;i<64;i++)
515 active_grps[i] = (active_ldg[i] & (ldg[i].active_devices!=0)) ;
516
517restart_pending_flags = 0;
518while(restart_pending_flags!= active_grps) {
519 done = 64'h0;
520 for(i=0;i<64;i++) {
521 if(active_ldg[i] & (ldg[i].active_devices!=0)) {
522 fork {
523 printf("CNiuIntrMgr :: CheckPendingFlags Checking LDG# - %d for pending interrupts \n",i);
524 pending_flags = ldg[i].isPending();
525 if(pending_flags==-1) {
526 printf("CNiuIntrMgr :: CheckPendingFlags Group - %d Returned ERROR!!! \n",i);
527 }
528 done[i] = 1;
529 } join none
530 }else done[i] = 1;
531 }
532 wait_child();
533 printf(" CNiuIntrMgr :: CheckPendingFlags! Exiting, All Interrupts done!! first Iteration \n");
534 // check to see if anything is stillpending
535for(i=0;i<64;i++) {
536 if(active_grps[i]) {
537 restart_pending_flags[i] = (ldg[i].pending_flag==0);
538 }
539}
540printf("CNiuIntrMgr :: CheckPendingFlags restart_pending_flags - %x \n",restart_pending_flags);
541
542}// while
543
544}
545
546function integer CNiuIntrMgr:: CheckDevPendingFlag(integer device_no) {
547 // first get the group to which this is bound
548 integer i;
549 integer pending_flags;
550 i=0;
551 while(i<64) {
552 if(active_ldg[i] & (ldg[i].active_devices[device_no])) {
553 break;
554 } else i++;
555 }
556 if(i==64) {
557 printf("CNiuIntrMgr:: CheckDevPendingFlag device_no - %d Not bound to any group!! ERROR \n",device_no);
558 return;
559 }
560 pending_flags = ldg[i].isPending();
561 if(pending_flags==-1) {
562 printf("CNiuIntrMgr :: CheckDevPendingFlag Group - %d Returned ERROR!!! \n",i);
563 }
564 CheckDevPendingFlag = pending_flags;
565}