summaryrefslogtreecommitdiffstats
path: root/src/lib/occlib/ipc_api.h
blob: 68538c9fa0ba6c1a229d1cc00337ffd37450ff1a (plain)
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
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/lib/occlib/ipc_api.h $                                    */
/*                                                                        */
/* OpenPOWER OnChipController Project                                     */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2017                        */
/* [+] 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                                                     */
#ifndef __IPC_API_H__
#define __IPC_API_H__

/// \file ipc_api.h
/// \brief Common header for Interprocessor Communications API
///
#include "ipc_structs.h"

#ifndef __ASSEMBLER__
///////////////////////////////////////////////////////////////////////////////
/// Initialize an IPC command message
///
/// \param msg A pointer to the command message
///
/// \param func_id A user-defined function ID that is known to both the sender
/// and receiver of a command message.  (Defined in \a ipc_func_ids.h)
///
/// \param resp_callback A user-defined function that should be called when
/// the message is returned as a response to the command.  This must be set
/// to 0 if no callback function should be called.
///
/// \param callback_arg A pointer to user-defined data that will be passed in
/// to the callback function when it is called. This should be set to 0 if
/// no data needs to be passed.
///
/// This function (or \a ipc_init_msgq_msg) must be called on a message at
/// least once before it is sent via the \a ipc_send_msg interface.
///
/// There are two types of function ID's. Function ID's that only work on a
/// single processor are called \e single-target ID's.  These function
/// ID's have the target ID embedded as part of the ID.  FUnction ID's
/// that are supported on multiple processors are called \e multi-target ID's.
/// Command messages associated with multi-target function ID's must go through
/// the extra step of setting the target ID by calling the \a ipc_set_cmd_target
/// interface on the command message.
///
/// If a callback function is provided, that callback function should cause
/// (directly or indirectly) the \ipc_free_msg interface to be called once it
/// is known that it is safe for the message to be reused (sent as a command
/// again).
///
void ipc_init_msg(ipc_msg_t* msg,
                  uint32_t func_id,
                  ipc_msg_handler_t resp_callback,
                  void* callback_arg);

//Use these to statically initialize an IPC message
#define IPC_MSG_INIT(_func_id, _resp_callback, _callback_arg) \
    {\
        {.node = KERN_DEQUE_ELEMENT_INIT()}, \
        .func_id.word32 = _func_id, \
                          .ipc_rc = IPC_RC_SUCCESS, \
                                    .resp_callback = _resp_callback, \
                                            .callback_arg = _callback_arg \
    }

#define IPC_MSG_CREATE(msg_name, _func_id, _resp_callback, _callback_arg) \
    ipc_msg_t msg_name = IPC_MSG_INIT(_func_id, _resp_callback, _callback_arg)

///////////////////////////////////////////////////////////////////////////////
/// Free up a message to be reused.
///
/// \param msg a pointer to a message.
///
/// This interface should be called on a message when it is known that it is
/// safe to reuse the message.  Normally, this would be one of the last things
/// performed in the response callback function for a command, but it may also
/// be called when it is known that a peer has stopped functioning.
///
static inline void ipc_free_msg(ipc_msg_t* msg)
{
    msg->func_id.active_flag = 0;
}

///////////////////////////////////////////////////////////////////////////////
/// Set the target ID for a multi-target command message.
///
/// \param cmd A pointer to an initialized command message.
///
/// \param target_id The target ID of the processor the command is intended
/// for.
///
/// The following return codes are possible:
///
/// \retval IPC_RC_SUCCESS The command's target ID was updated.
///
/// \retval IPC_RC_INVALID_FUNC_ID The function ID associated with this
/// command is not a valid mult-target function ID.
///
int ipc_set_cmd_target(ipc_msg_t* cmd, uint32_t target_id);


///////////////////////////////////////////////////////////////////////////////
/// Send a message as a command
///
/// \param cmd A pointer to an initialized command message
///
/// It is expected that at some point prior to calling this function the
/// message was initialized with a call to \a ipc_init_msg or
/// \a ipc_init_msgq_msg.
///
/// Once a message has been sent it is not safe to send again until it has been
/// sent back to the sender as a response.
///
/// The following return codes are possible:
///
/// \retval IPC_RC_SUCCESS The message was successfully placed on the target's
/// receive buffer.
///
/// \retval IPC_RC_SELF_BLOCKED The call was made prior to calling
/// \a ipc_enable.
///
/// \retval IPC_RC_INVALID_FUNC_ID The command was initialized with an invalid
/// function ID.
///
/// \retval IPC_RC_MSG_ACTIVE The message is currently in use.
///
/// \retval IPC_RC_INVALID_TARGET_ID The message was initialized with an
/// invalid target ID.  This can happen if a multi-target command has not had
/// its target set via the \a ipc_set_cmd_target function at least one time.
///
/// \retval IPC_RC_BUFFER_FULL The command could not be sent because the target's
/// receive buffer is full.
///
/// \retval IPC_RC_TARGET_BLOCKED The command could not be sent because the
/// target is blocking any new messages.
///
int ipc_send_cmd(ipc_msg_t* cmd);


