]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blob - src/rm_transport.c
a0c627409eaaf7a1543c50a852cfcf5d32fe45fb
[keystone-rtos/rm-lld.git] / src / rm_transport.c
1 /**\r
2  *   @file  rm_transport.c\r
3  *\r
4  *   @brief   \r
5  *      This is the Resource Manager transport source.\r
6  *\r
7  *  \par\r
8  *  ============================================================================\r
9  *  @n   (C) Copyright 2012-2013, Texas Instruments, Inc.\r
10  * \r
11  *  Redistribution and use in source and binary forms, with or without \r
12  *  modification, are permitted provided that the following conditions \r
13  *  are met:\r
14  *\r
15  *    Redistributions of source code must retain the above copyright \r
16  *    notice, this list of conditions and the following disclaimer.\r
17  *\r
18  *    Redistributions in binary form must reproduce the above copyright\r
19  *    notice, this list of conditions and the following disclaimer in the \r
20  *    documentation and/or other materials provided with the   \r
21  *    distribution.\r
22  *\r
23  *    Neither the name of Texas Instruments Incorporated nor the names of\r
24  *    its contributors may be used to endorse or promote products derived\r
25  *    from this software without specific prior written permission.\r
26  *\r
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \r
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT \r
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \r
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \r
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
38  *\r
39  *  \par\r
40 */\r
41 \r
42 /* Standard includes */\r
43 #include <string.h>\r
44 \r
45 /* RM external includes */\r
46 #include <ti/drv/rm/rm.h>\r
47 #include <ti/drv/rm/rm_transport.h>\r
48 \r
49 /* RM internal includes */\r
50 #include <ti/drv/rm/include/rm_loc.h>\r
51 #include <ti/drv/rm/include/rm_transportloc.h>\r
52 \r
53 /* RM OSAL layer */\r
54 #include <rm_osal.h>\r
55 \r
56 /**********************************************************************\r
57  ************************ Local Functions *****************************\r
58  **********************************************************************/\r
59 \r
60 /* FUNCTION PURPOSE: Adds a transport\r
61  ***********************************************************************\r
62  * DESCRIPTION: Returns a pointer to a transport structure that\r
63  *              was created, initialized, and added to the \r
64  *              instance transport list.\r
65  */\r
66 static Rm_Transport *transportAdd(const Rm_TransportCfg *transportCfg)\r
67 {\r
68     Rm_Inst      *rmInst = (Rm_Inst *) transportCfg->rmHandle;\r
69     Rm_Transport *transports = rmInst->transports;\r
70     Rm_Transport *newTransport = NULL;\r
71 \r
72     newTransport = Rm_osalMalloc (sizeof(Rm_Transport));\r
73     memset((void *)newTransport, 0, sizeof(Rm_Transport));\r
74 \r
75     if (newTransport) {\r
76         newTransport->rmHandle = transportCfg->rmHandle;\r
77         newTransport->appTransportHandle = transportCfg->appTransportHandle;\r
78         newTransport->remoteInstType = transportCfg->remoteInstType;\r
79         strncpy(newTransport->remoteInstName, transportCfg->remoteInstName, RM_NAME_MAX_CHARS);\r
80         newTransport->callouts.rmAllocPkt = transportCfg->transportCallouts.rmAllocPkt;\r
81         newTransport->callouts.rmSendPkt = transportCfg->transportCallouts.rmSendPkt;\r
82         newTransport->nextTransport = NULL;\r
83 \r
84         if (transports) {\r
85             while (transports->nextTransport) {\r
86                 transports = transports->nextTransport;\r
87             }\r
88             transports->nextTransport = newTransport;\r
89         }\r
90         else {\r
91             rmInst->transports = newTransport;\r
92         }\r
93     }\r
94     return (newTransport);\r
95 }\r
96 \r
97 /* FUNCTION PURPOSE: Tests if a transport is registered to an instance\r
98  ***********************************************************************\r
99  * DESCRIPTION: Returns TRUE if the supplied transport is found in\r
100  *              the instance transport list.  Otherwise, returns FALSE\r
101  */\r
102 static int transportIsRegistered(Rm_Handle rmHandle, Rm_Transport *transport)\r
103 {\r
104     Rm_Inst      *rmInst = (Rm_Inst *)rmHandle;\r
105     Rm_Transport *transportList = (Rm_Transport *)rmInst->transports;\r
106     \r
107     while (transportList) {\r
108         if (transportList == transport) {\r
109             return(RM_TRUE);             \r
110         }\r
111         transportList = transportList->nextTransport;\r
112     }\r
113     return (RM_FALSE);\r
114 }\r
115 \r
116 /* FUNCTION PURPOSE: Deletes a transport\r
117  ***********************************************************************\r
118  * DESCRIPTION: Removes a transport from an instance transport list\r
119  *              and then frees the memory associated with the transport\r
120  *              data structure\r
121  */\r
122 static void transportDelete(Rm_Transport *transport)\r
123 {\r
124     Rm_Inst      *rmInst = (Rm_Inst *)transport->rmHandle;\r
125     Rm_Transport *transportList = (Rm_Transport *)rmInst->transports;\r
126     Rm_Transport *prevTransport = NULL;\r
127 \r
128     /* Get previous transport in list */\r
129     while (transportList) {\r
130         if (transportList == transport) {\r
131             break;             \r
132         }\r
133         prevTransport = transportList;\r
134         transportList = transportList->nextTransport;\r
135     }\r
136 \r
137     if (prevTransport == NULL) {\r
138          rmInst->transports = transport->nextTransport;\r
139     }\r
140     else {\r
141          prevTransport->nextTransport = transport->nextTransport;\r
142     }\r
143     Rm_osalFree((void *)transport, sizeof(Rm_Transport));\r
144 }\r
145 \r
146 /**********************************************************************\r
147  ********************** Internal Functions ****************************\r
148  **********************************************************************/\r
149 \r
150 /* FUNCTION PURPOSE: Finds a transport based on remote inst name\r
151  ***********************************************************************\r
152  * DESCRIPTION: Returns a pointer to the transport within an instance's\r
153  *              transport list that matches the provided remote\r
154  *              instance name.  NULL is returned if no transports in \r
155  *              the list match the remote instance name.\r
156  */\r
157 Rm_Transport *rmTransportFindRemoteName(Rm_Transport *transports, char *remoteName)\r
158 {\r
159     while (transports) {\r
160         if (strncmp(transports->remoteInstName, remoteName, RM_NAME_MAX_CHARS) == 0) {\r
161             break;             \r
162         }\r
163         transports = transports->nextTransport;\r
164     }\r
165     return (transports);\r
166 }\r
167 \r
168 /* FUNCTION PURPOSE: Finds a transport based on remote inst type\r
169  ***********************************************************************\r
170  * DESCRIPTION: Returns a pointer to the transport within an instance's\r
171  *              transport list that matches the provided remote\r
172  *              instance type.  NULL is returned if no transports in \r
173  *              the list match the remote instance type.\r
174  */\r
175 Rm_Transport *rmTransportFindRemoteInstType(Rm_Transport *transports, Rm_InstType remoteInstType)\r
176 {\r
177     while (transports) {\r
178         if (transports->remoteInstType == remoteInstType) {\r
179             break;             \r
180         }\r
181         transports = transports->nextTransport;\r
182     }\r
183     return (transports);\r
184 }\r
185 \r
186 /**********************************************************************\r
187  ********************* Application visible APIs ***********************\r
188  **********************************************************************/\r
189 \r
190 /* FUNCTION PURPOSE: Registers an app transport with a RM instance\r
191  ***********************************************************************\r
192  * DESCRIPTION: Returns a transport handle to the application that\r
193  *              has been registered with an RM instance.  The handle\r
194  *              is used by the application to route packets to the\r
195  *              proper RM instance's based on the application\r
196  *              transport receive code.  The handle is also used\r
197  *              internally by RM to route request and response \r
198  *              packets to the correct application transports. NULL\r
199  *              is returned for the transport handle if any errors\r
200  *              are encountered.\r
201  */\r
202 Rm_TransportHandle Rm_transportRegister (const Rm_TransportCfg *transportCfg, int32_t *result)\r
203 {\r
204     Rm_Inst      *rmInst = (Rm_Inst *) transportCfg->rmHandle;\r
205     Rm_Transport *transport = NULL;\r
206     void         *key;\r
207 \r
208     *result = RM_OK;\r
209 \r
210     RM_SS_INST_INV_ENTER_CS(key);\r
211 \r
212     /* Shared servers and clients cannot connect to anyone */\r
213     if ((rmInst->instType == Rm_instType_SHARED_SERVER) ||\r
214         (rmInst->instType == Rm_instType_SHARED_CLIENT)){\r
215         *result = RM_ERROR_SHARED_INSTANCE_CANNOT_REG_TRANS;\r
216         goto errorExit;\r
217     }\r
218 \r
219     /* No one can connect to a shared server\r
220      * RM Servers cannot connect to other Servers.  \r
221      * RM Client Delegates cannot connect to other Client Delegates.\r
222      * RM Clients cannot connect to other Clients */\r
223     if ((transportCfg->remoteInstType == Rm_instType_SHARED_SERVER) ||\r
224         ((rmInst->instType == Rm_instType_SERVER) &&\r
225          (transportCfg->remoteInstType == Rm_instType_SERVER)) ||\r
226         ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
227          (transportCfg->remoteInstType == Rm_instType_CLIENT_DELEGATE)) ||\r
228         ((rmInst->instType == Rm_instType_CLIENT) &&\r
229          (transportCfg->remoteInstType == Rm_instType_CLIENT))) {\r
230         *result = RM_ERROR_INVALID_REMOTE_INST_TYPE;\r
231         goto errorExit;\r
232     }\r
233 \r
234     /* Verify Clients are not registering with more than one Client Delegate or Server. And\r
235      * that Client Delegate is not registering with more than one Server. */\r
236     if (rmInst->registeredWithDelegateOrServer &&\r
237         (((rmInst->instType == Rm_instType_CLIENT) &&\r
238           (transportCfg->remoteInstType == Rm_instType_CLIENT_DELEGATE)) || \r
239          ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
240           (transportCfg->remoteInstType == Rm_instType_SERVER)))) {\r
241         *result = RM_ERROR_ALREADY_REGD_SERVER_OR_CD;\r
242         goto errorExit;\r
243     }         \r
244     \r
245     if (!transportCfg->transportCallouts.rmAllocPkt) {\r
246         *result = RM_ERROR_TRANSPORT_ALLOC_PKT_NOT_REGD;\r
247         goto errorExit;\r
248     }\r
249     else if (!transportCfg->transportCallouts.rmSendPkt) {\r
250         *result = RM_ERROR_TRANSPORT_SEND_NOT_REGD;\r
251         goto errorExit;\r
252     }\r
253 \r
254     transport = transportAdd(transportCfg);\r
255     if ((transport->remoteInstType == Rm_instType_CLIENT_DELEGATE) ||\r
256         (transport->remoteInstType == Rm_instType_SERVER)) {\r
257         rmInst->registeredWithDelegateOrServer = RM_TRUE;\r
258     }\r
259 errorExit:\r
260     RM_SS_INST_WB_EXIT_CS(key);    \r
261     return ((Rm_TransportHandle) transport);\r
262 }\r
263 \r
264 /* FUNCTION PURPOSE: Unregisters an app transport from a RM instance\r
265  ***********************************************************************\r
266  * DESCRIPTION: Deletes a registered transport from the transport\r
267  *              list and cleans up the memory associated with the\r
268  *              transport data structure.\r
269  */\r
270 int32_t Rm_transportUnregister(Rm_TransportHandle transportHandle)\r
271 {\r
272     Rm_Transport *transport = (Rm_Transport *)transportHandle;\r
273     Rm_Inst      *rmInst = (Rm_Inst *)transport->rmHandle;\r
274     int32_t       retVal = RM_OK;\r
275 \r
276     if (transportIsRegistered(transport->rmHandle, transport)) {\r
277         if ((transport->remoteInstType == Rm_instType_CLIENT_DELEGATE) ||\r
278             (transport->remoteInstType == Rm_instType_SERVER)) {\r
279             rmInst->registeredWithDelegateOrServer = RM_FALSE;\r
280         }\r
281         transportDelete(transport);\r
282     }\r
283     else {\r
284         retVal = RM_ERROR_TRANSPORT_HANDLE_DOES_NOT_EXIST;\r
285     }\r
286     return (retVal);\r
287 }\r
288 \r
289 /* FUNCTION PURPOSE: Receives RM packets\r
290  ***********************************************************************\r
291  * DESCRIPTION: The application provides RM packets received on the\r
292  *              application transports to RM via this API.  Function\r
293  *              can be called from polling or ISR contexts.  Assume \r
294  *              invoking application will free packet after this\r
295  *              function returns.\r
296  */\r
297 int32_t Rm_receivePacket(Rm_TransportHandle transportHandle, const Rm_Packet *pkt)\r
298 {\r\r\r
299     Rm_Transport   *transport = (Rm_Transport *)transportHandle;\r
300     Rm_Inst        *rmInst = (Rm_Inst *)transport->rmHandle;\r
301     Rm_Transaction *transaction;\r
302     int32_t         retVal = RM_OK;\r
303 \r
304     if (!transportIsRegistered(transport->rmHandle, transport)) {\r
305         retVal = RM_ERROR_TRANSPORT_HANDLE_DOES_NOT_EXIST;\r
306         goto errorExit;\r
307     }\r
308 \r
309     switch (pkt->pktType) {\r
310         case Rm_pktType_RESOURCE_REQUEST:\r
311         {\r
312             Rm_ResourceRequestPkt *resourceReqPkt = (Rm_ResourceRequestPkt *)pkt->data;\r
313 \r
314             transaction = rmTransactionQueueAdd(rmInst);\r
315             transaction->remoteOriginatingId = resourceReqPkt->requestId;\r
316             if (resourceReqPkt->resourceReqType == Rm_resReqPktType_ALLOCATE_INIT) {\r
317                 transaction->type = Rm_service_RESOURCE_ALLOCATE_INIT;\r
318             }\r
319             else if (resourceReqPkt->resourceReqType == Rm_resReqPktType_ALLOCATE_USE) {\r
320                 transaction->type = Rm_service_RESOURCE_ALLOCATE_USE;\r
321             }            \r
322             else if (resourceReqPkt->resourceReqType == Rm_resReqPktType_FREE) {\r
323                 transaction->type = Rm_service_RESOURCE_FREE;\r
324             }\r
325             else if (resourceReqPkt->resourceReqType == Rm_resReqPktType_GET_NAMED) {\r
326                 transaction->type = Rm_service_RESOURCE_GET_BY_NAME;\r
327             }            \r
328             strncpy(transaction->pktSrcInstName, resourceReqPkt->pktSrcInstName, RM_NAME_MAX_CHARS);\r
329             strncpy(transaction->serviceSrcInstName, resourceReqPkt->serviceSrcInstName, RM_NAME_MAX_CHARS);\r
330             transaction->state = RM_SERVICE_PROCESSING;\r
331             memcpy ((void *)&(transaction->resourceInfo), (void *)&(resourceReqPkt->resourceInfo),\r
332                     sizeof(Rm_ResourceInfo));\r
333             break;\r
334         }\r
335         case Rm_pktType_RESOURCE_RESPONSE:\r
336         {\r
337             Rm_ResourceResponsePkt *resourceRespPkt = (Rm_ResourceResponsePkt *)pkt->data;\r
338 \r
339             if (transaction = rmTransactionQueueFind(rmInst,resourceRespPkt->responseId)) {\r
340                 if ((transaction->state == RM_SERVICE_APPROVED_STATIC) &&\r
341                     (resourceRespPkt->requestState != RM_SERVICE_APPROVED)) {\r
342                     /* Lock the RM instance since service validated against static policy failed against \r
343                      * Server's global policy */\r
344                     rmInst->isLocked = RM_TRUE;\r
345                 }\r
346                 transaction->state = resourceRespPkt->requestState;\r
347 \r
348                 if ((transaction->state == RM_SERVICE_APPROVED) &&\r
349                     ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||\r
350                      (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) ||\r
351                      (transaction->type == Rm_service_RESOURCE_GET_BY_NAME))) {\r
352                     memcpy ((void *)&(transaction->resourceInfo), (void *)&(resourceRespPkt->resourceInfo),\r
353                             sizeof(Rm_ResourceInfo));\r
354                 }\r
355                 else {\r
356                     /* Always copy owner count */\r
357                     transaction->resourceInfo.ownerCount = resourceRespPkt->resourceInfo.ownerCount;\r
358                 }\r
359             }\r
360             else {\r
361                 retVal = RM_ERROR_PKT_RESP_DOES_NOT_MATCH_ANY_REQ;\r
362                 goto errorExit;\r
363             }\r
364             break;\r
365         }\r
366         case Rm_pktType_NAMESERVER_REQUEST:\r
367         {\r
368             Rm_NsRequestPkt *nsRequestPkt = (Rm_NsRequestPkt *)pkt->data;\r
369 \r
370             transaction = rmTransactionQueueAdd(rmInst);\r
371             transaction->remoteOriginatingId = nsRequestPkt->requestId;\r
372 \r
373             if (nsRequestPkt->nsRequestType == Rm_nsReqPktType_MAP_RESOURCE) {\r
374                 transaction->type = Rm_service_RESOURCE_MAP_TO_NAME;\r
375             }\r
376             else if (nsRequestPkt->nsRequestType == Rm_nsReqPktType_UNMAP_RESOURCE) {\r
377                 transaction->type = Rm_service_RESOURCE_UNMAP_NAME;\r
378             }\r
379 \r
380             strncpy(transaction->pktSrcInstName, nsRequestPkt->pktSrcInstName, RM_NAME_MAX_CHARS);\r
381             strncpy(transaction->serviceSrcInstName, nsRequestPkt->serviceSrcInstName, RM_NAME_MAX_CHARS);\r
382             transaction->state = RM_SERVICE_PROCESSING;\r
383             memcpy ((void *)&(transaction->resourceInfo), (void *)&(nsRequestPkt->resourceInfo),\r
384                     sizeof(Rm_ResourceInfo));           \r
385             break;\r
386         }\r
387         case Rm_pktType_NAMESERVER_RESPONSE:\r
388         {\r
389             Rm_NsResponsePkt *nsResponsePkt = (Rm_NsResponsePkt *)pkt->data;\r
390 \r
391             if (transaction = rmTransactionQueueFind(rmInst, nsResponsePkt->responseId)) {\r
392                 if ((transaction->state == RM_SERVICE_APPROVED_STATIC) &&\r
393                     (nsResponsePkt->requestState != RM_SERVICE_APPROVED)) {\r
394                     /* Lock the RM instance since service validated against static policy failed against \r
395                      * Server's global policy */                    \r
396                     rmInst->isLocked = RM_TRUE;\r
397                 }                \r
398                 transaction->state = nsResponsePkt->requestState;            \r
399             }\r
400             else {\r
401                 retVal = RM_ERROR_PKT_RESP_DOES_NOT_MATCH_ANY_REQ;\r
402                 goto errorExit;\r
403             }\r
404             break;\r
405         }\r
406         default:\r
407             retVal = RM_ERROR_RECEIVED_INVALID_PACKET_TYPE;\r
408             goto errorExit;\r
409     }\r
410 \r
411     /* Process received transaction */\r
412     rmProcessRouter(rmInst, transaction);   \r
413 errorExit:\r
414     return(retVal);\r
415 }\r
416 \r