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