////////////////////////////////////////////////////////////////////////////////
/// Send a command message back to the sender as a response message with status.
///
/// \param rsp A pointer to a message that was recieved as a command message.
///
/// \param ipc_rc This should be either \a IPC_RC_SUCCESS if the command was
/// successful or \a IPC_RC_CMD_FAILED if the command failed.  If
/// command-specific return codes are needed, they should be returned as
/// command-specific fields instead of returning them here so that there
/// is no risk of overlapping return codes.
///
/// It is expected that at some point prior to calling this function the
/// message was initialized with a call to \a ipc_init_msg or
/// \a ipc_init_msgq_msg.
///
/// Once a message has been sent it is not safe to send again until it has been
/// sent back to the sender as a response.
///
/// The following return codes are possible:
///
/// \retval IPC_RC_SUCCESS The message was successfully placed on the target's
/// receive buffer.
///
/// \retval IPC_RC_MSG_NOT_ACTIVE The message is not from an active command.
///
/// \retval IPC_RC_INVALID_TARGET_ID The target id for the sender is invalid.
/// This likely means that the message has been corrupted.
///
/// \retval IPC_RC_BUFFER_FULL The response could not be sent because the target's
/// recieve buffer is full.
///
/// \retval IPC_RC_TARGET_BLOCKED The response could not be sent because the
/// target is blocking any new messages.
///
int ipc_send_rsp(ipc_msg_t* rsp, uint32_t return_code);


///////////////////////////////////////////////////////////////////////////////
/// Retrieves the IPC return code embedded in the response message.
///
/// \param rsp A pointer to a response message.
///
/// The embedded IPC return code is how the remote processor communicates
/// IPC internal failures to the local processor.  It can also be used by
/// non-IPC code on the remote processor to signal success or failure when it
/// sends the response message via the \a ipc_send_rsp interface.
///
/// The IPC return code should always be checked to verify that a command
/// message was processed successfully.
///
/// The following return codes are possible:
///
/// \retval IPC_RC_SUCCESS The message was successfully processed.
///
/// \retval IPC_RC_CMD_FAILED The command was processed on the remote end but
/// did not complete successfully.
///
/// \retval IPC_RC_CMD_NOT_SUPPORTED The function ID for the command is valid
/// but the remote end does not have support for that function ID.
///
/// \retval IPC_RC_INVALID_FUNC_ID The function ID for the command is invalid.
///
static inline int ipc_get_rc(ipc_msg_t* rsp)
{
    return rsp->ipc_rc;
}

///////////////////////////////////////////////////////////////////////////////
/// Retrieve the IPC function ID for a message
///
/// \param msg A pointer to an IPC message
///
/// This interface should be used to extract the IPC function ID of a message.
///
/// The IPC function ID is returned.
///
static inline int ipc_get_funcid(ipc_msg_t* msg)
{
    int func_id = msg->func_id.word32;

    //Multi-target function ID's always have the target ID set to
    //so that if the caller doesn't set it to a proper target id it will
    //flag an error.
    if(func_id & IPC_FLAG_MT)
    {
        func_id |= IPC_TARGET_MASK;
    }

    //Clear the active and response flags in case they are set along
    //with the sender ID.
    func_id &= ~(IPC_FLAG_ACTIVE | IPC_FLAG_RESPONSE | IPC_SENDER_MASK);

    return func_id;
}

///////////////////////////////////////////////////////////////////////////////
/// Determine if a message is a response or a command
///
/// \param msg A pointer to an IPC message
///
/// This function should be used to determine if a message is a response or a
/// command.  The function will return a non-zero value if the message is a
/// response and 0 otherwise.
///
static inline int ipc_is_a_response(ipc_msg_t* msg)
{
    return msg->func_id.response_flag;
}

