e546fc3f09be869737c996a1d0028a1394c1085e
[keystone-rtos/rm-lld.git] / src / rm.c
1 /**\r
2  *   @file  rm.c\r
3  *\r
4  *   @brief   \r
5  *      This is the Resource Manager source.\r
6  *\r
7  *  \par\r
8  *  ============================================================================\r
9  *  @n   (C) Copyright 2012, 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 /* RM Types */\r
43 #include <ti/drv/rm/rm_types.h>\r
44 \r
45 /* RM external includes */\r
46 #include <ti/drv/rm/rm.h>\r
47 #include <ti/drv/rm/rmservices.h>\r
48 #include <ti/drv/rm/rmtransport.h>\r
49 #include <ti/drv/rm/rmpolicy.h>\r
50 \r
51 /* RM internal includes */\r
52 #include <ti/drv/rm/include/rmloc.h>\r
53 \r
54 /* RM OSAL layer */\r
55 #include <rm_osal.h>\r
56 \r
57 /**********************************************************************\r
58  ************************** Globals ***********************************\r
59  **********************************************************************/\r
60 \r
61 /* Place QMSS PDSP permissions array */\r
62 #pragma DATA_SECTION (rmQmssPdspFirmwarePerms, ".rm");\r
63 #pragma DATA_ALIGN (rmQmssPdspFirmwarePerms, 128)\r
64 Rm_Perms rmQmssPdspFirmwarePerms[RM_ALIGN_PERMISSIONS_ARRAY(RM_QMSS_FIRMWARE_PDSPS, Rm_Perms)];\r
65 \r
66 \r
67 /** @brief Global Variable which describes the RM Version Information */\r
68 const char   rmVersionStr[] = RM_VERSION_STR ":" __DATE__  ":" __TIME__;\r
69 \r
70 /**********************************************************************\r
71  ********************** Internal Functions ****************************\r
72  **********************************************************************/\r
73 \r
74 /* At the very least the transaction ID needs to be provided to create a transaction */\r
75 Rm_Transaction *Rm_transactionQueueAdd(Rm_Inst *rmInst, uint32_t transactionId)\r
76 {\r
77     Rm_Transaction *transactionQueue = (Rm_Transaction *)rmInst->transactionQueue;\r
78     Rm_Transaction *newTransaction = NULL;\r
79     void *key;\r
80 \r
81     /* Lock access to the RM instance's transaction queue */\r
82     key = Rm_osalLocalCsEnter();\r
83 \r
84     /* Get memory for a new transaction from local memory */\r
85     newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction), false);\r
86 \r
87     /* Return if the memory allocated for the transaction entry is NULL */\r
88     if (newTransaction == NULL)\r
89     {\r
90         Rm_osalLocalCsExit(key);\r
91         return(newTransaction);\r
92     }\r
93 \r
94     /* Clear the transaction */\r
95     memset((void *)newTransaction, 0, sizeof(Rm_Transaction));\r
96 \r
97     /* Populate transaction with the provided ID */\r
98     newTransaction->id = transactionId;\r
99     /* New transaction's nextTransaction pointer will always be NULL */\r
100     newTransaction->nextTransaction = NULL;  \r
101 \r
102     /* Check if there are any transactions in the transaction queue */\r
103     if (transactionQueue)\r
104     {\r
105         /* At least one transaction in the transaction queue.  Add the new entry to the \r
106          * end of the transaction queue */\r
107         while (transactionQueue->nextTransaction != NULL)\r
108         {\r
109             /* Traverse the list until arriving at the last transaction */\r
110             transactionQueue = transactionQueue->nextTransaction;\r
111         }\r
112 \r
113         /* Add the new transaction to the end of the queue */\r
114         transactionQueue->nextTransaction = newTransaction;\r
115     }\r
116     else\r
117     {\r
118         /* The transaction queue does not currently exist.  The new transaction is the \r
119          * first transaction */\r
120         rmInst->transactionQueue = newTransaction;\r
121     }\r
122 \r
123     Rm_osalLocalCsExit(key);\r
124     return (newTransaction);\r
125 }\r
126 \r
127 Rm_Transaction *Rm_transactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)\r
128 {\r
129     Rm_Transaction *transaction = (Rm_Transaction *)rmInst->transactionQueue;\r
130     void *key;\r
131 \r
132     /* Make sure there is at least one transaction in the transaction queue */\r
133     if (transaction != NULL)\r
134     {\r
135         /* Find the transaction ID within the specified RM instance's transaction queue.\r
136          * If the end of the transaction queue is reached without finding the transaction the \r
137          * transaction pointer will be NULL */\r
138         while (transaction != NULL)\r
139         {\r
140             if (transaction->transactionId == transactionId)\r
141             {\r
142                 /* Match: break out of loop and return the transaction */\r
143                 break;             \r
144             }\r
145             transaction = transaction->nextTransaction;\r
146         }\r
147     }\r
148 \r
149     return (transaction);\r
150 }\r
151 \r
152 int32_t Rm_transactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)\r
153 {\r
154     Rm_Transaction *transaction = (Rm_Transaction *) rmInst->transactionQueue;\r
155     Rm_Transaction *prevTransaction = NULL;\r
156     void *key;\r
157 \r
158     /* Lock access to the RM instance's transaction queue */\r
159     key = Rm_osalLocalCsEnter();\r
160 \r
161     /* Make sure there is at least one entry in the transaction queue */\r
162     if (transaction == NULL)\r
163     {\r
164         Rm_osalLocalCsExit(key);\r
165         return (RM_SERVICE_ERROR_NO_TRANSACTIONS_IN_QUEUE);\r
166     }\r
167 \r
168     /* Find the transaction ID within the specified RM instance's transaction queue. */\r
169     while (transaction != NULL)\r
170     {\r
171         if (transaction->transactionId == transactionId)\r
172         {\r
173             /* Match: break out of loop and delete the transaction */\r
174             break;             \r
175         }\r
176 \r
177         prevTransaction = transaction;\r
178         transaction = transaction->nextEntry;\r
179     }\r
180 \r
181     /* Traversed entire queue but did not find transaction */\r
182     if (transaction == NULL)\r
183     {\r
184         Rm_osalLocalCsExit(key);\r
185         return (RM_SERVICE_ERROR_SERVICE_TRANSACTION_DOES_NOT_EXIST);\r
186     }\r
187     else\r
188     {\r
189         /* Delete the transaction */\r
190         if ((prevTransaction == NULL) && transaction->nextTransaction)\r
191         {\r
192             /* Transaction to be deleted exists at start of transaction queue.  Map second\r
193              * transaction to be start of transaction queue as long as there are more than\r
194              * one transactions */\r
195             rmInst->transactionQueue = transaction->nextTransaction;\r
196         }\r
197         else\r
198         {\r
199             /* Transaction to be deleted is in the middle or at end of the queue.  Adjust \r
200              * adjacent transaction pointers.  This covers the case where the transaction to be \r
201              * removed is at the end of the queue. */\r
202             prevTransaction->nextTransaction = transaction->nextTransaction;\r
203         }\r
204 \r
205         /* Free the memory associated with the transaction. */\r
206         Rm_osalFree((void *)transaction, sizeof(Rm_Transaction), false);\r
207     }\r
208 \r
209     Rm_osalLocalCsExit(key);\r
210     return (RM_SERVICE_ACTION_OKAY);\r
211 }\r
212 \r
213 /* Function used to send RM response transactions to lower level agents */\r
214 void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
215                               Rm_TransactionReceipt *receipt)\r
216 {\r
217     Rm_TransportNode *dstTransportNode = NULL;\r
218     Rm_Packet *rmPkt = NULL;\r
219 \r
220     /* Find the transport for the RM instance that sent the request. */\r
221     dstTransportNode = Rm_transportNodeFindRemoteName(rmInst, transaction->sourceInstName);\r
222 \r
223     /* Create a RM packet using the service information */\r
224     switch (transaction->type)\r
225     {\r
226         case Rm_service_RESOURCE_ALLOCATE:\r
227         case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
228         case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
229         case Rm_service_RESOURCE_FREE:\r
230         case Rm_service_RESOURCE_BLOCK_FREE:\r
231         case Rm_service_RESOURCE_FREE_BY_NAME:\r
232             rmPkt = Rm_transportCreateResourceResponsePkt(rmInst, dstTransportNode, \r
233                                                           transaction, receipt);\r
234             break;\r
235         case Rm_service_RESOURCE_MAP_TO_NAME:\r
236         case Rm_service_RESOURCE_UNMAP_NAME:\r
237             rmPkt = Rm_transportCreateNsResponsePkt(rmInst, dstTransportNode,\r
238                                                     transaction, receipt);\r
239             break;\r
240         default:\r
241             /* Invalid service type.  Flag the error and return */\r
242             receipt->serviceResult = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
243             break;\r
244     }\r
245 \r
246     if (receipt->serviceResult <= RM_SERVICE_ERROR_BASE)\r
247     {\r
248         /* Delete the transaction and return immediately because an error occurred \r
249          * allocating the packet */\r
250         Rm_transactionQueueDelete(rmInst, transaction->id);\r
251         return;\r
252     }\r
253 \r
254     /* Send the RM packet to the application transport */\r
255     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt))\r
256     {\r
257         /* Non-NULL value returned by transport send.  An error occurred\r
258          * in the transport while attempting to send the packet.*/\r
259         receipt->serviceResult = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
260         /* Clean up the packet */\r
261         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
262         {\r
263             /* Non-NULL value returned by transport packet free. Flag the\r
264              * error */\r
265              receipt->serviceResult = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
266         }\r
267         return;\r
268     }\r
269 \r
270     /* Fill out the receipt information and delete the transaction */\r
271     receipt->serviceResult = transaction->details;\r
272     Rm_transactionQueueDelete(rmInst, transaction->id);\r
273 }\r
274 \r
275 /* Function used to forward RM transactions to higher level agents */\r
276 void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
277                               Rm_TransactionReceipt *receipt)\r
278 {\r
279     Rm_TransportNode *dstTransportNode = NULL;\r
280     Rm_Packet *rmPkt = NULL;\r
281 \r
282     /* Make sure the RM instance has a transport registered with a higher level agent */\r
283     if (rmInst->registeredWithDelegateOrServer == false)\r
284     {\r
285         receipt->serviceResult = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
286         return;\r
287     }\r
288 \r
289     /* Find the transport for the higher level agent.  Check for a remote Client Delegate first.\r
290      * If a connection does not exist check for a connection to a Server */\r
291     dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_CLIENT_DELEGATE);\r
292     if (dstTransportNode == NULL)\r
293     {\r
294         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
295     }\r
296 \r
297     /* Create a RM packet using the service information */\r
298     switch (transaction->type)\r
299     {\r
300         case Rm_service_RESOURCE_ALLOCATE:\r
301         case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
302         case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
303         case Rm_service_RESOURCE_FREE:\r
304         case Rm_service_RESOURCE_BLOCK_FREE:\r
305         case Rm_service_RESOURCE_FREE_BY_NAME:\r
306             rmPkt = Rm_transportCreateResourceReqPkt(rmInst, dstTransportNode, \r
307                                                      transaction, receipt);\r
308             break;\r
309         case Rm_service_RESOURCE_MAP_TO_NAME:\r
310         case Rm_service_RESOURCE_UNMAP_NAME:\r
311             rmPkt = Rm_transportCreateNsRequestPkt(rmInst, dstTransportNode,\r
312                                                    transaction, receipt);\r
313             break;\r
314         default:\r
315             /* Invalid service type.  Flag the error and return */\r
316             receipt->serviceResult = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
317             break;\r
318     }\r
319 \r
320     if (receipt->serviceResult <= RM_SERVICE_ERROR_BASE)\r
321     {\r
322         /* Return immediately because an error occurred allocating the packet */\r
323         return;\r
324     }\r
325 \r
326     /* Switch the queued transaction to the awaiting response state */\r
327     transaction->state = Rm_transactionState_AWAITING_RESPONSE;\r
328 \r
329     /* Send the RM packet to the application transport */\r
330     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt))\r
331     {\r
332         /* Non-NULL value returned by transport send.  An error occurred\r
333          * in the transport while attempting to send the packet.*/\r
334         receipt->serviceResult = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
335         /* Clean up the packet */\r
336         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
337         {\r
338             /* Non-NULL value returned by transport packet free. Flag the\r
339              * error */\r
340              receipt->serviceResult = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
341         }\r
342         return;\r
343     }\r
344 \r
345     /* Inform requesting component that the service is being forwarded to a higher lever\r
346      * RM agent for processing.  The result of the service will be provided to the \r
347      * component via the specified callback function */\r
348     receipt->serviceResult = RM_SERVICE_PROCESSING;\r
349     receipt->serviceId = transaction->id;\r
350 }\r
351 \r
352 void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction, \r
353                               Rm_TransactionReceipt *receipt)\r
354 {\r
355     Rm_Transaction *queuedTransaction = NULL;\r
356     \r
357     if (rmInst->instType == Rm_instType_CLIENT)\r
358     {\r
359         /* Check if the new transaction's ID matches any transactions waiting for\r
360          * responses.  A transaction received as a response will have an ID that \r
361          * matches the transaction that originated the request packet */\r
362         if (queuedTransaction = Rm_transactionQueueFind(rmInst, transaction->id))\r
363         {\r
364             if (queuedTransaction->state == Rm_transactionState_AWAITING_RESPONSE)\r
365             {\r
366                 /* Found a transaction awaiting a response.  Pass both transactions\r
367                  * to the service responder for response processing */\r
368                 Rm_serviceResponder(rmInst, transaction, queuedTransaction, receipt);\r
369             }\r
370             else\r
371             {\r
372                 /* Request transaction was not in the awaiting response state.  Flag the\r
373                  * error in the receipt and return */\r
374                 receipt->serviceResult = RM_SERVICE_ERROR_INVALID_REQUEST_TRANSACTION_STATE_UPON_RESPONSE;\r
375             }\r
376         }\r
377         else\r
378         {\r
379             /* This is a new transaction.  Make sure the transaction is not a \r
380              * response transaction sent to the wrong RM instance */\r
381             if ((transaction->state == Rm_transactionState_RESOURCE_APPROVED) ||\r
382                 (transaction->state == Rm_transactionState_RESOURCE_DENIED))\r
383             {\r
384                 /* No matching request transaction.  This transaction result was sent to the\r
385                  * wrong RM instance.  Flag the error in the receipt and return */\r
386                 receipt->serviceResult = RM_SERVICE_ERROR_INVALID_TRANSACTION_RECEIVED_ON_CLIENT;\r
387             }\r
388             else\r
389             {\r
390                 /* All service requests on Clients are forwarded to the higher level RM agent\r
391                  * either a Client Delegate or Server, based on the RM system architecture */\r
392                 Rm_transactionForwarder(rmInst, transaction, receipt);\r
393             }\r
394         }\r
395     }\r
396     else\r
397     {\r
398         /* Execute a command processor based on the command type */\r
399         switch (transaction->transCommand)\r
400         {\r
401             case Rm_command_ALLOCATE:\r
402             case Rm_command_BLOCK_ALLOCATE:\r
403             case Rm_command_ALLOCATE_NAMED:\r
404                 Rm_allocate(rmInst, transaction, receipt);\r
405                 break;\r
406             case Rm_command_FREE:\r
407             case Rm_command_BLOCK_FREE:\r
408             case Rm_command_FREE_NAMED:\r
409                 Rm_free(rmInst, transaction, receipt);\r
410                 break;\r
411             case Rm_command_MAP_NAME:\r
412                 Rm_nsAddObject(rmInst, transaction, receipt);\r
413                 break;\r
414             case Rm_command_UNMAP_NAME:\r
415                 Rm_nsDeleteObject(rmInst, transaction, receipt);\r
416                 break;\r
417             case Rm_command_RESOURCE_STATUS:\r
418                 Rm_getResourceStatus(rmInst, transaction, receipt);\r
419                 break;\r
420             case Rm_command_RESOURCE_RESPONSE:\r
421                 \r
422                 break;\r
423             case Rm_command_POLICY_REQUEST:\r
424                 break;\r
425             case Rm_command_POLICY_RESPONSE:\r
426                 break;\r
427         }\r
428 \r
429     }\r
430 \r
431 }\r
432 \r
433 /**********************************************************************\r
434  ********************** Application visible APIs **********************\r
435  **********************************************************************/\r
436 \r
437 Rm_Handle Rm_init(Rm_InitCfg *initCfg)\r
438 {\r
439     Rm_Inst *rmInst;\r
440 \r
441     /* Instance creation checks.  Add one to strlen calculation for null character */\r
442     if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)\r
443     {\r
444         /* Failure: Instance name is too big */\r
445         return (NULL);\r
446     }\r
447     \r
448     /* Get memory for RM instance from local memory */\r
449     rmInst = Rm_osalMalloc (sizeof(Rm_Inst), false);\r
450     /* Populate instance based on input parameters */\r
451     strcpy (&rmInst->name[0], initCfg->instName);\r
452     rmInst->instType = initCfg->instType;\r
453     rmInst->instState = RM_state_IDLE;\r
454     rmInst->registeredWithDelegateOrServer = false;\r
455     rmInst->serviceCallback = NULL;\r
456 \r
457     /* The transport APIs must be provided */\r
458     if ((initCfg->rmAllocPktFuncPtr == NULL) ||\r
459         (initCfg->rmFreePktFuncPtr == NULL) ||\r
460         (initCfg->rmSendFuncPtr == NULL) ||\r
461         (initCfg->rmReceiveFuncPtr == NULL) ||\r
462         (initCfg->rmNumPktsReceivedFuncPtr == NULL))\r
463     {\r
464         return (NULL);\r
465     }\r
466         \r
467     /* Populate the instance transport callouts */\r
468     rmInst->transport.rmAllocPkt = initCfg->rmAllocPktFuncPtr;\r
469     rmInst->transport.rmFreePkt = initCfg->rmFreePktFuncPtr;\r
470     rmInst->transport.rmSend = initCfg->rmSendFuncPtr;\r
471     rmInst->transport.rmReceive = initCfg->rmReceiveFuncPtr;\r
472     rmInst->transport.rmNumPktsReceived = initCfg->rmNumPktsReceivedFuncPtr;\r
473 \r
474     /* Initialize the transport routing map linked list pointer to NULL.  The linked list\r
475      * nodes will be created when the application registers transports */\r
476     rmInst->routeMap = NULL;\r
477 \r
478     /* Initialize the transaction queue linked list pointer to NULL.  The linked list\r
479      * nodes will be created when the transactions are forwarded to higher level RM\r
480      * agents. */\r
481     rmInst->transactionQueue= NULL;\r
482 \r
483     /* RM Server specific actions */\r
484     if (rmInst->instType == Rm_instType_SERVER)\r
485     {\r
486        /* parse DTB, etc */\r
487     }\r
488 \r
489     /* Instance startup policies are only used for Servers and Client Delegates */\r
490     if (rmInst->instType != Rm_instType_CLIENT)\r
491     {\r
492         rmInst->instPolicy = initCfg->startupPolicy;\r
493 \r
494         /* Store policy via policy APIs ... */\r
495     }\r
496 \r
497     /* Return the RM Handle */\r
498     return ((Rm_Handle) rmInst);\r
499 }\r
500 \r
501 uint32_t Rm_getVersion (void)\r
502 {\r
503     return RM_VERSION_ID;\r
504 }\r
505 \r
506 \r
507 const char* Rm_getVersionStr (void)\r
508 {\r
509     return rmVersionStr;\r
510 }\r
511 \r
512 /**\r
513 @}\r
514 */\r