e546fc3f09be869737c996a1d0028a1394c1085e
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