///////////////////////////////////////////////////////////////////////////////
/// Determine if a message is free to be re-used
///
/// \param msg A pointer to an IPC message
///
/// This function should be used to determine if a message is free to re-use.
/// The function will return a non-zero value if the message is free and
/// 0 otherwise.
///
static inline int ipc_is_free(ipc_msg_t* msg)
{
    return !msg->func_id.active_flag;
}

///////////////////////////////////////////////////////////////////////////////
/// Retrieve the sender ID of a message.
///
/// \param msg A pointer to an IPC message
///
/// This function should be used to retrieve the sender ID of a message.  It
/// returns the sender ID.
///
static inline int ipc_sender_id(ipc_msg_t* msg)
{
    return msg->func_id.sender_id;
}

///////////////////////////////////////////////////////////////////////////////
/// Retrieve the target ID of a message.
///
/// \param msg A pointer to an IPC message
///
/// This function should be used to retrieve the target ID of a message.  It
/// returns the target ID.
///
static inline int ipc_target_id(ipc_msg_t* msg)
{
    return msg->func_id.target_id;
}

///////////////////////////////////////////////////////////////////////////////
/// Initializes IPC control structures.
///
/// Clears the IPC buffers for this processor and places them in a state
/// where new messages are blocked.  Also initializes the IPC handler table
/// for this processor if STATIC_IPC_TABLES has not been defined.
///
/// This function always returns \a IPC_RC_SUCCESS
///
int ipc_init(void);


///////////////////////////////////////////////////////////////////////////////
/// Enables IPC communications.
///
/// Unmasks the IPC interrupt for this processor and places the circular
/// buffers in a state where they can recieve messages.
///
/// This function must be called before using the \a ipc_send_cmd function or
/// it will return \a IPC_RC_SELF_BLOCKED.
///
/// The function always returns \a IPC_RC_SUCCESS.
///
int ipc_enable(void);


///////////////////////////////////////////////////////////////////////////////
/// Disable recieving new IPC commands for a processor.
///
/// \param target_id The target ID of the processor to disable receiving new
/// IPC commands on.
///
/// This interface should be used by a processor that knows it is about to go
/// down or by a processor that knows that one of its peers has halted.
///
/// Calling this function on a processor will cause other processors to get
/// a return code of \a IPC_RC_TARGET_BLOCKED with subsequent calls to
/// \a ipc_send_cmd.  Calling this function on one's self (using a target ID of
/// OCCHW_INST_ID_SELF) will cause subsequent calls to \a ipc_send_cmd to
/// return \a IPC_RC_SELF_BLOCKED.
///
/// Possible return codes for this function are:
///
/// \retval IPC_RC_SUCCESS The target processor was successfully disabled.
///
/// \retval IPC_RC_INVALID_TARGET_ID The target ID is invalid.
///
int ipc_disable(uint32_t target_id);


///////////////////////////////////////////////////////////////////////////////
/// Associates an IPC function ID with a handler function
///
/// \param func_id A user-defined function ID that is known to both the sender
/// and receiver of a command message.  (Defined in \a ipc_func_ids.h)
///
/// \param handler A pointer to the function that handles command messages that
/// have been initialized with \a func_id.
///
/// \param callback_arg A pointer to data that is passed as an argument to the
/// handler function when it is called.
///
/// This function should be used to link an IPC function ID with a function.
/// Once this has been done, if the local processor recieves a command message
/// with an IPC function ID that matches \a func_id then it will call the
/// handler function that was specified by \a handler.
///
/// NOTE: All handler functions will be called from an interrupt context.
///
/// Possible return codes are:
///
/// \retval IPC_RC_SUCCESS The operation completed successfully.
///
/// \retval IPC_RC_INVALID_TARGET_ID The function ID is a single-target
/// function ID that does not target this processor.
///
/// \retval IPC_RC_INVALID_FUNC_ID The function ID is not a valid IPC function
/// ID.
///
/// \retval IPC_RC_INVALID_ARG The handler parameter must be a non-zero value.
///
int ipc_set_handler(uint32_t func_id,
                    ipc_msg_handler_t handler,
                    void* callback_arg);


///////////////////////////////////////////////////////////////////////////////
/// Initialize an IPC message queue.
///
/// \param msgq A pointer to a message queue.
///
/// All message queues must be initialized one time prior to use with other
/// interfaces.
///
void ipc_init_msgq(ipc_msgq_t* msgq);

//Use this to statically initialize an IPC message queue
#define IPC_MSGQ_CREATE(msgq) \
    ipc_msgq_t msgq = \
                      {\
                       .msg_head = KERN_DEQUE_SENTINEL_INIT(&msgq.msg_head),\
                       .msg_sem = KERN_SEMAPHORE_INITIALIZATION(0, 0)\
                      }

