Lines 46-55
Link Here
|
46 |
#define VCHIQ_MINOR 0 |
46 |
#define VCHIQ_MINOR 0 |
47 |
|
47 |
|
48 |
/* Some per-instance constants */ |
48 |
/* Some per-instance constants */ |
49 |
#define MAX_COMPLETIONS 16 |
49 |
#define MAX_COMPLETIONS 128 |
50 |
#define MAX_SERVICES 64 |
50 |
#define MAX_SERVICES 64 |
51 |
#define MAX_ELEMENTS 8 |
51 |
#define MAX_ELEMENTS 8 |
52 |
#define MSG_QUEUE_SIZE 64 |
52 |
#define MSG_QUEUE_SIZE 128 |
53 |
|
53 |
|
54 |
#define KEEPALIVE_VER 1 |
54 |
#define KEEPALIVE_VER 1 |
55 |
#define KEEPALIVE_VER_MIN KEEPALIVE_VER |
55 |
#define KEEPALIVE_VER_MIN KEEPALIVE_VER |
Lines 208-237
add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
Link Here
|
208 |
void *bulk_userdata) |
208 |
void *bulk_userdata) |
209 |
{ |
209 |
{ |
210 |
VCHIQ_COMPLETION_DATA_T *completion; |
210 |
VCHIQ_COMPLETION_DATA_T *completion; |
|
|
211 |
int insert; |
211 |
DEBUG_INITIALISE(g_state.local) |
212 |
DEBUG_INITIALISE(g_state.local) |
212 |
|
213 |
|
213 |
while (instance->completion_insert == |
214 |
insert = instance->completion_insert; |
214 |
(instance->completion_remove + MAX_COMPLETIONS)) { |
215 |
while ((insert - instance->completion_remove) >= MAX_COMPLETIONS) { |
215 |
/* Out of space - wait for the client */ |
216 |
/* Out of space - wait for the client */ |
216 |
DEBUG_TRACE(SERVICE_CALLBACK_LINE); |
217 |
DEBUG_TRACE(SERVICE_CALLBACK_LINE); |
217 |
vchiq_log_trace(vchiq_arm_log_level, |
218 |
vchiq_log_trace(vchiq_arm_log_level, |
218 |
"add_completion - completion queue full"); |
219 |
"add_completion - completion queue full"); |
219 |
DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT); |
220 |
DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT); |
|
|
221 |
|
220 |
if (down_interruptible(&instance->remove_event) != 0) { |
222 |
if (down_interruptible(&instance->remove_event) != 0) { |
221 |
vchiq_log_info(vchiq_arm_log_level, |
223 |
vchiq_log_info(vchiq_arm_log_level, |
222 |
"service_callback interrupted"); |
224 |
"service_callback interrupted"); |
223 |
return VCHIQ_RETRY; |
225 |
return VCHIQ_RETRY; |
224 |
} else if (instance->closing) { |
226 |
} |
|
|
227 |
|
228 |
if (instance->closing) { |
225 |
vchiq_log_info(vchiq_arm_log_level, |
229 |
vchiq_log_info(vchiq_arm_log_level, |
226 |
"service_callback closing"); |
230 |
"service_callback closing"); |
227 |
return VCHIQ_ERROR; |
231 |
return VCHIQ_SUCCESS; |
228 |
} |
232 |
} |
229 |
DEBUG_TRACE(SERVICE_CALLBACK_LINE); |
233 |
DEBUG_TRACE(SERVICE_CALLBACK_LINE); |
230 |
} |
234 |
} |
231 |
|
235 |
|
232 |
completion = |
236 |
completion = &instance->completions[insert & (MAX_COMPLETIONS - 1)]; |
233 |
&instance->completions[instance->completion_insert & |
|
|
234 |
(MAX_COMPLETIONS - 1)]; |
235 |
|
237 |
|
236 |
completion->header = header; |
238 |
completion->header = header; |
237 |
completion->reason = reason; |
239 |
completion->reason = reason; |
Lines 252-260
add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
Link Here
|
252 |
wmb(); |
254 |
wmb(); |
253 |
|
255 |
|
254 |
if (reason == VCHIQ_MESSAGE_AVAILABLE) |
256 |
if (reason == VCHIQ_MESSAGE_AVAILABLE) |
255 |
user_service->message_available_pos = |
257 |
user_service->message_available_pos = insert; |
256 |
instance->completion_insert; |
258 |
|
257 |
instance->completion_insert++; |
259 |
instance->completion_insert = ++insert; |
258 |
|
260 |
|
259 |
up(&instance->insert_event); |
261 |
up(&instance->insert_event); |
260 |
|
262 |
|
Lines 279-284
service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
Link Here
|
279 |
USER_SERVICE_T *user_service; |
281 |
USER_SERVICE_T *user_service; |
280 |
VCHIQ_SERVICE_T *service; |
282 |
VCHIQ_SERVICE_T *service; |
281 |
VCHIQ_INSTANCE_T instance; |
283 |
VCHIQ_INSTANCE_T instance; |
|
|
284 |
int skip_completion = 0; |
282 |
DEBUG_INITIALISE(g_state.local) |
285 |
DEBUG_INITIALISE(g_state.local) |
283 |
|
286 |
|
284 |
DEBUG_TRACE(SERVICE_CALLBACK_LINE); |
287 |
DEBUG_TRACE(SERVICE_CALLBACK_LINE); |
Lines 345-353
service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
Link Here
|
345 |
user_service->msg_queue[user_service->msg_insert & |
348 |
user_service->msg_queue[user_service->msg_insert & |
346 |
(MSG_QUEUE_SIZE - 1)] = header; |
349 |
(MSG_QUEUE_SIZE - 1)] = header; |
347 |
user_service->msg_insert++; |
350 |
user_service->msg_insert++; |
348 |
spin_unlock(&msg_queue_spinlock); |
|
|
349 |
|
350 |
up(&user_service->insert_event); |
351 |
|
351 |
|
352 |
/* If there is a thread waiting in DEQUEUE_MESSAGE, or if |
352 |
/* If there is a thread waiting in DEQUEUE_MESSAGE, or if |
353 |
** there is a MESSAGE_AVAILABLE in the completion queue then |
353 |
** there is a MESSAGE_AVAILABLE in the completion queue then |
Lines 356-368
service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
Link Here
|
356 |
if (((user_service->message_available_pos - |
356 |
if (((user_service->message_available_pos - |
357 |
instance->completion_remove) >= 0) || |
357 |
instance->completion_remove) >= 0) || |
358 |
user_service->dequeue_pending) { |
358 |
user_service->dequeue_pending) { |
359 |
DEBUG_TRACE(SERVICE_CALLBACK_LINE); |
|
|
360 |
user_service->dequeue_pending = 0; |
359 |
user_service->dequeue_pending = 0; |
361 |
return VCHIQ_SUCCESS; |
360 |
skip_completion = 1; |
362 |
} |
361 |
} |
363 |
|
362 |
|
|
|
363 |
spin_unlock(&msg_queue_spinlock); |
364 |
|
365 |
up(&user_service->insert_event); |
366 |
|
364 |
header = NULL; |
367 |
header = NULL; |
365 |
} |
368 |
} |
|
|
369 |
|
370 |
if (skip_completion) { |
371 |
DEBUG_TRACE(SERVICE_CALLBACK_LINE); |
372 |
return VCHIQ_SUCCESS; |
373 |
} |
374 |
|
366 |
DEBUG_TRACE(SERVICE_CALLBACK_LINE); |
375 |
DEBUG_TRACE(SERVICE_CALLBACK_LINE); |
367 |
|
376 |
|
368 |
return add_completion(instance, reason, header, user_service, |
377 |
return add_completion(instance, reason, header, user_service, |
Lines 789-795
vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
Link Here
|
789 |
break; |
798 |
break; |
790 |
} |
799 |
} |
791 |
|
800 |
|
792 |
memcpy(&args, (const void*)arg, sizeof(args)); |
801 |
memcpy(&args, (const void*)arg, sizeof(args)); |
793 |
|
802 |
|
794 |
lmutex_lock(&instance->completion_mutex); |
803 |
lmutex_lock(&instance->completion_mutex); |
795 |
|
804 |
|
Lines 797-802
vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
Link Here
|
797 |
while ((instance->completion_remove == |
806 |
while ((instance->completion_remove == |
798 |
instance->completion_insert) |
807 |
instance->completion_insert) |
799 |
&& !instance->closing) { |
808 |
&& !instance->closing) { |
|
|
809 |
|
800 |
DEBUG_TRACE(AWAIT_COMPLETION_LINE); |
810 |
DEBUG_TRACE(AWAIT_COMPLETION_LINE); |
801 |
lmutex_unlock(&instance->completion_mutex); |
811 |
lmutex_unlock(&instance->completion_mutex); |
802 |
rc = down_interruptible(&instance->insert_event); |
812 |
rc = down_interruptible(&instance->insert_event); |
Lines 811-834
vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
Link Here
|
811 |
} |
821 |
} |
812 |
DEBUG_TRACE(AWAIT_COMPLETION_LINE); |
822 |
DEBUG_TRACE(AWAIT_COMPLETION_LINE); |
813 |
|
823 |
|
814 |
/* A read memory barrier is needed to stop prefetch of a stale |
|
|
815 |
** completion record |
816 |
*/ |
817 |
rmb(); |
818 |
|
819 |
if (ret == 0) { |
824 |
if (ret == 0) { |
820 |
int msgbufcount = args.msgbufcount; |
825 |
int msgbufcount = args.msgbufcount; |
|
|
826 |
int remove; |
827 |
|
828 |
remove = instance->completion_remove; |
829 |
|
821 |
for (count = 0; count < args.count; count++) { |
830 |
for (count = 0; count < args.count; count++) { |
822 |
VCHIQ_COMPLETION_DATA_T *completion; |
831 |
VCHIQ_COMPLETION_DATA_T *completion; |
823 |
VCHIQ_SERVICE_T *service1; |
832 |
VCHIQ_SERVICE_T *service1; |
824 |
USER_SERVICE_T *user_service; |
833 |
USER_SERVICE_T *user_service; |
825 |
VCHIQ_HEADER_T *header; |
834 |
VCHIQ_HEADER_T *header; |
826 |
if (instance->completion_remove == |
835 |
|
827 |
instance->completion_insert) |
836 |
if (remove == instance->completion_insert) |
828 |
break; |
837 |
break; |
|
|
838 |
|
829 |
completion = &instance->completions[ |
839 |
completion = &instance->completions[ |
830 |
instance->completion_remove & |
840 |
remove & (MAX_COMPLETIONS - 1)]; |
831 |
(MAX_COMPLETIONS - 1)]; |
841 |
|
|
|
842 |
|
843 |
/* A read memory barrier is needed to prevent |
844 |
** the prefetch of a stale completion record |
845 |
*/ |
846 |
rmb(); |
832 |
|
847 |
|
833 |
service1 = completion->service_userdata; |
848 |
service1 = completion->service_userdata; |
834 |
user_service = service1->base.userdata; |
849 |
user_service = service1->base.userdata; |
Lines 905-911
vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
Link Here
|
905 |
break; |
920 |
break; |
906 |
} |
921 |
} |
907 |
|
922 |
|
908 |
instance->completion_remove++; |
923 |
/* Ensure that the above copy has completed |
|
|
924 |
** before advancing the remove pointer. */ |
925 |
mb(); |
926 |
|
927 |
instance->completion_remove = ++remove; |
909 |
} |
928 |
} |
910 |
|
929 |
|
911 |
if (msgbufcount != args.msgbufcount) { |
930 |
if (msgbufcount != args.msgbufcount) { |