1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
|
/*
* arch/arm/mach-sunxi/arisc/message_manager/message_manager.c
*
* Copyright (c) 2012 Allwinner.
* 2012-10-01 Written by superm (superm@allwinnertech.com).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "message_manager_i.h"
/* the start and end of message pool */
static struct arisc_message *message_start;
static struct arisc_message *message_end;
/* spinlock for this module */
static spinlock_t msg_mgr_lock;
/* message cache manager */
static struct arisc_message_cache message_cache;
static void *arisc_message_pool_base;
static uint32_t arisc_message_pool_size;
/**
* initialize message manager.
* @para: none.
*
* returns: 0 if initialize succeeded, others if failed.
*/
int arisc_message_manager_init(void *addr, uint32_t size)
{
int i;
arisc_message_pool_base = addr;
arisc_message_pool_size = size;
/* initialize message pool start and end */
message_start = (struct arisc_message *)(arisc_message_pool_base);
message_end = (struct arisc_message *)((ptrdiff_t)arisc_message_pool_base + arisc_message_pool_size);
//memset((void *)message_start, 0, arisc_message_pool_size);
/* initialize message_cache */
for (i = 0; i < ARISC_MESSAGE_CACHED_MAX; i++) {
message_cache.cache[i] = NULL;
}
message_cache.number = 0;
return 0;
}
/**
* exit message manager.
* @para: none.
*
* returns: 0 if exit succeeded, others if failed.
*/
int arisc_message_manager_exit(void)
{
return 0;
}
static int arisc_message_invalid(struct arisc_message *pmessage)
{
if ((pmessage >= message_start) &&
(pmessage < message_end)) {
/* valid arisc message */
return 0;
}
/* invalid arisc message */
return 1;
}
/**
* allocate one message frame. mainly use for send message by message-box,
* the message frame allocate form messages pool shared memory area.
* @para: none.
*
* returns: the pointer of allocated message frame, NULL if failed;
*/
struct arisc_message *arisc_message_allocate(unsigned int msg_attr)
{
struct arisc_message *pmessage = NULL;
struct arisc_message *palloc = NULL;
/* first find in message_cache */
spin_lock(&msg_mgr_lock);
if (message_cache.number) {
ARISC_INF("arisc message_cache.number = 0x%x.\n", message_cache.number);
message_cache.number--;
palloc = message_cache.cache[message_cache.number];
ARISC_INF("message [%llx] allocate from message_cache\n", palloc);
if (arisc_message_invalid(palloc)) {
ARISC_ERR("allocate cache message [%llx] invalid\n", palloc);
}
}
spin_unlock(&msg_mgr_lock);
if (arisc_message_invalid(palloc)) {
/*
* cached message_cache finded fail,
* use spinlock 0 to exclusive with arisc.
*/
arisc_hwspin_lock(AW_MSG_HWSPINLOCK);
/* search from the start of message pool every time. */
pmessage = message_start;
while (pmessage < message_end) {
if (pmessage->state == ARISC_MESSAGE_FREED) {
/* find free message in message pool, allocate it */
palloc = pmessage;
palloc->state = ARISC_MESSAGE_ALLOCATED;
ARISC_INF("message [%llx] allocate from message pool\n", palloc);
break;
}
/* next message frame */
pmessage++;
}
/* unlock hwspinlock 0 */
arisc_hwspin_unlock(AW_MSG_HWSPINLOCK);
}
if (arisc_message_invalid(palloc)) {
ARISC_ERR("allocate message [%llx] frame is invalid\n", palloc);
return NULL;
}
/* initialize messgae frame */
palloc->next = NULL;
palloc->attr = msg_attr;
palloc->private = NULL;
return palloc;
}
/**
* free one message frame. mainly use for process message finished,
* free it to messages pool or add to free message queue.
* @pmessage: the pointer of free message frame.
*
* returns: none.
*/
void arisc_message_free(struct arisc_message *pmessage)
{
struct arisc_message *free_message = pmessage;
/* check this message valid or not */
if (arisc_message_invalid(free_message)) {
ARISC_ERR("free invalid arisc message [%llx]\n", free_message);
return;
}
/* try to free to free_list first */
spin_lock(&msg_mgr_lock);
if (message_cache.number < ARISC_MESSAGE_CACHED_MAX) {
ARISC_INF("insert message [%llx] to message_cache\n", free_message);
ARISC_INF("message_cache number : %d\n", message_cache.number);
/* cached this message, message state: ALLOCATED */
message_cache.cache[message_cache.number] = free_message;
message_cache.number++;
free_message->next = NULL;
free_message->state = ARISC_MESSAGE_ALLOCATED;
free_message = NULL;
}
spin_unlock(&msg_mgr_lock);
/* try to free message to pool if free to cache fail */
if (free_message) {
/* free to message pool,set message state as FREED. */
arisc_hwspin_lock(AW_MSG_HWSPINLOCK);
ARISC_INF("insert message [%llx] to message pool\n", free_message);
free_message->state = ARISC_MESSAGE_FREED;
free_message->next = NULL;
arisc_hwspin_unlock(AW_MSG_HWSPINLOCK);
}
}
/**
* notify system that one message coming.
* @pmessage: the pointer of coming message frame.
*
* returns: 0 if notify succeeded, other if failed.
*/
int arisc_message_coming_notify(struct arisc_message *pmessage)
{
int ret;
/* ac327 receive message to arisc */
ARISC_INF("-------------------------------------------------------------\n");
ARISC_INF(" MESSAGE FROM ARISC \n");
ARISC_INF("message addr : %llx\n", pmessage);
ARISC_INF("message type : %x\n", pmessage->type);
ARISC_INF("message attr : %x\n", pmessage->attr);
ARISC_INF("-------------------------------------------------------------\n");
/* message per-process */
pmessage->state = ARISC_MESSAGE_PROCESSING;
/* process message */
switch (pmessage->type) {
case ARISC_AXP_INT_COMING_NOTIFY: {
ARISC_INF("pmu interrupt coming notify\n");
ret = arisc_axp_int_notify(pmessage);
pmessage->result = ret;
break;
}
case ARISC_AUDIO_PERDONE_NOTIFY: {
ARISC_INF("audio perdone notify\n");
ret = arisc_audio_perdone_notify(pmessage);
pmessage->result = ret;
break;
}
case ARISC_REPORT_ERR_INFO: {
ARISC_INF("arisc report error info\n");
ret = arisc_report_error_info(pmessage);
pmessage->result = ret;
break;
}
default : {
ARISC_ERR("invalid message type for ac327 process\n");
ARISC_ERR("message addr : %llx\n", pmessage);
ARISC_ERR("message state : %x\n", pmessage->state);
ARISC_ERR("message attr : %x\n", pmessage->attr);
ARISC_ERR("message type : %x\n", pmessage->type);
ARISC_ERR("message result : %x\n", pmessage->result);
ret = -EINVAL;
break;
}
}
/* message post process */
pmessage->state = ARISC_MESSAGE_PROCESSED;
if (pmessage->attr & ARISC_MESSAGE_ATTR_HARDSYN) {
/* synchronous message, should feedback process result */
arisc_hwmsgbox_feedback_message(pmessage, ARISC_SEND_MSG_TIMEOUT);
} else {
/*
* asyn message, no need feedback message result,
* free message directly.
*/
arisc_message_free(pmessage);
}
return ret;
}
struct arisc_message *arisc_message_map_to_cpux(uint32_t addr)
{
struct arisc_message *message;
message = (struct arisc_message *)((ptrdiff_t)addr + (ptrdiff_t)arisc_message_pool_base);
return message;
}
uint32_t arisc_message_map_to_cpus(struct arisc_message *message)
{
uint32_t value = (uint32_t)((ptrdiff_t)message - (ptrdiff_t)arisc_message_pool_base);
return value;
}
int arisc_message_valid(struct arisc_message *pmessage)
{
if ((pmessage >= message_start) && (pmessage < message_end)) {
/* valid message */
return 1;
}
return 0;
}
|