]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ipc/ipcdev.git/blob - src/ti/sdo/ipc/transports/TransportShmCirc.c
0058666d9db5cbab1dc01d7f77d5778571c77422
[ipc/ipcdev.git] / src / ti / sdo / ipc / transports / TransportShmCirc.c
1 /*
2  * Copyright (c) 2012-2013, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  *  ======== TransportShmCirc.c ========
34  */
36 #include <xdc/std.h>
38 #include <xdc/runtime/Assert.h>
39 #include <xdc/runtime/Error.h>
40 #include <xdc/runtime/Memory.h>
42 #include <ti/sysbios/hal/Cache.h>
43 #include <ti/sysbios/hal/Hwi.h>
44 #include <ti/sysbios/knl/Swi.h>
46 #include <ti/sdo/ipc/interfaces/INotifyDriver.h>
48 #include "package/internal/TransportShmCirc.xdc.h"
50 #include <ti/sdo/ipc/_Ipc.h>
51 #include <ti/sdo/utils/_MultiProc.h>
52 #include <ti/sdo/ipc/_SharedRegion.h>
53 #include <ti/sdo/ipc/_Notify.h>
54 #include <ti/sdo/ipc/_MessageQ.h>
56 /* Bit mask operations */
57 #define SET_BIT(num,pos)            ((num) |= (1u << (pos)))
58 #define CLEAR_BIT(num,pos)          ((num) &= ~(1u << (pos)))
59 #define TEST_BIT(num,pos)           ((num) & (1u << (pos)))
61 /* Need to use reserved notify events */
62 #undef TransportShmCirc_notifyEventId
63 #define TransportShmCirc_notifyEventId \
64         ti_sdo_ipc_transports_TransportShmCirc_notifyEventId + \
65                     (UInt32)((UInt32)Notify_SYSTEMKEY << 16)
67 /*
68  *************************************************************************
69  *                       Instance functions
70  *************************************************************************
71  */
73 /*
74  *  ======== TransportShmCirc_Instance_init ========
75  */
76 Int TransportShmCirc_Instance_init(TransportShmCirc_Object *obj,
77         UInt16 remoteProcId, const TransportShmCirc_Params *params,
78         Error_Block *eb)
79 {
80     Int         localIndex;
81     Int         remoteIndex;
82     UInt32      minAlign;
83     Int         status;
84     Bool        flag;
85     Swi_Handle  swiHandle;
86     Swi_Params  swiParams;
87     SizeT       ctrlSize, circBufSize, totalSelfSize;
89     swiHandle = TransportShmCirc_Instance_State_swiObj(obj);
91     /* determine which slot to use */
92     if (MultiProc_self() < remoteProcId) {
93         localIndex  = 0;
94         remoteIndex = 1;
95     }
96     else {
97         localIndex  = 1;
98         remoteIndex = 0;
99     }
101     /* Creating using sharedAddr */
102     obj->regionId = SharedRegion_getId(params->sharedAddr);
104     /* determine the minimum alignment */
105     minAlign = Memory_getMaxDefaultTypeAlign();
106     if (SharedRegion_getCacheLineSize(obj->regionId) > minAlign) {
107         minAlign = SharedRegion_getCacheLineSize(obj->regionId);
108     }
110     /* Assert that the buffer is in a valid shared region */
111     Assert_isTrue(obj->regionId != SharedRegion_INVALIDREGIONID,
112         ti_sdo_ipc_Ipc_A_addrNotInSharedRegion);
114     /* Assert that sharedAddr is cache aligned */
115     Assert_isTrue(((UInt32)params->sharedAddr % minAlign == 0),
116         ti_sdo_ipc_Ipc_A_addrNotCacheAligned);
118     /* set object fields */
119     obj->cacheEnabled = SharedRegion_isCacheEnabled(obj->regionId);
120     obj->objType      = ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC;
121     obj->priority     = params->priority;
122     obj->remoteProcId = remoteProcId;
124     /* calculate the circular buffer size one-way */
125     circBufSize =
126         _Ipc_roundup(sizeof(Bits32) * TransportShmCirc_numMsgs, minAlign);
128     /* calculate the control size one-way */
129     ctrlSize = _Ipc_roundup(sizeof(Bits32), minAlign);
131     /* calculate the total size one-way */
132     totalSelfSize =  circBufSize + (2 * ctrlSize);
134     /*
135      *  Init put/get buffer and index pointers.
136      *  These are all on different cache lines.
137      */
138     obj->putBuffer =
139         (Ptr)((UInt32)params->sharedAddr + (localIndex * totalSelfSize));
141     obj->putWriteIndex = (Bits32 *)((UInt32)obj->putBuffer + circBufSize);
143     obj->putReadIndex = (Bits32 *)((UInt32)obj->putWriteIndex + ctrlSize);
145     obj->getBuffer =
146         (Ptr)((UInt32)params->sharedAddr + (remoteIndex * totalSelfSize));
148     obj->getWriteIndex = (Bits32 *)((UInt32)obj->getBuffer + circBufSize);
150     obj->getReadIndex = (Bits32 *)((UInt32)obj->getWriteIndex + ctrlSize);
152     /*
153      *  Calculate the size for cache inv in isr.
154      *  This size is the circular buffer + putWriteIndex.
155      *  [sizeof(Ptr) * numMsgs] + [the sizeof(Ptr)]
156      *  aligned to a cache line.
157      */
158     obj->opCacheSize = ((UInt32)obj->putReadIndex - (UInt32)obj->putBuffer);
160     /* construct the Swi */
161     Swi_Params_init(&swiParams);
162     swiParams.arg0 = (UArg)obj;
163     Swi_construct(Swi_struct(swiHandle),
164                  (Swi_FuncPtr)TransportShmCirc_swiFxn,
165                  &swiParams, eb);
167     /* register the event with Notify */
168     status = Notify_registerEventSingle(
169                  remoteProcId,    /* remoteProcId */
170                  0,               /* lineId */
171                  TransportShmCirc_notifyEventId,
172                  (Notify_FnNotifyCbck)TransportShmCirc_notifyFxn,
173                  (UArg)swiHandle);
175     if (status < 0) {
176         Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
177         return (1);
178     }
180     /* Register the transport with MessageQ */
181     flag = ti_sdo_ipc_MessageQ_registerTransport(
182         TransportShmCirc_Handle_upCast(obj), remoteProcId, params->priority);
184     if (flag == FALSE) {
185         Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
186         return (2);
187     }
189     /* init the putWrite and putRead Index to 0 */
190     obj->putWriteIndex[0] = 0;
191     obj->putReadIndex[0] = 0;
193     /* cache wb the putWrite/Read Index but no need to inv them */
194     if (obj->cacheEnabled) {
195         Cache_wb(obj->putWriteIndex,
196                  sizeof(Bits32),
197                  Cache_Type_ALL, TRUE);
199         Cache_wb(obj->putReadIndex,
200                  sizeof(Bits32),
201                  Cache_Type_ALL, TRUE);
202     }
204     return (0);
207 /*
208  *  ======== TransportShmCirc_Instance_finalize ========
209  */
210 Void TransportShmCirc_Instance_finalize(TransportShmCirc_Object *obj, Int status)
212     switch(status) {
213         case 0: /* MessageQ_registerTransport succeeded */
214             ti_sdo_ipc_MessageQ_unregisterTransport(obj->remoteProcId,
215                 obj->priority);
217             /* fall thru OK */
218         case 1: /* Notify_registerEventSingle failed */
219         case 2: /* MessageQ_registerTransport failed */
220             Notify_unregisterEventSingle(
221                 obj->remoteProcId,
222                 0,
223                 TransportShmCirc_notifyEventId);
224             break;
225     }
228 /*
229  *  ======== TransportShmCirc_put ========
230  */
231 Bool TransportShmCirc_put(TransportShmCirc_Object *obj, Ptr msg)
233     Int status;
234     UInt hwiKey;
235     SharedRegion_SRPtr msgSRPtr;
236     UInt32 *eventEntry;
237     UInt32 writeIndex, readIndex;
238     Bool loop       = FALSE;
239     UInt16 regionId = SharedRegion_INVALIDREGIONID;
241     /*
242      *  If translation is disabled and we always have to write back the
243      *  message then we can avoid calling SharedRegion_getId(). The wait
244      *  flag is "FALSE" here because we do other cache calls below.
245      */
246     if (ti_sdo_ipc_SharedRegion_translate ||
247         !TransportShmCirc_alwaysWriteBackMsg ) {
248         regionId = SharedRegion_getId(msg);
249         if (SharedRegion_isCacheEnabled(regionId)) {
250             Cache_wbInv(msg, ((MessageQ_Msg)(msg))->msgSize, Cache_Type_ALL,
251                         FALSE);
252         }
253     }
254     else {
255         Cache_wbInv(msg, ((MessageQ_Msg)(msg))->msgSize, Cache_Type_ALL, FALSE);
256     }
258     /*
259      *  Get the msg's SRPtr.  OK if (regionId == SharedRegion_INVALIDID &&
260      *  SharedRegion_translate == FALSE)
261      */
262     msgSRPtr = SharedRegion_getSRPtr(msg, regionId);
264     /*
265      *  Retrieve the get Index. No need to cache inv the
266      *  readIndex until the writeIndex wraps. Only need to invalidate
267      *  once every N times [N = number of messages].
268      */
269     readIndex = obj->putReadIndex[0];
271     do {
272         /* disable interrupts */
273         hwiKey = Hwi_disable();
275         /* retrieve the put index */
276         writeIndex = obj->putWriteIndex[0];
278         /* if slot available 'break' out of loop */
279         if (((writeIndex + 1) & TransportShmCirc_maxIndex) != readIndex) {
280             break;
281         }
283         /* restore interrupts */
284         Hwi_restore(hwiKey);
286         /* check to make sure code has looped */
287         if (loop) {
288             /* if no slot available */
289             return (FALSE);
290         }
292         /* cache invalidate the putReadIndex */
293         if (obj->cacheEnabled) {
294             Cache_inv(obj->putReadIndex,
295                       sizeof(Bits32),
296                       Cache_Type_ALL,
297                       TRUE);
298         }
300         /* re-read the putReadIndex */
301         readIndex = obj->putReadIndex[0];
303         /* convey that the code has looped around */
304         loop = TRUE;
305     } while (1);
307     /* interrupts are disabled at this point */
309     /* calculate the next available entry */
310     eventEntry = (UInt32 *)(
311         (UInt32)obj->putBuffer + (writeIndex * sizeof(Ptr)));
313     /* Set the eventId field and payload for the entry */
314     eventEntry[0] = msgSRPtr;
316     /*
317      *  Writeback the event entry. No need to invalidate since
318      *  only one processor ever writes here. No need to wait for
319      *  cache operation since another cache operation is done below.
320      */
321     if (obj->cacheEnabled) {
322         Cache_wb(eventEntry,
323                  sizeof(Ptr),
324                  Cache_Type_ALL,
325                  FALSE);
326     }
328     /* update the putWriteIndex */
329     obj->putWriteIndex[0] = (writeIndex + 1) & TransportShmCirc_maxIndex;
331     /* restore interrupts */
332     Hwi_restore(hwiKey);
334     /*
335      *  Writeback the putWriteIndex.
336      *  No need to invalidate since only one processor
337      *  ever writes here.
338      */
339     if (obj->cacheEnabled) {
340         Cache_wb(obj->putWriteIndex,
341                  sizeof(Bits32),
342                  Cache_Type_ALL,
343                  TRUE);
344     }
346     /* Notify the remote processor */
347     status = Notify_sendEvent(
348                  obj->remoteProcId,
349                  0,
350                  TransportShmCirc_notifyEventId,
351                  0,
352                  FALSE);
354     if (status < 0) {
355         return (FALSE);
356     }
358     return (TRUE);
361 /*
362  *  ======== TransportShmCirc_control ========
363  */
364 Bool TransportShmCirc_control(TransportShmCirc_Object *obj, UInt cmd,
365     UArg cmdArg)
367     return (FALSE);
370 /*
371  *  ======== TransportShmCirc_getStatus ========
372  */
373 Int TransportShmCirc_getStatus(TransportShmCirc_Object *obj)
375     return (0);
378 /*
379  *************************************************************************
380  *                       Module functions
381  *************************************************************************
382  */
384 /*
385  *  ======== TransportShm_notifyFxn ========
386  */
387 Void TransportShmCirc_notifyFxn(UInt16 procId,
388                                 UInt16 lineId,
389                                 UInt32 eventId,
390                                 UArg arg,
391                                 UInt32 payload)
393     Swi_Handle swiHandle;
395     /* Swi_Handle was passed as arg in register */
396     swiHandle = (Swi_Handle)arg;
398     /* post the Swi */
399     Swi_post(swiHandle);
402 /*
403  *  ======== TransportShmCirc_swiFxn ========
404  */
405 Void TransportShmCirc_swiFxn(UArg arg)
407     TransportShmCirc_Object *obj;
408     UInt32 *eventEntry;
409     UInt32 queueId;
410     MessageQ_Msg msg;
411     UInt32 writeIndex, readIndex;
413     obj = (TransportShmCirc_Object *)arg;
415     /* Make sure the TransportShmCirc_Object is not NULL */
416     Assert_isTrue(obj != NULL, ti_sdo_ipc_Ipc_A_internal);
418     /*
419      *  Invalidate both getBuffer and getWriteIndex from cache.
420      */
421     if (obj->cacheEnabled) {
422         Cache_inv(obj->getBuffer,
423                   obj->opCacheSize,
424                   Cache_Type_ALL,
425                   TRUE);
426     }
428     /* get the writeIndex and readIndex */
429     writeIndex = obj->getWriteIndex[0];
430     readIndex = obj->getReadIndex[0];
432     /* get the next entry to be processed */
433     eventEntry = (UInt32 *)&(obj->getBuffer[readIndex]);
435     while (writeIndex != readIndex) {
436         /* get the msg (convert SRPtr to Ptr) */
437         msg = SharedRegion_getPtr((SharedRegion_SRPtr)eventEntry[0]);
439         /* get the queue id */
440         queueId = MessageQ_getDstQueue(msg);
442         /* put message on local queue */
443         MessageQ_put(queueId, msg);
445         /* update the local readIndex. */
446         readIndex = ((readIndex + 1) & TransportShmCirc_maxIndex);
448         /* set the getReadIndex */
449         obj->getReadIndex[0] = readIndex;
451         /*
452          *  Write back the getReadIndex once every N / 4 messages.
453          *  No need to invalidate since only one processor ever
454          *  writes this . No need to wait for operation to complete
455          *  since remote core updates its readIndex at least once
456          *  every N messages and the remote core will not use a slot
457          *  until it sees that the event has been processed with this
458          *  cache wb. Chances are small that the remote core needs
459          *  to spin due to this since we are doing a wb N / 4.
460          */
461         if ((obj->cacheEnabled) &&
462             ((readIndex % TransportShmCirc_modIndex) == 0)) {
463             Cache_wb(obj->getReadIndex,
464                      sizeof(Bits32),
465                      Cache_Type_ALL,
466                      FALSE);
467         }
469         /* get the next entry */
470         eventEntry = (UInt32 *)&(obj->getBuffer[readIndex]);
471     }
474 /*
475  *  ======== TransportShmCirc_sharedMemReq ========
476  */
477 SizeT TransportShmCirc_sharedMemReq(const TransportShmCirc_Params *params)
479     UInt16 regionId;
480     SizeT minAlign, memReq;
482     /* Ensure that params is non-NULL */
483     Assert_isTrue(params != NULL, ti_sdo_ipc_Ipc_A_internal);
485     regionId = SharedRegion_getId(params->sharedAddr);
487     minAlign = Memory_getMaxDefaultTypeAlign();
488     if (SharedRegion_getCacheLineSize(regionId) > minAlign) {
489         minAlign = SharedRegion_getCacheLineSize(regionId);
490     }
492     /*
493      *  Amount of shared memory:
494      *  1 putBuffer with numMsgs (rounded to CLS) +
495      *  1 putWriteIndex ptr (rounded to CLS) +
496      *  1 putReadIndex put (rounded to CLS) +
497      *  1 getBuffer with numMsgs (rounded to CLS) +
498      *  1 getWriteIndex ptr (rounded to CLS) +
499      *  1 getReadIndex put (rounded to CLS) +
500      *
501      *  For CLS of 128b it is:
502      *      128b + 128b + 128b + 128b+ 128b + 128b = 768b
503      *
504      *  Note: CLS means Cache Line Size
505      */
506     memReq = 2 * (
507         (_Ipc_roundup(sizeof(Ptr) * TransportShmCirc_numMsgs, minAlign)) +
508         ( 2 * _Ipc_roundup(sizeof(Bits32), minAlign)));
510     return (memReq);
513 /*
514  *  ======== TransportShmCirc_setErrFxn ========
515  */
516 Void TransportShmCirc_setErrFxn(TransportShmCirc_ErrFxn errFxn)
518     /* Ignore the errFxn */