1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <platform.h>
18 #include <eventQ.h>
19 #include <stddef.h>
20 #include <timer.h>
21 #include <stdio.h>
22 #include <heap.h>
23 #include <slab.h>
24 #include <cpu.h>
25 #include <util.h>
26 #include <plat/inc/plat.h>
27
28
29 struct EvtRecord {
30 struct EvtRecord *next;
31 struct EvtRecord *prev;
32 uint32_t evtType;
33 void* evtData;
34 uintptr_t evtFreeData;
35 };
36
37 struct EvtQueue {
38 struct EvtRecord *head;
39 struct EvtRecord *tail;
40 struct SlabAllocator *evtsSlab;
41 EvtQueueForciblyDiscardEvtCbkF forceDiscardCbk;
42 };
43
44
45
evtQueueAlloc(uint32_t size,EvtQueueForciblyDiscardEvtCbkF forceDiscardCbk)46 struct EvtQueue* evtQueueAlloc(uint32_t size, EvtQueueForciblyDiscardEvtCbkF forceDiscardCbk)
47 {
48 struct EvtQueue *q = heapAlloc(sizeof(struct EvtQueue));
49 struct SlabAllocator *slab = slabAllocatorNew(sizeof(struct EvtRecord), alignof(struct EvtRecord), size);
50
51 if (q && slab) {
52 q->forceDiscardCbk = forceDiscardCbk;
53 q->evtsSlab = slab;
54 q->head = NULL;
55 q->tail = NULL;
56 return q;
57 }
58
59 if (q)
60 heapFree(q);
61 if (slab)
62 slabAllocatorDestroy(slab);
63
64 return NULL;
65 }
66
evtQueueFree(struct EvtQueue * q)67 void evtQueueFree(struct EvtQueue* q)
68 {
69 struct EvtRecord *t;
70
71 while (q->head) {
72 t = q->head;
73 q->head = q->head->next;
74 q->forceDiscardCbk(t->evtType, t->evtData, t->evtFreeData);
75 slabAllocatorFree(q->evtsSlab, t);
76 }
77
78 slabAllocatorDestroy(q->evtsSlab);
79 heapFree(q);
80 }
81
evtQueueEnqueue(struct EvtQueue * q,uint32_t evtType,void * evtData,uintptr_t evtFreeData,bool atFront)82 bool evtQueueEnqueue(struct EvtQueue* q, uint32_t evtType, void *evtData, uintptr_t evtFreeData, bool atFront)
83 {
84 struct EvtRecord *rec;
85 uint64_t intSta;
86
87 if (!q)
88 return false;
89
90 rec = slabAllocatorAlloc(q->evtsSlab);
91 if (!rec) {
92 intSta = cpuIntsOff();
93
94 //find a victim for discarding
95 rec = q->head;
96 while (rec && !(rec->evtType & EVENT_TYPE_BIT_DISCARDABLE))
97 rec = rec->next;
98
99 if (rec) {
100 q->forceDiscardCbk(rec->evtType, rec->evtData, rec->evtFreeData);
101 if (rec->prev)
102 rec->prev->next = rec->next;
103 else
104 q->head = rec->next;
105 if (rec->next)
106 rec->next->prev = rec->prev;
107 else
108 q->tail = rec->prev;
109 }
110
111 cpuIntsRestore (intSta);
112 if (!rec)
113 return false;
114 }
115
116 rec->next = NULL;
117 rec->evtType = evtType;
118 rec->evtData = evtData;
119 rec->evtFreeData = evtFreeData;
120
121 intSta = cpuIntsOff();
122
123 if (atFront) { /* this is almost always not the case */
124 rec->prev = NULL;
125 rec->next = q->head;
126 q->head = rec;
127 if (q->tail)
128 rec->next->prev = rec;
129 else
130 q->tail = rec;
131 }
132 else { /* the common case */
133 rec->prev = q->tail;
134 q->tail = rec;
135 if (q->head)
136 rec->prev->next = rec;
137 else
138 q->head = rec;
139 }
140
141 cpuIntsRestore(intSta);
142 platWake();
143 return true;
144 }
145
evtQueueDequeue(struct EvtQueue * q,uint32_t * evtTypeP,void ** evtDataP,uintptr_t * evtFreeDataP,bool sleepIfNone)146 bool evtQueueDequeue(struct EvtQueue* q, uint32_t *evtTypeP, void **evtDataP, uintptr_t *evtFreeDataP, bool sleepIfNone)
147 {
148 struct EvtRecord *rec = NULL;
149 uint64_t intSta;
150
151 while(1) {
152 intSta = cpuIntsOff();
153
154 rec = q->head;
155 if (rec) {
156 q->head = rec->next;
157 if (q->head)
158 q->head->prev = NULL;
159 else
160 q->tail = NULL;
161 break;
162 }
163 else if (!sleepIfNone)
164 break;
165 else if (!timIntHandler()) { // check for timers. if any fire, do not sleep (since by the time callbacks run, moremight be due)
166 platSleep(); //sleep
167 timIntHandler(); //first thing when awake: check timers
168 }
169 cpuIntsRestore(intSta);
170 }
171
172 cpuIntsRestore(intSta);
173
174 if (!rec)
175 return false;
176
177 *evtTypeP = rec->evtType;
178 *evtDataP = rec->evtData;
179 *evtFreeDataP = rec->evtFreeData;
180 slabAllocatorFree(q->evtsSlab, rec);
181
182 return true;
183 }
184
185