///////////////////////////////////////////////////////////////////////////////
/// Initialize an IPC message and associate it with an IPC message queue
///
/// \param msg A pointer to an IPC message.
///
/// \param func_id A user-defined function ID that is known to both the sender
/// and receiver of the command message.  (Defined in \a ipc_func_ids.h)
///
/// \param msgq A pointer to an initialized IPC message queue.
///
/// This interface should be used in place of \a ipc_init_msg when the caller
/// wishes to have the command response placed on the specified IPC message
/// queue.  This allows a thread to block (via the \a ipc_msq_recv interface)
/// on the message queue until a response to a command has arrived.
///
/// \note An IPC message queue can be associated with more than one IPC
/// message.
///
/// See \a ipc_init_msg for more information.
///
void ipc_init_msgq_msg(ipc_msg_t* msg, uint32_t func_id, ipc_msgq_t* msgq);

//Use this to statically create an initialized IPC message queue message
#define IPC_MSGQ_MSG_CREATE(msg_name, func_id, msgq) \
    IPC_MSG_CREATE(msg_name, func_id, ipc_msgq_handler, msgq)

///////////////////////////////////////////////////////////////////////////////
/// Wait (with timeout) for an IPC message on an IPC message queue.
///
/// \param msg A pointer to an IPC message pointer.
///
/// \param msgq A pointer to an initialized IPC message queue.
///
/// \param timeout The time to wait for the next IPC message to arrive.
///
/// This interface can be used in a thread context to block while waiting for
/// the next message (command or response) to arrive on an IPC message queue.
///
/// For an IPC command message to be placed on an IPC message queue, the
/// function ID for the command must first be associated with the message queue
/// by making a call to \a ipc_register_msgq.
///
/// For an IPC response message to be placed on an IPC message queue, the
/// message must be initialized via the \a ipc_init_msgq_msg interface.
///
/// If \a ipc_msgq_recv returns a value of \a IPC_RC_SUCCESS then \a msg is
/// guaranteed to point to a new message.  Otherwise, an IPC message was not
/// retrieved from the message queue and \a msg will be set to 0.
///
/// Possible return codes for this function are:
///
/// \retval IPC_RC_SUCCESS A new IPC message was received and \a msg has been
/// set to point to the new message.
///
/// \retval IPC_RC_TIMEOUT No new messages were recieved within the timeout
/// period and \msg was set to 0.
///
/// \retval IPC_RC_NO_MSG This should never happen, but if it does it indicates
/// an internal failure occurred.
///
int ipc_msgq_recv(ipc_msg_t** msg, ipc_msgq_t* msgq, KERN_INTERVAL timeout);


///////////////////////////////////////////////////////////////////////////////
/// Associate an IPC message queue with an IPC function ID
///
/// \param func_id A user-defined function ID that is known to both the sender
/// and receiver of a command message.  (Defined in \a ipc_func_ids.h)
///
/// \param msgq A pointer to an initialized IPC message queue.
///
/// This interface associates an IPC function ID with an IPC message queue so
/// that when the calling processor recieves a command with the specified
/// function ID the message will be place on the message queue and a thread
/// that is blocked waiting for a message on the queue (using the
/// \a ipc_msgq_recv interface) will be woken up and given the message.
///
/// This function should be called in place of the \a ipc_set_handler
/// interface.
///
/// NOTE: Multiple function ID's can be associated with a single queue.
///
/// Possible return codes are:
///
/// \retval IPC_RC_SUCCESS The operation completed successfully.
///
/// \retval IPC_RC_INVALID_TARGET_ID The function ID is a single-target
/// function ID that does not target this processor.
///
/// \retval IPC_RC_INVALID_FUNC_ID The function ID is not a valid IPC function
/// ID.
///
int ipc_register_msgq(uint32_t func_id, ipc_msgq_t* msgq);

///////////////////////////////////////////////////////////////////////////////
/// Internal function that places an IPC message on an IPC message queue
///
void ipc_msgq_handler(ipc_msg_t* msg, void* arg);

///////////////////////////////////////////////////////////////////////////////
/// The default IPC command handler simply sends a response with the IPC return
/// code set to IPC_RC_CMD_NOT_SUPPORTED
///
void ipc_default_handler(ipc_msg_t* msg, void* arg);

#endif /*__ASSEMBLER__*/
#endif  /* __IPC_API_H__ */
OpenPOWER on IntegriCloud