1 /**
2 * @file rm_services.c
3 *
4 * @brief
5 * This is the Resource Manager services source.
6 *
7 * \par
8 * ============================================================================
9 * @n (C) Copyright 2012-2015, Texas Instruments, Inc.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the
21 * distribution.
22 *
23 * Neither the name of Texas Instruments Incorporated nor the names of
24 * its contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 *
39 * \par
40 */
42 /* RM external API includes */
43 #include <ti/drv/rm/rm.h>
44 #include <ti/drv/rm/rm_services.h>
46 /* RM internal API includes */
47 #include <ti/drv/rm/include/rm_loc.h>
48 #include <ti/drv/rm/include/rm_internal.h>
50 /* RM OSAL layer */
51 #include <rm_osal.h>
53 /**********************************************************************
54 ********************** Internal Functions ****************************
55 **********************************************************************/
57 /* FUNCTION PURPOSE: Internal Callback to unblock RM instance
58 ***********************************************************************
59 * DESCRIPTION: Internal callback function executed when the result
60 * of a service request has been received from a remote
61 * instance. The original service request did not specify
62 * a callback function so the Rm_serviceHandler is blocked
63 * waiting for the response. This function unblocks the
64 * Rm_serviceHandler to return the response to the
65 * application.
66 */
67 void rmServiceInternalCallback(Rm_Handle rmHandle)
68 {
69 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
71 /* Unblock so Rm_serviceHandler can provide response to application */
72 Rm_osalTaskUnblock(rmInst->blockHandle);
73 }
75 /**********************************************************************
76 ********************** Application visible APIs **********************
77 **********************************************************************/
79 /* FUNCTION PURPOSE: Handles application component service requests
80 ***********************************************************************
81 * DESCRIPTION: Receives service requests from application components
82 * and routes them to the transaction processor. If
83 * the service can be handled immediately the response
84 * will be provided in the service response. If the
85 * service requires a blocking operation the handler
86 * will provide a service ID back to the application.
87 * The response will be sent at a later time via the
88 * application supplied callback function.
89 */
90 void Rm_serviceHandler (void *rmHandle, const Rm_ServiceReqInfo *serviceRequest,
91 Rm_ServiceRespInfo *serviceResponse)
92 {
93 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
94 char *instanceName;
95 Rm_Transaction *transaction;
96 void *key;
97 void *mtKey;
99 RM_SS_INST_INV_ENTER_CS(rmInst, key);
100 RM_SC_INST_INV_ENTER_CS(rmInst, key);
101 if (rmInst->mtSemObj) {
102 mtKey = Rm_osalMtCsEnter(rmInst->mtSemObj);
103 }
105 if (rmInst->isLocked) {
106 serviceResponse->serviceState = RM_SERVICE_DENIED_RM_INSTANCE_LOCKED;
107 goto errorExit;
108 }
110 if (serviceRequest->type >= Rm_service_LAST) {
111 serviceResponse->serviceState = RM_ERROR_INVALID_SERVICE_TYPE;
112 goto errorExit;
113 }
115 if (serviceRequest->resourceName) {
116 if ((strlen(serviceRequest->resourceName) + 1) > RM_NAME_MAX_CHARS) {
117 serviceResponse->serviceState = RM_ERROR_RESOURCE_NAME_TOO_LONG;
118 goto errorExit;
119 }
120 }
122 if (serviceRequest->resourceNsName) {
123 if ((strlen(serviceRequest->resourceNsName) + 1) > RM_NAME_MAX_CHARS) {
124 serviceResponse->serviceState = RM_ERROR_NAMESERVER_NAME_TOO_LONG;
125 goto errorExit;
126 }
127 }
129 /* Copy location of instance name to local variable in case Shared Client
130 * needs to transfer control to a shared server */
131 instanceName = rmInst->instName;
132 if (rmInst->instType == Rm_instType_SHARED_CLIENT) {
133 /* Transfer control to shared server instance */
134 rmInst = rmInst->u.sharedClient.sharedServerHandle;
135 }
137 if (transaction = rmTransactionQueueAdd(rmInst)) {
138 transaction->type = serviceRequest->type;
139 rm_strncpy(transaction->serviceSrcInstName, instanceName,
140 RM_NAME_MAX_CHARS);
141 transaction->u.callback.serviceCallback = serviceRequest->callback.serviceCallback;
142 transaction->state = RM_SERVICE_PROCESSING;
143 if (serviceRequest->resourceName) {
144 rm_strncpy(transaction->resourceInfo.name,
145 serviceRequest->resourceName, RM_NAME_MAX_CHARS);
146 }
147 transaction->resourceInfo.base = serviceRequest->resourceBase;
148 transaction->resourceInfo.length = serviceRequest->resourceLength;
149 transaction->resourceInfo.alignment = serviceRequest->resourceAlignment;
150 transaction->resourceInfo.ownerCount = RM_RESOURCE_NUM_OWNERS_INVALID;
151 transaction->resourceInfo.instAllocCount = RM_INST_ALLOC_COUNT_INVALID;
152 if (serviceRequest->resourceNsName) {
153 rm_strncpy(transaction->resourceInfo.nameServerName,
154 serviceRequest->resourceNsName, RM_NAME_MAX_CHARS);
155 }
157 /* Process received transaction */
158 rmProcessRouter(rmInst, transaction);
160 memset((void *)serviceResponse, 0, sizeof(*serviceResponse));
162 if ((rmInst->instType == Rm_instType_SHARED_SERVER) &&
163 (transaction->state == RM_SERVICE_PROCESSING)) {
164 /* Shared Server should always return a fully processed transaction */
165 serviceResponse->serviceState = RM_ERROR_SHARED_INSTANCE_UNFINISHED_REQ;
166 rmTransactionQueueDelete(rmInst, transaction->localId);
167 } else {
168 if ((transaction->state == RM_SERVICE_PROCESSING) &&
169 (transaction->u.callback.serviceCallback == NULL)) {
170 /* Block until response is received. Response will be
171 * received in transaction. */
172 Rm_osalTaskBlock(rmInst->blockHandle);
173 }
175 serviceResponse->rmHandle = rmHandle;
176 serviceResponse->serviceState = transaction->state;
177 /* Owner and instance allocation count will only be set within RM
178 * under certain circumstances. */
179 serviceResponse->resourceNumOwners = transaction->resourceInfo.ownerCount;
180 serviceResponse->instAllocCount = transaction->resourceInfo.instAllocCount;
181 if ((serviceResponse->serviceState == RM_SERVICE_PROCESSING) ||
182 (serviceResponse->serviceState == RM_SERVICE_APPROVED_STATIC) ||
183 (serviceResponse->serviceState ==
184 RM_SERVICE_PENDING_SERVER_RESPONSE)) {
185 /* Service still being processed. Static requests will have
186 * their validation responses sent once all transports have
187 * been established. Provide transaction ID back to component
188 * so it can sort service responses received via callback
189 * function */
190 serviceResponse->serviceId = transaction->localId;
191 }
193 if ((serviceResponse->serviceState == RM_SERVICE_APPROVED) ||
194 (serviceResponse->serviceState == RM_SERVICE_APPROVED_STATIC)) {
195 rm_strncpy(serviceResponse->resourceName,
196 transaction->resourceInfo.name, RM_NAME_MAX_CHARS);
197 serviceResponse->resourceBase = transaction->resourceInfo.base;
198 serviceResponse->resourceLength = transaction->resourceInfo.length;
199 }
201 /* Transactions still processing not deleted from queue including
202 * static transactions which will be verified once all transports
203 * are up */
204 if ((serviceResponse->serviceState != RM_SERVICE_PROCESSING) &&
205 (serviceResponse->serviceState != RM_SERVICE_APPROVED_STATIC) &&
206 (serviceResponse->serviceState !=
207 RM_SERVICE_PENDING_SERVER_RESPONSE)) {
208 rmTransactionQueueDelete(rmInst, transaction->localId);
209 }
210 }
211 } else {
212 serviceResponse->serviceState = RM_ERROR_SERVICE_TRANS_NOT_CREATED;
213 }
215 errorExit:
216 /* Free sem object using originating instance in case the Shared Client to
217 * Shared Server instance switch took place */
218 if (((Rm_Inst *)rmHandle)->mtSemObj) {
219 Rm_osalMtCsExit(((Rm_Inst *)rmHandle)->mtSemObj, mtKey);
220 }
221 /* Shared Client switches to Shared Server instance so only need
222 * SS_EXIT_CS macro */
223 RM_SS_INST_WB_EXIT_CS(rmInst, key);
224 return;
225 }
227 /* FUNCTION PURPOSE: Opens the RM instance service handle
228 ***********************************************************************
229 * DESCRIPTION: Returns the service handle for an RM instance. Only
230 * one service handle is opened per instance.
231 */
232 Rm_ServiceHandle *Rm_serviceOpenHandle(Rm_Handle rmHandle, int32_t *result)
233 {
234 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
235 Rm_ServiceHandle *serviceHandle = NULL;
236 void *key;
237 void *mtKey;
239 RM_SS_INST_INV_ENTER_CS(rmInst, key);
240 if (rmInst->mtSemObj) {
241 mtKey = Rm_osalMtCsEnter(rmInst->mtSemObj);
242 }
244 *result = RM_OK;
246 serviceHandle = rmInst->serviceHandle;
247 if (serviceHandle == NULL) {
248 serviceHandle = Rm_osalMalloc(sizeof(*serviceHandle));
249 if (serviceHandle) {
250 serviceHandle->rmHandle = rmHandle;
251 serviceHandle->Rm_serviceHandler = Rm_serviceHandler;
252 RM_SS_OBJ_WB(rmInst, serviceHandle, Rm_ServiceHandle);
253 rmInst->serviceHandle = serviceHandle;
254 }
255 else {
256 *result = RM_ERROR_SERVICE_HANDLE_MEM_ALLOC_FAILED;
257 }
258 }
260 if (rmInst->mtSemObj) {
261 Rm_osalMtCsExit(rmInst->mtSemObj, mtKey);
262 }
263 RM_SS_INST_WB_EXIT_CS(rmInst, key);
264 return (serviceHandle);
265 }
267 /* FUNCTION PURPOSE: Closes the RM instance service handle
268 ***********************************************************************
269 * DESCRIPTION: Closes the service handle for an RM instance.
270 */
271 int32_t Rm_serviceCloseHandle(Rm_ServiceHandle *rmServiceHandle)
272 {
273 Rm_Inst *rmInst = (Rm_Inst *)rmServiceHandle->rmHandle;
274 int32_t retVal = RM_OK;
275 void *key;
276 void *mtKey;
278 RM_SS_INST_INV_ENTER_CS(rmInst, key);
279 if (rmInst->mtSemObj) {
280 mtKey = Rm_osalMtCsEnter(rmInst->mtSemObj);
281 }
283 if (rmInst->serviceHandle) {
284 Rm_osalFree((void *)rmServiceHandle, sizeof(*rmServiceHandle));
285 rmInst->serviceHandle = NULL;
286 }
287 else {
288 retVal = RM_ERROR_SERVICE_HANDLE_ALREADY_CLOSED;
289 }
291 if (rmInst->mtSemObj) {
292 Rm_osalMtCsExit(rmInst->mtSemObj, mtKey);
293 }
294 RM_SS_INST_WB_EXIT_CS(rmInst, key);
295 return(retVal);
296 }