]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_interrupt_vg.c
gpu: vivante: Update driver from Freescale 3.10.53-1.1-ga BSP
[karo-tx-linux.git] / drivers / mxc / gpu-viv / hal / kernel / gc_hal_kernel_interrupt_vg.c
1 /****************************************************************************
2 *
3 *    Copyright (C) 2005 - 2014 by Vivante Corp.
4 *
5 *    This program is free software; you can redistribute it and/or modify
6 *    it under the terms of the GNU General Public License as published by
7 *    the Free Software Foundation; either version 2 of the license, or
8 *    (at your option) any later version.
9 *
10 *    This program is distributed in the hope that it will be useful,
11 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 *    GNU General Public License for more details.
14 *
15 *    You should have received a copy of the GNU General Public License
16 *    along with this program; if not write to the Free Software
17 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 *****************************************************************************/
20
21
22 #include "gc_hal_kernel_precomp.h"
23
24 #if gcdENABLE_VG
25
26 /******************************************************************************\
27 *********************** Support Functions and Definitions **********************
28 \******************************************************************************/
29
30 /* Interruot statistics will be accumulated if not zero. */
31 #define gcmENABLE_INTERRUPT_STATISTICS 0
32
33 #define _GC_OBJ_ZONE    gcvZONE_INTERRUPT
34
35 /* Object structure. */
36 struct _gckVGINTERRUPT
37 {
38     /* Object. */
39     gcsOBJECT                   object;
40
41     /* gckVGKERNEL pointer. */
42     gckVGKERNEL                 kernel;
43
44     /* gckOS pointer. */
45     gckOS                       os;
46
47     /* Interrupt handlers. */
48     gctINTERRUPT_HANDLER        handlers[32];
49
50     /* Main interrupt handler thread. */
51     gctTHREAD                   handler;
52     gctBOOL                     terminate;
53
54     /* Interrupt FIFO. */
55     gctSEMAPHORE                fifoValid;
56     gctUINT32                   fifo[256];
57     gctUINT                     fifoItems;
58     gctUINT8                    head;
59     gctUINT8                    tail;
60
61     /* Interrupt statistics. */
62 #if gcmENABLE_INTERRUPT_STATISTICS
63     gctUINT                     maxFifoItems;
64     gctUINT                     fifoOverflow;
65     gctUINT                     maxSimultaneous;
66     gctUINT                     multipleCount;
67 #endif
68 };
69
70
71 /*******************************************************************************
72 **
73 **  _ProcessInterrupt
74 **
75 **  The interrupt processor.
76 **
77 **  INPUT:
78 **
79 **      ThreadParameter
80 **          Pointer to the gckVGINTERRUPT object.
81 **
82 **  OUTPUT:
83 **
84 **      Nothing.
85 */
86
87 #if gcmENABLE_INTERRUPT_STATISTICS
88 static void
89 _ProcessInterrupt(
90     gckVGINTERRUPT Interrupt,
91     gctUINT_PTR TriggeredCount
92     )
93 #else
94 static void
95 _ProcessInterrupt(
96     gckVGINTERRUPT Interrupt
97     )
98 #endif
99 {
100     gceSTATUS status;
101     gctUINT32 triggered;
102     gctUINT i;
103
104     /* Advance to the next entry. */
105     Interrupt->tail      += 1;
106     Interrupt->fifoItems -= 1;
107
108     /* Get the interrupt value. */
109     triggered = Interrupt->fifo[Interrupt->tail];
110     gcmkASSERT(triggered != 0);
111
112     gcmkTRACE_ZONE(
113         gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
114         "%s: triggered=0x%08X\n",
115         __FUNCTION__,
116         triggered
117         );
118
119     /* Walk through all possible interrupts. */
120     for (i = 0; i < gcmSIZEOF(Interrupt->handlers); i += 1)
121     {
122         /* Test if interrupt happened. */
123         if ((triggered & 1) == 1)
124         {
125 #if gcmENABLE_INTERRUPT_STATISTICS
126             if (TriggeredCount != gcvNULL)
127             {
128                 (* TriggeredCount) += 1;
129             }
130 #endif
131
132             /* Make sure we have valid handler. */
133             if (Interrupt->handlers[i] == gcvNULL)
134             {
135                 gcmkTRACE(
136                     gcvLEVEL_ERROR,
137                     "%s: Interrupt %d isn't registered.\n",
138                     __FUNCTION__, i
139                     );
140             }
141             else
142             {
143                 gcmkTRACE_ZONE(
144                     gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
145                     "%s: interrupt=%d\n",
146                     __FUNCTION__,
147                     i
148                     );
149
150                 /* Call the handler. */
151                 status = Interrupt->handlers[i] (Interrupt->kernel);
152
153                 if (gcmkIS_ERROR(status))
154                 {
155                     /* Failed to signal the semaphore. */
156                     gcmkTRACE(
157                         gcvLEVEL_ERROR,
158                         "%s: Error %d incrementing the semaphore #%d.\n",
159                         __FUNCTION__, status, i
160                         );
161                 }
162             }
163         }
164
165         /* Next interrupt. */
166         triggered >>= 1;
167
168         /* No more interrupts to handle? */
169         if (triggered == 0)
170         {
171             break;
172         }
173     }
174 }
175
176
177 /*******************************************************************************
178 **
179 **  _MainInterruptHandler
180 **
181 **  The main interrupt thread serves the interrupt FIFO and calls registered
182 **  handlers for the interrupts that occured. The handlers are called in the
183 **  sequence interrupts occured with the exception when multiple interrupts
184 **  occured at the same time. In that case the handler calls are "sorted" by
185 **  the interrupt number therefore giving the interrupts with lower numbers
186 **  higher priority.
187 **
188 **  INPUT:
189 **
190 **      ThreadParameter
191 **          Pointer to the gckVGINTERRUPT object.
192 **
193 **  OUTPUT:
194 **
195 **      Nothing.
196 */
197
198 static gctTHREADFUNCRESULT gctTHREADFUNCTYPE
199 _MainInterruptHandler(
200     gctTHREADFUNCPARAMETER ThreadParameter
201     )
202 {
203     gceSTATUS status;
204     gckVGINTERRUPT interrupt;
205
206 #if gcmENABLE_INTERRUPT_STATISTICS
207     gctUINT count;
208 #endif
209
210     /* Cast the object. */
211     interrupt = (gckVGINTERRUPT) ThreadParameter;
212
213     /* Enter the loop. */
214     while (gcvTRUE)
215     {
216         /* Wait for an interrupt. */
217         status = gckOS_DecrementSemaphore(interrupt->os, interrupt->fifoValid);
218
219         /* Error? */
220         if (gcmkIS_ERROR(status))
221         {
222             break;
223         }
224
225         /* System termination request? */
226         if (status == gcvSTATUS_TERMINATE)
227         {
228             break;
229         }
230
231         /* Driver is shutting down? */
232         if (interrupt->terminate)
233         {
234             break;
235         }
236
237 #if gcmENABLE_INTERRUPT_STATISTICS
238         /* Reset triggered count. */
239         count = 0;
240
241         /* Process the interrupt. */
242         _ProcessInterrupt(interrupt, &count);
243
244         /* Update conters. */
245         if (count > interrupt->maxSimultaneous)
246         {
247             interrupt->maxSimultaneous = count;
248         }
249
250         if (count > 1)
251         {
252             interrupt->multipleCount += 1;
253         }
254 #else
255         /* Process the interrupt. */
256         _ProcessInterrupt(interrupt);
257 #endif
258     }
259
260     return 0;
261 }
262
263
264 /*******************************************************************************
265 **
266 **  _StartInterruptHandler / _StopInterruptHandler
267 **
268 **  Main interrupt handler routine control.
269 **
270 **  INPUT:
271 **
272 **      ThreadParameter
273 **          Pointer to the gckVGINTERRUPT object.
274 **
275 **  OUTPUT:
276 **
277 **      Nothing.
278 */
279
280 static gceSTATUS
281 _StartInterruptHandler(
282     gckVGINTERRUPT Interrupt
283     )
284 {
285     gceSTATUS status, last;
286
287     do
288     {
289         /* Objects must not be already created. */
290         gcmkASSERT(Interrupt->fifoValid == gcvNULL);
291         gcmkASSERT(Interrupt->handler   == gcvNULL);
292
293         /* Reset the termination request. */
294         Interrupt->terminate = gcvFALSE;
295
296 #if !gcdENABLE_INFINITE_SPEED_HW
297         /* Construct the fifo semaphore. */
298         gcmkERR_BREAK(gckOS_CreateSemaphoreVG(
299             Interrupt->os, &Interrupt->fifoValid
300             ));
301
302         /* Start the interrupt handler thread. */
303         gcmkERR_BREAK(gckOS_StartThread(
304             Interrupt->os,
305             _MainInterruptHandler,
306             Interrupt,
307             &Interrupt->handler
308             ));
309 #endif
310
311         /* Success. */
312         return gcvSTATUS_OK;
313     }
314     while (gcvFALSE);
315
316     /* Roll back. */
317     if (Interrupt->fifoValid != gcvNULL)
318     {
319         gcmkCHECK_STATUS(gckOS_DestroySemaphore(
320             Interrupt->os, Interrupt->fifoValid
321             ));
322
323         Interrupt->fifoValid = gcvNULL;
324     }
325
326     /* Return the status. */
327     return status;
328 }
329
330 static gceSTATUS
331 _StopInterruptHandler(
332     gckVGINTERRUPT Interrupt
333     )
334 {
335     gceSTATUS status;
336
337     do
338     {
339         /* Does the thread exist? */
340         if (Interrupt->handler == gcvNULL)
341         {
342             /* The semaphore must be NULL as well. */
343             gcmkASSERT(Interrupt->fifoValid == gcvNULL);
344
345             /* Success. */
346             status = gcvSTATUS_OK;
347             break;
348         }
349
350         /* The semaphore must exist as well. */
351         gcmkASSERT(Interrupt->fifoValid != gcvNULL);
352
353         /* Set the termination request. */
354         Interrupt->terminate = gcvTRUE;
355
356         /* Unlock the thread. */
357         gcmkERR_BREAK(gckOS_IncrementSemaphore(
358             Interrupt->os, Interrupt->fifoValid
359             ));
360
361         /* Wait until the thread quits. */
362         gcmkERR_BREAK(gckOS_StopThread(
363             Interrupt->os,
364             Interrupt->handler
365             ));
366
367         /* Destroy the semaphore. */
368         gcmkERR_BREAK(gckOS_DestroySemaphore(
369             Interrupt->os, Interrupt->fifoValid
370             ));
371
372         /* Reset handles. */
373         Interrupt->handler   = gcvNULL;
374         Interrupt->fifoValid = gcvNULL;
375     }
376     while (gcvFALSE);
377
378     /* Return the status. */
379     return status;
380 }
381
382
383 /******************************************************************************\
384 ***************************** Interrupt Object API *****************************
385 \******************************************************************************/
386
387 /*******************************************************************************
388 **
389 **  gckVGINTERRUPT_Construct
390 **
391 **  Construct an interrupt object.
392 **
393 **  INPUT:
394 **
395 **      Kernel
396 **          Pointer to the gckVGKERNEL object.
397 **
398 **  OUTPUT:
399 **
400 **      Interrupt
401 **          Pointer to the new gckVGINTERRUPT object.
402 */
403
404 gceSTATUS
405 gckVGINTERRUPT_Construct(
406     IN gckVGKERNEL Kernel,
407     OUT gckVGINTERRUPT * Interrupt
408     )
409 {
410     gceSTATUS status;
411     gckVGINTERRUPT interrupt = gcvNULL;
412
413     gcmkHEADER_ARG("Kernel=0x%x Interrupt=0x%x", Kernel, Interrupt);
414
415     /* Verify argeuments. */
416     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
417     gcmkVERIFY_ARGUMENT(Interrupt != gcvNULL);
418
419     do
420     {
421         /* Allocate the gckVGINTERRUPT structure. */
422         gcmkERR_BREAK(gckOS_Allocate(
423             Kernel->os,
424             gcmSIZEOF(struct _gckVGINTERRUPT),
425             (gctPOINTER *) &interrupt
426             ));
427
428         /* Reset the object data. */
429         gcmkVERIFY_OK(gckOS_ZeroMemory(
430             interrupt, gcmSIZEOF(struct _gckVGINTERRUPT)
431             ));
432
433         /* Initialize the object. */
434         interrupt->object.type = gcvOBJ_INTERRUPT;
435
436         /* Initialize the object pointers. */
437         interrupt->kernel = Kernel;
438         interrupt->os     = Kernel->os;
439
440         /* Initialize the current FIFO position. */
441         interrupt->head = (gctUINT8)~0;
442         interrupt->tail = (gctUINT8)~0;
443
444         /* Start the thread. */
445         gcmkERR_BREAK(_StartInterruptHandler(interrupt));
446
447         /* Return interrupt object. */
448         *Interrupt = interrupt;
449
450         gcmkFOOTER_ARG("*Interrup=0x%x", *Interrupt);
451         /* Success. */
452         return gcvSTATUS_OK;
453     }
454     while (gcvFALSE);
455
456     /* Roll back. */
457     if (interrupt != gcvNULL)
458     {
459         /* Free the gckVGINTERRUPT structure. */
460         gcmkVERIFY_OK(gckOS_Free(interrupt->os, interrupt));
461     }
462
463     gcmkFOOTER();
464
465     /* Return the status. */
466     return status;
467 }
468
469
470 /*******************************************************************************
471 **
472 **  gckVGINTERRUPT_Destroy
473 **
474 **  Destroy an interrupt object.
475 **
476 **  INPUT:
477 **
478 **      Interrupt
479 **          Pointer to the gckVGINTERRUPT object to destroy.
480 **
481 **  OUTPUT:
482 **
483 **      Nothing.
484 */
485
486 gceSTATUS
487 gckVGINTERRUPT_Destroy(
488     IN gckVGINTERRUPT Interrupt
489     )
490 {
491     gceSTATUS status;
492
493     gcmkHEADER_ARG("Interrupt=0x%x", Interrupt);
494
495     /* Verify the arguments. */
496     gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
497
498     do
499     {
500         /* Stop the interrupt thread. */
501         gcmkERR_BREAK(_StopInterruptHandler(Interrupt));
502
503         /* Mark the object as unknown. */
504         Interrupt->object.type = gcvOBJ_UNKNOWN;
505
506         /* Free the gckVGINTERRUPT structure. */
507         gcmkERR_BREAK(gckOS_Free(Interrupt->os, Interrupt));
508     }
509     while (gcvFALSE);
510
511     gcmkFOOTER();
512
513     /* Return the status. */
514     return status;
515 }
516
517
518 /*******************************************************************************
519 **
520 **  gckVGINTERRUPT_DumpState
521 **
522 **  Print the current state of the interrupt manager.
523 **
524 **  INPUT:
525 **
526 **      Interrupt
527 **          Pointer to a gckVGINTERRUPT object.
528 **
529 **  OUTPUT:
530 **
531 **      Nothing.
532 */
533
534 #if gcvDEBUG
535 gceSTATUS
536 gckVGINTERRUPT_DumpState(
537     IN gckVGINTERRUPT Interrupt
538     )
539 {
540     gcmkHEADER_ARG("Interrupt=0x%x", Interrupt);
541     /* Verify the arguments. */
542     gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
543
544     /* Print the header. */
545     gcmkTRACE_ZONE(
546         gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
547         "%s: INTERRUPT OBJECT STATUS\n",
548         __FUNCTION__
549         );
550
551     /* Print statistics. */
552 #if gcmENABLE_INTERRUPT_STATISTICS
553     gcmkTRACE_ZONE(
554         gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
555         "  Maximum number of FIFO items accumulated at a single time: %d\n",
556         Interrupt->maxFifoItems
557         );
558
559     gcmkTRACE_ZONE(
560         gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
561         "  Interrupt FIFO overflow happened times: %d\n",
562         Interrupt->fifoOverflow
563         );
564
565     gcmkTRACE_ZONE(
566         gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
567         "  Maximum number of interrupts simultaneously generated: %d\n",
568         Interrupt->maxSimultaneous
569         );
570
571     gcmkTRACE_ZONE(
572         gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
573         "  Number of times when there were multiple interrupts generated: %d\n",
574         Interrupt->multipleCount
575         );
576 #endif
577
578     gcmkTRACE_ZONE(
579         gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
580         "  The current number of entries in the FIFO: %d\n",
581         Interrupt->fifoItems
582         );
583
584     /* Print the FIFO contents. */
585     if (Interrupt->fifoItems != 0)
586     {
587         gctUINT8 index;
588         gctUINT8 last;
589
590         gcmkTRACE_ZONE(
591             gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
592             "  FIFO current contents:\n"
593             );
594
595         /* Get the current pointers. */
596         index = Interrupt->tail;
597         last  = Interrupt->head;
598
599         while (index != last)
600         {
601             /* Advance to the next entry. */
602             index += 1;
603
604             gcmkTRACE_ZONE(
605                 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
606                 "    %d: 0x%08X\n",
607                 index, Interrupt->fifo[index]
608                 );
609         }
610     }
611
612     gcmkFOOTER_NO();
613     /* Success. */
614     return gcvSTATUS_OK;
615 }
616 #endif
617
618
619 /*******************************************************************************
620 **
621 **  gckVGINTERRUPT_Enable
622 **
623 **  Enable the specified interrupt.
624 **
625 **  INPUT:
626 **
627 **      Interrupt
628 **          Pointer to a gckVGINTERRUPT object.
629 **
630 **      Id
631 **          Pointer to the variable that holds the interrupt number to be
632 **          registered in range 0..31.
633 **          If the value is less then 0, gckVGINTERRUPT_Enable will attempt
634 **          to find an unused interrupt. If such interrupt is found, the number
635 **          will be assigned to the variable if the functuion call succeedes.
636 **
637 **      Handler
638 **          Pointer to the handler to register for the interrupt.
639 **
640 **  OUTPUT:
641 **
642 **      Nothing.
643 */
644
645 gceSTATUS
646 gckVGINTERRUPT_Enable(
647     IN gckVGINTERRUPT Interrupt,
648     IN OUT gctINT32_PTR Id,
649     IN gctINTERRUPT_HANDLER Handler
650     )
651 {
652     gceSTATUS status;
653     gctINT32 i;
654
655     gcmkHEADER_ARG("Interrupt=0x%x Id=0x%x Handler=0x%x", Interrupt, Id, Handler);
656
657     /* Verify the arguments. */
658     gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
659     gcmkVERIFY_ARGUMENT(Id != gcvNULL);
660     gcmkVERIFY_ARGUMENT(Handler != gcvNULL);
661
662     do
663     {
664         /* See if we need to allocate an ID. */
665         if (*Id < 0)
666         {
667             /* Find the first unused interrupt handler. */
668             for (i = 0; i < gcmCOUNTOF(Interrupt->handlers); ++i)
669             {
670                 if (Interrupt->handlers[i] == gcvNULL)
671                 {
672                     break;
673                 }
674             }
675
676             /* No unused innterrupts? */
677             if (i == gcmCOUNTOF(Interrupt->handlers))
678             {
679                 status = gcvSTATUS_OUT_OF_RESOURCES;
680                 break;
681             }
682
683             /* Update the interrupt ID. */
684             *Id = i;
685         }
686
687         /* Make sure the ID is in range. */
688         else if (*Id >= gcmCOUNTOF(Interrupt->handlers))
689         {
690             status = gcvSTATUS_INVALID_ARGUMENT;
691             break;
692         }
693
694         /* Set interrupt handler. */
695         Interrupt->handlers[*Id] = Handler;
696
697         /* Success. */
698         status = gcvSTATUS_OK;
699     }
700     while (gcvFALSE);
701
702     gcmkFOOTER();
703     /* Return the status. */
704     return status;
705 }
706
707
708 /*******************************************************************************
709 **
710 **  gckVGINTERRUPT_Disable
711 **
712 **  Disable the specified interrupt.
713 **
714 **  INPUT:
715 **
716 **      Interrupt
717 **          Pointer to a gckVGINTERRUPT object.
718 **
719 **      Id
720 **          Interrupt number to be disabled in range 0..31.
721 **
722 **  OUTPUT:
723 **
724 **      Nothing.
725 */
726
727 gceSTATUS
728 gckVGINTERRUPT_Disable(
729     IN gckVGINTERRUPT Interrupt,
730     IN gctINT32 Id
731     )
732 {
733     gcmkHEADER_ARG("Interrupt=0x%x Id=0x%x", Interrupt, Id);
734     /* Verify the arguments. */
735     gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
736     gcmkVERIFY_ARGUMENT((Id >= 0) && (Id < gcmCOUNTOF(Interrupt->handlers)));
737
738     /* Reset interrupt handler. */
739     Interrupt->handlers[Id] = gcvNULL;
740
741     gcmkFOOTER_NO();
742     /* Success. */
743     return gcvSTATUS_OK;
744 }
745
746
747 /*******************************************************************************
748 **
749 **  gckVGINTERRUPT_Enque
750 **
751 **  Read the interrupt status register and put the value in the interrupt FIFO.
752 **
753 **  INPUT:
754 **
755 **      Interrupt
756 **          Pointer to a gckVGINTERRUPT object.
757 **
758 **  OUTPUT:
759 **
760 **      Nothing.
761 */
762
763 #ifndef __QNXNTO__
764 gceSTATUS
765 gckVGINTERRUPT_Enque(
766     IN gckVGINTERRUPT Interrupt
767     )
768 #else
769 gceSTATUS
770 gckVGINTERRUPT_Enque(
771     IN gckVGINTERRUPT Interrupt,
772     OUT gckOS *Os,
773     OUT gctSEMAPHORE *Semaphore
774     )
775 #endif
776 {
777     gceSTATUS status;
778     gctUINT32 triggered;
779
780     gcmkHEADER_ARG("Interrupt=0x%x", Interrupt);
781
782     /* Verify the arguments. */
783     gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
784
785 #ifdef __QNXNTO__
786     *Os = gcvNULL;
787     *Semaphore = gcvNULL;
788 #endif
789
790     do
791     {
792         /* Read interrupt status register. */
793         gcmkERR_BREAK(gckVGHARDWARE_ReadInterrupt(
794             Interrupt->kernel->hardware, &triggered
795             ));
796
797         /* Mask out TS overflow interrupt */
798         triggered &= 0xfffffffe;
799
800         /* No interrupts to process? */
801         if (triggered == 0)
802         {
803             status = gcvSTATUS_NOT_OUR_INTERRUPT;
804             break;
805         }
806
807         /* FIFO overflow? */
808         if (Interrupt->fifoItems == gcmCOUNTOF(Interrupt->fifo))
809         {
810 #if gcmENABLE_INTERRUPT_STATISTICS
811             Interrupt->fifoOverflow += 1;
812 #endif
813
814             /* OR the interrupt with the last value in the FIFO. */
815             Interrupt->fifo[Interrupt->head] |= triggered;
816
817             /* Success (kind of). */
818             status = gcvSTATUS_OK;
819         }
820         else
821         {
822             /* Advance to the next entry. */
823             Interrupt->head      += 1;
824             Interrupt->fifoItems += 1;
825
826 #if gcmENABLE_INTERRUPT_STATISTICS
827             if (Interrupt->fifoItems > Interrupt->maxFifoItems)
828             {
829                 Interrupt->maxFifoItems = Interrupt->fifoItems;
830             }
831 #endif
832
833             /* Set the new value. */
834             Interrupt->fifo[Interrupt->head] = triggered;
835
836 #ifndef __QNXNTO__
837             /* Increment the FIFO semaphore. */
838             gcmkERR_BREAK(gckOS_IncrementSemaphore(
839                 Interrupt->os, Interrupt->fifoValid
840                 ));
841 #else
842             *Os = Interrupt->os;
843             *Semaphore = Interrupt->fifoValid;
844 #endif
845
846             /* Windows kills our threads prematurely when the application
847                exists. Verify here that the thread is still alive. */
848             status = gckOS_VerifyThread(Interrupt->os, Interrupt->handler);
849
850             /* Has the thread been prematurely terminated? */
851             if (status != gcvSTATUS_OK)
852             {
853                 /* Process all accumulated interrupts. */
854                 while (Interrupt->head != Interrupt->tail)
855                 {
856 #if gcmENABLE_INTERRUPT_STATISTICS
857                     /* Process the interrupt. */
858                     _ProcessInterrupt(Interrupt, gcvNULL);
859 #else
860                     /* Process the interrupt. */
861                     _ProcessInterrupt(Interrupt);
862 #endif
863                 }
864
865                 /* Set success. */
866                 status = gcvSTATUS_OK;
867             }
868         }
869     }
870     while (gcvFALSE);
871
872     gcmkFOOTER();
873     /* Return status. */
874     return status;
875 }
876
877 #endif /* gcdENABLE_VG */