bump up min IOS version
[libogc.git] / libogc / arqueue.c
blob264e9d9558c0148ca0c4f1d8bb16c24d7c60121f
1 /*-------------------------------------------------------------
3 arqueue.c -- ARAM task request queue implementation
5 Copyright (C) 2004
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any
11 damages arising from the use of this software.
13 Permission is granted to anyone to use this software for any
14 purpose, including commercial applications, and to alter it and
15 redistribute it freely, subject to the following restrictions:
17 1. The origin of this software must not be misrepresented; you
18 must not claim that you wrote the original software. If you use
19 this software in a product, an acknowledgment in the product
20 documentation would be appreciated but is not required.
22 2. Altered source versions must be plainly marked as such, and
23 must not be misrepresented as being the original software.
25 3. This notice may not be removed or altered from any source
26 distribution.
28 -------------------------------------------------------------*/
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <lwp.h>
35 #include "asm.h"
36 #include "processor.h"
37 #include "arqueue.h"
39 //#define _ARQ_DEBUG
41 static u32 __ARQChunkSize;
42 static u32 __ARQInitFlag = 0;
43 static lwpq_t __ARQSyncQueue;
45 static lwp_queue __ARQReqQueueLo;
46 static lwp_queue __ARQReqQueueHi;
47 static ARQRequest *__ARQReqPendingLo;
48 static ARQRequest *__ARQReqPendingHi;
49 static ARQCallback __ARQCallbackLo = NULL;
50 static ARQCallback __ARQCallbackHi = NULL;
52 static __inline__ void __ARQPopTaskQueueHi()
54 ARQRequest *req;
56 req = (ARQRequest*)__lwp_queue_getI(&__ARQReqQueueHi);
57 if(!req) return;
59 req->state = ARQ_TASK_RUNNING;
60 #ifdef _ARQ_DEBUG
61 printf("__ARQPopTaskQueueHi(%02x,%08x,%08x,%d)\n",req->dir,req->aram_addr,req->mram_addr,req->len);
62 #endif
63 AR_StartDMA(req->dir,req->mram_addr,req->aram_addr,req->len);
64 __ARQCallbackHi = req->callback;
65 __ARQReqPendingHi = req;
68 static void __ARQCallbackDummy(ARQRequest *req)
72 static void __ARQCallbackSync(ARQRequest *req)
74 LWP_ThreadBroadcast(__ARQSyncQueue);
77 static void __ARQServiceQueueLo()
79 ARQRequest *req;
81 if(!__ARQReqPendingLo) {
82 req = (ARQRequest*)__lwp_queue_getI(&__ARQReqQueueLo);
83 __ARQReqPendingLo = req;
86 req = __ARQReqPendingLo;
87 if(req) {
88 req->state = ARQ_TASK_RUNNING;
89 #ifdef _ARQ_DEBUG
90 printf("__ARQServiceQueueLo(%02x,%08x,%08x,%d,%d)\n",req->dir,req->aram_addr,req->mram_addr,req->len,__ARQChunkSize);
91 #endif
92 if(req->len<=__ARQChunkSize) {
93 AR_StartDMA(req->dir,req->mram_addr,req->aram_addr,req->len);
94 __ARQCallbackLo = __ARQReqPendingLo->callback;
95 } else {
96 AR_StartDMA(req->dir,req->mram_addr,req->aram_addr,__ARQChunkSize);
97 __ARQReqPendingLo->len -= __ARQChunkSize;
98 __ARQReqPendingLo->aram_addr += __ARQChunkSize;
99 __ARQReqPendingLo->mram_addr += __ARQChunkSize;
104 static void __ARInterruptServiceRoutine()
106 if(__ARQCallbackHi) {
107 __ARQReqPendingHi->state = ARQ_TASK_FINISHED;
108 __ARQCallbackHi(__ARQReqPendingHi);
109 __ARQReqPendingHi = NULL;
110 __ARQCallbackHi = NULL;
111 } else if(__ARQCallbackLo) {
112 __ARQReqPendingLo->state = ARQ_TASK_FINISHED;
113 __ARQCallbackLo(__ARQReqPendingLo);
114 __ARQReqPendingLo = NULL;
115 __ARQCallbackLo = NULL;
117 __ARQPopTaskQueueHi();
118 if(!__ARQReqPendingHi) __ARQServiceQueueLo();
121 void ARQ_Init()
123 u32 level;
124 #ifdef _ARQ_DEBUG
125 printf("ARQ_Init(%02x)\n",__ARQInitFlag);
126 #endif
127 if(__ARQInitFlag) return;
129 _CPU_ISR_Disable(level);
131 __ARQReqPendingLo = NULL;
132 __ARQReqPendingHi = NULL;
133 __ARQCallbackLo = NULL;
134 __ARQCallbackHi = NULL;
136 __ARQChunkSize = ARQ_DEF_CHUNK_SIZE;
138 LWP_InitQueue(&__ARQSyncQueue);
140 __lwp_queue_init_empty(&__ARQReqQueueLo);
141 __lwp_queue_init_empty(&__ARQReqQueueHi);
143 AR_RegisterCallback(__ARInterruptServiceRoutine);
145 __ARQInitFlag = 1;
146 _CPU_ISR_Restore(level);
149 void ARQ_Reset()
151 u32 level;
152 _CPU_ISR_Disable(level);
153 __ARQInitFlag = 0;
154 _CPU_ISR_Restore(level);
157 void ARQ_SetChunkSize(u32 size)
159 u32 level;
160 _CPU_ISR_Disable(level);
161 __ARQChunkSize = (size+31)&~31;
162 _CPU_ISR_Restore(level);
165 u32 ARQ_GetChunkSize()
167 return __ARQChunkSize;
170 void ARQ_FlushQueue()
172 u32 level;
174 _CPU_ISR_Disable(level);
176 __lwp_queue_init_empty(&__ARQReqQueueLo);
177 __lwp_queue_init_empty(&__ARQReqQueueHi);
178 if(!__ARQCallbackLo) __ARQReqPendingLo = NULL;
180 _CPU_ISR_Restore(level);
183 void ARQ_PostRequestAsync(ARQRequest *req,u32 owner,u32 dir,u32 prio,u32 aram_addr,u32 mram_addr,u32 len,ARQCallback cb)
185 u32 level;
186 ARQRequest *p;
188 req->state = ARQ_TASK_READY;
189 req->dir = dir;
190 req->owner = owner;
191 req->aram_addr = aram_addr;
192 req->mram_addr = mram_addr;
193 req->len = len;
194 req->prio = prio;
195 req->callback = (cb==NULL) ? __ARQCallbackDummy : cb;
197 _CPU_ISR_Disable(level);
199 if(prio==ARQ_PRIO_LO) __lwp_queue_appendI(&__ARQReqQueueLo,&req->node);
200 else __lwp_queue_appendI(&__ARQReqQueueHi,&req->node);
202 if(!__ARQReqPendingLo && !__ARQReqPendingHi) {
203 p = (ARQRequest*)__lwp_queue_getI(&__ARQReqQueueHi);
204 if(p) {
205 p->state = ARQ_TASK_RUNNING;
206 #ifdef _ARQ_DEBUG
207 printf("ARQ_PostRequest(%02x,%08x,%08x,%d)\n",p->dir,p->aram_addr,p->mram_addr,p->len);
208 #endif
209 AR_StartDMA(p->dir,p->mram_addr,p->aram_addr,p->len);
210 __ARQCallbackHi = p->callback;
211 __ARQReqPendingHi = p;
213 if(!__ARQReqPendingHi) __ARQServiceQueueLo();
215 _CPU_ISR_Restore(level);
218 void ARQ_PostRequest(ARQRequest *req,u32 owner,u32 dir,u32 prio,u32 aram_addr,u32 mram_addr,u32 len)
220 u32 level;
222 ARQ_PostRequestAsync(req,owner,dir,prio,aram_addr,mram_addr,len,__ARQCallbackSync);
224 _CPU_ISR_Disable(level);
225 while(req->state!=ARQ_TASK_FINISHED) {
226 LWP_ThreadSleep(__ARQSyncQueue);
228 _CPU_ISR_Restore(level);
231 void ARQ_RemoveRequest(ARQRequest *req)
233 u32 level;
235 _CPU_ISR_Disable(level);
236 __lwp_queue_extractI(&req->node);
237 if(__ARQReqPendingLo && __ARQReqPendingLo==req && __ARQCallbackLo==NULL) __ARQReqPendingLo = NULL;
238 _CPU_ISR_Restore(level);
241 u32 ARQ_RemoveOwnerRequest(u32 owner)
243 u32 level,cnt;
244 ARQRequest *req;
246 _CPU_ISR_Disable(level);
248 cnt = 0;
249 req = (ARQRequest*)__ARQReqQueueHi.first;
250 while(req!=(ARQRequest*)__lwp_queue_tail(&__ARQReqQueueHi)) {
251 if(req->owner==owner) {
252 __lwp_queue_extractI(&req->node);
253 cnt++;
255 req = (ARQRequest*)req->node.next;
258 req = (ARQRequest*)__ARQReqQueueLo.first;
259 while(req!=(ARQRequest*)__lwp_queue_tail(&__ARQReqQueueLo)) {
260 if(req->owner==owner) {
261 __lwp_queue_extractI(&req->node);
262 cnt++;
264 req = (ARQRequest*)req->node.next;
266 if(__ARQReqPendingLo && __ARQReqPendingLo==req && __ARQCallbackLo==NULL) __ARQReqPendingLo = NULL;
267 _CPU_ISR_Restore(level);
269 return cnt;