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
|
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
/* $Source: src/lib/occlib/ipc_msgq.c $ */
/* */
/* OpenPOWER OnChipController Project */
/* */
/* Contributors Listed Below - COPYRIGHT 2015,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
/* implied. See the License for the specific language governing */
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
/// \file ipc_msgq.c
/// \brief Implementation of IPC (InterProcessor Communication) routines that
/// involve using message queues (primarily in a thread context).
#include "ipc_api.h"
///////////////////////////////////////////////////////////////////////////////
// Handles msgq messages (commands and responses) by placing them on a message
// queue and then posting the message queue semaphore.
// This function is for internal use only!
void ipc_msgq_handler(ipc_msg_t* msg, void* arg)
{
ipc_msgq_t* msgq = (ipc_msgq_t*)arg;
//NOTE: this is hard coded to 0 on PPE
if(KERN_CONTEXT_CRITICAL_INTERRUPT())
{
//NOTE: this is a no-op on PPE
IPC_DEFER_TO_NONCRITICAL(msg);
}
else
{
KERN_DEQUE_PUSH_BACK(&msgq->msg_head, &msg->node);
KERN_SEMAPHORE_POST(&msgq->msg_sem);
}
}
///////////////////////////////////////////////////////////////////////////////
/// Wait (with timeout) for an IPC message on an IPC message queue.
///
int ipc_msgq_recv(ipc_msg_t** msg, ipc_msgq_t* msgq, KERN_INTERVAL timeout)
{
int rc;
ipc_msg_t* popped_msg = 0;
KERN_MACHINE_CONTEXT ctx;
// First check for pending messages already on the queue.
KERN_CRITICAL_SECTION_ENTER(KERN_CRITICAL, &ctx);
popped_msg = (ipc_msg_t*)KERN_DEQUE_POP_FRONT(&msgq->msg_head);
if(popped_msg)
{
KERN_CRITICAL_SECTION_EXIT(&ctx);
rc = IPC_RC_SUCCESS;
}
else // no message - wait for one
{
rc = KERN_SEMAPHORE_PEND(&msgq->msg_sem, timeout);
KERN_CRITICAL_SECTION_EXIT(&ctx);
if(rc)
{
if(rc == -KERN_SEMAPHORE_PEND_TIMED_OUT ||
rc == -KERN_SEMAPHORE_PEND_NO_WAIT)
{
rc = IPC_RC_TIMEOUT;
}
}
else
{
//The queue is also modified in the IPC interrupt context so
//we need to make sure interrupts are disabled while we modify it.
KERN_CRITICAL_SECTION_ENTER(KERN_CRITICAL, &ctx);
popped_msg = (ipc_msg_t*)KERN_DEQUE_POP_FRONT(&msgq->msg_head);
KERN_CRITICAL_SECTION_EXIT(&ctx);
if(popped_msg)
{
rc = IPC_RC_SUCCESS;
}
else
{
rc = IPC_RC_NO_MSG;
}
}
}
*msg = popped_msg;
return rc;
}
///////////////////////////////////////////////////////////////////////////////
/// Associate a message queue with a function ID (commands recieved with the
/// specified function id will be placed on the message queue).
///
int ipc_register_msgq(uint32_t func_id, ipc_msgq_t* msgq)
{
return ipc_set_handler(func_id, ipc_msgq_handler, msgq);
}
|