Steve Muckle | 0a9c087 | 2022-02-16 05:58:07 +0000 | [diff] [blame] | 1 | /******************************************************************************* |
| 2 | * Copyright (C) 2018 Cadence Design Systems, Inc. |
| 3 | * |
| 4 | * Permission is hereby granted, free of charge, to any person obtaining |
| 5 | * a copy of this software and associated documentation files (the |
| 6 | * "Software"), to use this Software with Cadence processor cores only and |
| 7 | * not with any other processors and platforms, subject to |
| 8 | * the following conditions: |
| 9 | * |
| 10 | * The above copyright notice and this permission notice shall be included |
| 11 | * in all copies or substantial portions of the Software. |
| 12 | * |
| 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 14 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 15 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| 16 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| 17 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| 18 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 20 | |
| 21 | ******************************************************************************/ |
| 22 | |
| 23 | #define MODULE_TAG PROXY |
| 24 | |
| 25 | /******************************************************************************* |
| 26 | * Includes |
| 27 | ******************************************************************************/ |
| 28 | |
| 29 | #include "xf.h" |
| 30 | |
| 31 | /******************************************************************************* |
| 32 | * Tracing configuration |
| 33 | ******************************************************************************/ |
| 34 | |
| 35 | TRACE_TAG(INIT, 1); |
| 36 | TRACE_TAG(CMD, 1); |
| 37 | TRACE_TAG(EXEC, 1); |
| 38 | TRACE_TAG(RSP, 1); |
| 39 | TRACE_TAG(REG, 1); |
| 40 | TRACE_TAG(MEM, 1); |
| 41 | TRACE_TAG(GRAPH, 1); |
| 42 | TRACE_TAG(BUFFER, 1); |
| 43 | |
| 44 | /******************************************************************************* |
| 45 | * Internal functions definitions |
| 46 | ******************************************************************************/ |
| 47 | |
| 48 | /* ...execute proxy command synchronously */ |
| 49 | static inline int xf_proxy_cmd_exec(xf_proxy_t *proxy, xf_user_msg_t *msg) |
| 50 | { |
| 51 | xf_proxy_msg_t m; |
| 52 | |
| 53 | /* ...send command to remote proxy */ |
| 54 | m.id = msg->id, m.opcode = msg->opcode, m.length = msg->length; |
| 55 | |
| 56 | /* ...translate address */ |
| 57 | XF_CHK_ERR((m.address = xf_proxy_b2a(proxy, msg->buffer)) != XF_PROXY_BADADDR, -EINVAL); |
| 58 | |
| 59 | /* ...pass command to remote proxy */ |
| 60 | XF_CHK_API(xf_ipc_send(&proxy->ipc, &m, msg->buffer)); |
| 61 | |
| 62 | /* ...wait for response reception indication from proxy thread */ |
| 63 | XF_CHK_API(xf_proxy_response_get(proxy, &m)); |
| 64 | |
| 65 | /* ...copy parameters */ |
| 66 | msg->id = m.id, msg->opcode = m.opcode, msg->length = m.length; |
| 67 | |
| 68 | /* ...translate address back to virtual space */ |
| 69 | XF_CHK_ERR((msg->buffer = xf_proxy_a2b(proxy, m.address)) != (void *)-1, -EBADFD); |
| 70 | |
| 71 | TRACE(EXEC, _b("proxy[%p]: command done: [%08x:%p:%u]"), proxy, msg->opcode, msg->buffer, msg->length); |
| 72 | |
| 73 | return 0; |
| 74 | } |
| 75 | |
| 76 | #if 0 |
| 77 | /* ...pass command to remote DSP */ |
| 78 | static inline int xf_proxy_cmd(xf_proxy_t *proxy, xf_handle_t *handle, xf_user_msg_t *m) |
| 79 | { |
| 80 | xf_proxy_msg_t msg; |
| 81 | |
| 82 | /* ...set session-id of the message */ |
| 83 | msg.id = __XF_MSG_ID(__XF_AP_CLIENT(proxy->core, handle->client), m->id); |
| 84 | msg.opcode = m->opcode; |
| 85 | msg.length = m->length; |
| 86 | |
| 87 | /* ...translate buffer pointer to shared address */ |
| 88 | XF_CHK_ERR((msg.address = xf_proxy_b2a(proxy, m->buffer)) != XF_PROXY_BADADDR, -EINVAL); |
| 89 | |
| 90 | /* ...submit command message to IPC layer */ |
| 91 | return XF_CHK_API(xf_ipc_send(&proxy->ipc, &msg, m->buffer)); |
| 92 | } |
| 93 | #endif /* 0 */ |
| 94 | |
| 95 | /* ...allocate local client-id number */ |
| 96 | static inline u32 xf_client_alloc(xf_proxy_t *proxy, xf_handle_t *handle) |
| 97 | { |
| 98 | u32 client; |
| 99 | |
| 100 | if ((client = proxy->cmap[0].next) != 0) |
| 101 | { |
| 102 | /* ...pop client from free clients list */ |
| 103 | proxy->cmap[0].next = proxy->cmap[client].next; |
| 104 | |
| 105 | /* ...put client handle into association map */ |
| 106 | handle->client = client, proxy->cmap[client].handle = handle; |
| 107 | } |
| 108 | |
| 109 | return client; |
| 110 | } |
| 111 | |
| 112 | /* ...recycle local client-id number */ |
| 113 | static inline void xf_client_free(xf_proxy_t *proxy, xf_handle_t *handle) |
| 114 | { |
| 115 | u32 client = handle->client; |
| 116 | |
| 117 | /* ...push client into head of the free clients list */ |
| 118 | proxy->cmap[client].next = proxy->cmap[0].next; |
| 119 | |
| 120 | /* ...adjust head of free clients */ |
| 121 | proxy->cmap[0].next = client; |
| 122 | } |
| 123 | |
| 124 | /* ...lookup client basing on its local id */ |
| 125 | static inline xf_handle_t * xf_client_lookup(xf_proxy_t *proxy, u32 client) |
| 126 | { |
| 127 | /* ...client index must be in proper range */ |
| 128 | BUG(client >= XF_CFG_PROXY_MAX_CLIENTS, _x("Invalid client index: %u"), client); |
| 129 | |
| 130 | /* ...check if client index is small */ |
| 131 | if (proxy->cmap[client].next < XF_CFG_PROXY_MAX_CLIENTS) |
| 132 | return NULL; |
| 133 | else |
| 134 | return proxy->cmap[client].handle; |
| 135 | } |
| 136 | |
| 137 | /* ...create new client on remote core */ |
| 138 | static inline int xf_client_register(xf_proxy_t *proxy, xf_handle_t *handle, xf_id_t id, u32 core) |
| 139 | { |
| 140 | void *b = xf_handle_aux(handle); |
| 141 | xf_user_msg_t msg; |
| 142 | |
| 143 | /* ...set session-id: source is local proxy, destination is remote proxy */ |
| 144 | msg.id = __XF_MSG_ID(__XF_AP_PROXY(proxy->core), __XF_DSP_PROXY(core)); |
| 145 | msg.opcode = XF_REGISTER; |
| 146 | msg.buffer = b; |
| 147 | msg.length = strlen(id) + 1; |
| 148 | |
| 149 | /* ...copy component identifier */ |
| 150 | strncpy(b, id, xf_buffer_length(handle->aux)); |
| 151 | |
| 152 | /* ...execute command synchronously */ |
| 153 | XF_CHK_API(xf_proxy_cmd_exec(proxy, &msg)); |
| 154 | |
| 155 | /* ...check operation is successfull */ |
| 156 | XF_CHK_ERR(msg.opcode == (u32) XF_REGISTER, -EFAULT); |
| 157 | |
| 158 | /* ...save received component global client-id */ |
| 159 | handle->id = XF_MSG_SRC(msg.id); |
| 160 | |
| 161 | TRACE(REG, _b("[%p]=[%s:%u:%u]"), handle, id, XF_PORT_CORE(handle->id), XF_PORT_CLIENT(handle->id)); |
| 162 | |
| 163 | return 0; |
| 164 | } |
| 165 | |
| 166 | /* ...unregister client from remote proxy */ |
| 167 | static inline int xf_client_unregister(xf_proxy_t *proxy, xf_handle_t *handle) |
| 168 | { |
| 169 | xf_user_msg_t msg; |
| 170 | |
| 171 | /* ...make sure the client is consistent */ |
| 172 | BUG(proxy->cmap[handle->client].handle != handle, _x("Invalid handle: %p"), handle); |
| 173 | |
| 174 | /* ...set message parameters */ |
| 175 | msg.id = __XF_MSG_ID(__XF_AP_PROXY(proxy->core), handle->id); |
| 176 | msg.opcode = XF_UNREGISTER; |
| 177 | msg.buffer = NULL; |
| 178 | msg.length = 0; |
| 179 | |
| 180 | /* ...synchronously execute command on remote proxy */ |
| 181 | XF_CHK_API(xf_proxy_cmd_exec(proxy, &msg)); |
| 182 | |
| 183 | /* ...opcode must be XF_UNREGISTER - tbd */ |
| 184 | BUG(msg.opcode != XF_UNREGISTER, _x("Invalid opcode: %X"), msg.opcode); |
| 185 | |
| 186 | TRACE(REG, _b("%p[%u:%u] unregistered"), handle, XF_PORT_CORE(handle->id), XF_PORT_CLIENT(handle->id)); |
| 187 | |
| 188 | return 0; |
| 189 | } |
| 190 | |
| 191 | /* ...allocate shared buffer */ |
| 192 | static inline int xf_proxy_buffer_alloc(xf_proxy_t *proxy, u32 length, void **buffer) |
| 193 | { |
| 194 | u32 core = proxy->core; |
| 195 | xf_user_msg_t msg; |
| 196 | |
| 197 | /* ...prepare command parameters */ |
| 198 | msg.id = __XF_MSG_ID(__XF_AP_PROXY(core), __XF_DSP_PROXY(core)); |
| 199 | msg.opcode = XF_ALLOC; |
| 200 | msg.length = length; |
| 201 | msg.buffer = NULL; |
| 202 | |
| 203 | /* ...synchronously execute command on remote proxy */ |
| 204 | XF_CHK_API(xf_proxy_cmd_exec(proxy, &msg)); |
| 205 | |
| 206 | /* ...check if response is valid */ |
| 207 | XF_CHK_ERR(msg.opcode == XF_ALLOC, -EBADFD); |
| 208 | |
| 209 | /* ...check if allocation is successful */ |
| 210 | XF_CHK_ERR(msg.buffer != NULL, -ENOMEM); |
| 211 | |
| 212 | /* ...save output parameter */ |
| 213 | *buffer = msg.buffer; |
| 214 | |
| 215 | TRACE(MEM, _b("proxy-%u: allocated [%p:%u]"), core, *buffer, length); |
| 216 | |
| 217 | return 0; |
| 218 | } |
| 219 | |
| 220 | /* ...free shared AP-DSP memory */ |
| 221 | static inline int xf_proxy_buffer_free(xf_proxy_t *proxy, void *buffer, u32 length) |
| 222 | { |
| 223 | u32 core = proxy->core; |
| 224 | xf_user_msg_t msg; |
| 225 | |
| 226 | /* ...prepare command parameters */ |
| 227 | msg.id = __XF_MSG_ID(__XF_AP_PROXY(core), __XF_DSP_PROXY(core)); |
| 228 | msg.opcode = XF_FREE; |
| 229 | msg.length = length; |
| 230 | msg.buffer = buffer; |
| 231 | |
| 232 | /* ...synchronously execute command on remote proxy */ |
| 233 | XF_CHK_API(xf_proxy_cmd_exec(proxy, &msg)); |
| 234 | |
| 235 | /* ...check if response is valid */ |
| 236 | XF_CHK_ERR(msg.opcode == XF_FREE, -EBADFD); |
| 237 | |
| 238 | TRACE(MEM, _b("proxy-%u: free [%p:%u]"), core, buffer, length); |
| 239 | |
| 240 | return 0; |
| 241 | } |
| 242 | |
| 243 | /******************************************************************************* |
| 244 | * Proxy interface asynchronous receiving thread |
| 245 | ******************************************************************************/ |
| 246 | |
| 247 | static void * xf_proxy_thread(void *arg) |
| 248 | { |
| 249 | xf_proxy_t *proxy = arg; |
| 250 | xf_handle_t *client; |
| 251 | int r; |
| 252 | |
| 253 | /* ...start polling thread */ |
| 254 | while (1) |
| 255 | { |
| 256 | xf_proxy_msg_t m; |
| 257 | xf_user_msg_t msg; |
| 258 | |
| 259 | /* ...wait for response from remote proxy (infinite timeout) */ |
| 260 | if ((r = xf_ipc_wait(&proxy->ipc, 0)) < 0) |
| 261 | break; |
| 262 | |
| 263 | /* ...retrieve all responses received */ |
| 264 | while ((r = xf_ipc_recv(&proxy->ipc, &m, &msg.buffer)) == sizeof(m)) |
| 265 | { |
| 266 | /* ...make sure we have proper core identifier of SHMEM interface */ |
| 267 | BUG(XF_MSG_DST_CORE(m.id) != proxy->core, _x("Invalid session-id: %X (core=%u)"), m.id, proxy->core); |
| 268 | |
| 269 | /* ...make sure translation is successful */ |
| 270 | BUG(msg.buffer == (void *)-1, _x("Invalid buffer address: %08x"), m.address); |
| 271 | |
| 272 | /* ...retrieve information fields */ |
| 273 | msg.id = XF_MSG_SRC(m.id), msg.opcode = m.opcode, msg.length = m.length; |
| 274 | |
| 275 | TRACE(RSP, _b("R[%08x]:(%08x,%u,%08x)"), m.id, m.opcode, m.length, m.address); |
| 276 | |
| 277 | /* ...lookup component basing on destination port specification */ |
| 278 | if (XF_AP_CLIENT(m.id) == 0) |
| 279 | { |
| 280 | /* ...put proxy response to local IPC queue */ |
| 281 | xf_proxy_response_put(proxy, &m); |
| 282 | } |
| 283 | else if ((client = xf_client_lookup(proxy, XF_AP_CLIENT(m.id))) != NULL) |
| 284 | { |
| 285 | /* ...client is found; invoke its response callback (must be non-blocking) */ |
| 286 | client->response(client, &msg); |
| 287 | } |
| 288 | else |
| 289 | { |
| 290 | /* ...client has been disconnected already; drop message */ |
| 291 | TRACE(RSP, _b("Client look-up failed - drop message")); |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | /* ...if result code is negative; terminate thread operation */ |
| 296 | if (r < 0) |
| 297 | { |
| 298 | TRACE(ERROR, _x("abnormal proxy[%p] thread termination: %d"), proxy, r); |
| 299 | break; |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | TRACE(INIT, _b("IPC proxy[%p] thread terminated: %d"), proxy, r); |
| 304 | |
| 305 | return (void *)(intptr_t)r; |
| 306 | } |
| 307 | |
| 308 | /******************************************************************************* |
| 309 | * HiFi proxy API |
| 310 | ******************************************************************************/ |
| 311 | |
| 312 | /* ...open HiFi proxy */ |
| 313 | int xf_proxy_init(xf_proxy_t *proxy, u32 core, void *p_shmem) |
| 314 | { |
| 315 | u32 i; |
| 316 | int r; |
| 317 | |
| 318 | /* ...initialize proxy lock */ |
| 319 | __xf_lock_init(&proxy->lock); |
| 320 | |
| 321 | /* ...open proxy IPC interface */ |
| 322 | XF_CHK_API(xf_ipc_open(&proxy->ipc, core, p_shmem)); |
| 323 | |
| 324 | /* ...save proxy core - hmm, too much core identifiers - tbd */ |
| 325 | proxy->core = core; |
| 326 | |
| 327 | /* ...line-up all clients into single-linked list */ |
| 328 | for (i = 0; i < XF_CFG_PROXY_MAX_CLIENTS - 1; i++) |
| 329 | { |
| 330 | proxy->cmap[i].next = i + 1; |
| 331 | } |
| 332 | |
| 333 | /* ...tail of the list points back to head (list terminator) */ |
| 334 | proxy->cmap[i].next = 0; |
| 335 | |
| 336 | /* ...initialize thread attributes (joinable, with minimal stack) */ |
| 337 | if ((r = __xf_thread_create(&proxy->thread, xf_proxy_thread, proxy)) < 0) |
| 338 | { |
| 339 | TRACE(ERROR, _x("Failed to create polling thread: %d"), r); |
| 340 | xf_ipc_close(&proxy->ipc, core); |
| 341 | return r; |
| 342 | } |
| 343 | |
| 344 | TRACE(INIT, _b("proxy-%u[%p] opened"), core, proxy); |
| 345 | |
| 346 | return 0; |
| 347 | } |
| 348 | |
| 349 | /* ...close proxy handle */ |
| 350 | void xf_proxy_close(xf_proxy_t *proxy) |
| 351 | { |
| 352 | u32 core = proxy->core; |
| 353 | |
| 354 | /* ...terminate proxy thread */ |
| 355 | __xf_thread_destroy(&proxy->thread); |
| 356 | |
| 357 | /* ...close proxy IPC interface */ |
| 358 | xf_ipc_close(&proxy->ipc, core); |
| 359 | |
| 360 | TRACE(INIT, _b("proxy-%u[%p] closed"), core, proxy); |
| 361 | } |
| 362 | |
| 363 | /******************************************************************************* |
| 364 | * HiFi component API |
| 365 | ******************************************************************************/ |
| 366 | |
| 367 | /* ...open component handle */ |
| 368 | int xf_open(xf_proxy_t *proxy, xf_handle_t *handle, xf_id_t id, u32 core, xf_response_cb response) |
| 369 | { |
| 370 | int r; |
| 371 | |
| 372 | /* ...retrieve auxiliary control buffer from proxy - need I */ |
| 373 | XF_CHK_ERR(handle->aux = xf_buffer_get(proxy->aux), -EBUSY); |
| 374 | |
| 375 | /* ...initialize IPC data */ |
| 376 | XF_CHK_API(xf_ipc_data_init(&handle->ipc)); |
| 377 | |
| 378 | /* ...register client in interlocked fashion */ |
| 379 | xf_proxy_lock(proxy); |
| 380 | |
| 381 | /* ...allocate local client */ |
| 382 | if (xf_client_alloc(proxy, handle) == 0) |
| 383 | { |
| 384 | TRACE(ERROR, _x("client allocation failed")); |
| 385 | r = -EBUSY; |
| 386 | } |
| 387 | else if ((r = xf_client_register(proxy, handle, id, core)) < 0) |
| 388 | { |
| 389 | TRACE(ERROR, _x("client registering failed")); |
| 390 | xf_client_free(proxy, handle); |
| 391 | } |
| 392 | |
| 393 | xf_proxy_unlock(proxy); |
| 394 | |
| 395 | /* ...if failed, release buffer handle */ |
| 396 | if (r < 0) |
| 397 | { |
| 398 | /* ...operation failed; return buffer back to proxy pool */ |
| 399 | xf_buffer_put(handle->aux), handle->aux = NULL; |
| 400 | } |
| 401 | else |
| 402 | { |
| 403 | /* ...operation completed successfully; assign handle data */ |
| 404 | handle->response = response; |
| 405 | handle->proxy = proxy; |
| 406 | |
| 407 | TRACE(INIT, _b("component[%p]:(id=%s,core=%u) created"), handle, id, core); |
| 408 | } |
| 409 | |
| 410 | return XF_CHK_API(r); |
| 411 | } |
| 412 | |
| 413 | /* ...close component handle */ |
| 414 | void xf_close(xf_handle_t *handle) |
| 415 | { |
| 416 | xf_proxy_t *proxy = handle->proxy; |
| 417 | |
| 418 | /* ...do I need to take component lock here? guess no - tbd */ |
| 419 | |
| 420 | /* ...buffers and stuff? - tbd */ |
| 421 | |
| 422 | /* ...acquire global proxy lock */ |
| 423 | xf_proxy_lock(proxy); |
| 424 | |
| 425 | /* ...unregister component from remote DSP proxy (ignore result code) */ |
| 426 | (void) xf_client_unregister(proxy, handle); |
| 427 | |
| 428 | /* ...recycle client-id afterwards */ |
| 429 | xf_client_free(proxy, handle); |
| 430 | |
| 431 | /* ...release global proxy lock */ |
| 432 | xf_proxy_unlock(proxy); |
| 433 | |
| 434 | /* ...destroy IPC data */ |
| 435 | xf_ipc_data_destroy(&handle->ipc); |
| 436 | |
| 437 | /* ...clear handle data */ |
| 438 | xf_buffer_put(handle->aux), handle->aux = NULL; |
| 439 | |
| 440 | /* ...wipe out proxy pointer */ |
| 441 | handle->proxy = NULL; |
| 442 | |
| 443 | TRACE(INIT, _b("component[%p] destroyed"), handle); |
| 444 | } |
| 445 | |
| 446 | /* ...port binding function */ |
| 447 | int xf_route(xf_handle_t *src, u32 src_port, xf_handle_t *dst, u32 dst_port, u32 num, u32 size, u32 align) |
| 448 | { |
| 449 | xf_proxy_t *proxy = src->proxy; |
| 450 | xf_buffer_t *b; |
| 451 | xf_route_port_msg_t *m; |
| 452 | xf_user_msg_t msg; |
| 453 | |
| 454 | /* ...validity checks - proxy pointers are same */ |
| 455 | XF_CHK_ERR(proxy == dst->proxy, -EINVAL); |
| 456 | |
| 457 | /* ...buffer data is valid */ |
| 458 | XF_CHK_ERR(num && size && xf_is_power_of_two(align), -EINVAL); |
| 459 | |
| 460 | /* ...get control buffer */ |
| 461 | XF_CHK_ERR(b = xf_buffer_get(proxy->aux), -EBUSY); |
| 462 | |
| 463 | /* ...get message buffer */ |
| 464 | m = xf_buffer_data(b); |
| 465 | |
| 466 | /* ...fill-in message parameters */ |
| 467 | //m->src = __XF_PORT_SPEC2(src->id, src_port); |
| 468 | m->dst = __XF_PORT_SPEC2(dst->id, dst_port); |
| 469 | m->alloc_number = num; |
| 470 | m->alloc_size = size; |
| 471 | m->alloc_align = align; |
| 472 | |
| 473 | /* ...set command parameters */ |
| 474 | msg.id = __XF_MSG_ID(__XF_AP_PROXY(proxy->core), __XF_PORT_SPEC2(src->id, src_port)); |
| 475 | msg.opcode = XF_ROUTE; |
| 476 | msg.length = sizeof(*m); |
| 477 | msg.buffer = m; |
| 478 | |
| 479 | /* ...synchronously execute command on remote DSP */ |
| 480 | XF_CHK_API(xf_proxy_cmd_exec(proxy, &msg)); |
| 481 | |
| 482 | /* ...return buffer to proxy */ |
| 483 | xf_buffer_put(b); |
| 484 | |
| 485 | /* ...check result is successfull */ |
| 486 | XF_CHK_ERR(msg.opcode == (u32) XF_ROUTE, -ENOMEM); |
| 487 | |
| 488 | /* ...port binding completed */ |
| 489 | TRACE(GRAPH, _b("[%p]:%u bound to [%p]:%u"), src, src_port, dst, dst_port); |
| 490 | |
| 491 | return 0; |
| 492 | } |
| 493 | |
| 494 | /* ...port unbinding function */ |
| 495 | int xf_unroute(xf_handle_t *src, u32 src_port) |
| 496 | { |
| 497 | xf_proxy_t *proxy = src->proxy; |
| 498 | xf_buffer_t *b; |
| 499 | xf_unroute_port_msg_t *m; |
| 500 | xf_user_msg_t msg; |
| 501 | int r; |
| 502 | |
| 503 | /* ...get control buffer */ |
| 504 | XF_CHK_ERR(b = xf_buffer_get(proxy->aux), -EBUSY); |
| 505 | |
| 506 | /* ...get message buffer */ |
| 507 | m = xf_buffer_data(b); |
| 508 | |
| 509 | /* ...fill-in message parameters */ |
| 510 | //m->src = __XF_PORT_SPEC2(src->id, src_port); |
| 511 | |
| 512 | /* ...set command parameters */ |
| 513 | msg.id = __XF_MSG_ID(__XF_AP_PROXY(proxy->core), __XF_PORT_SPEC2(src->id, src_port)); |
| 514 | msg.opcode = XF_UNROUTE; |
| 515 | msg.length = sizeof(*m); |
| 516 | msg.buffer = m; |
| 517 | |
| 518 | /* ...synchronously execute command on remote DSP */ |
| 519 | if ((r = xf_proxy_cmd_exec(proxy, &msg)) != 0) |
| 520 | { |
| 521 | TRACE(ERROR, _x("Command failed: %d"), r); |
| 522 | goto out; |
| 523 | } |
| 524 | else if (msg.opcode != (u32) XF_UNROUTE) |
| 525 | { |
| 526 | TRACE(ERROR, _x("Port unbinding failed")); |
| 527 | r = -EBADFD; |
| 528 | goto out; |
| 529 | } |
| 530 | |
| 531 | /* ...port binding completed */ |
| 532 | TRACE(GRAPH, _b("[%p]:%u unbound"), src, src_port); |
| 533 | |
| 534 | out: |
| 535 | /* ...return buffer to proxy */ |
| 536 | xf_buffer_put(b); |
| 537 | |
| 538 | return r; |
| 539 | } |
| 540 | |
| 541 | /* ...send a command message to component */ |
| 542 | int xf_command(xf_handle_t *handle, u32 port, u32 opcode, void *buffer, u32 length) |
| 543 | { |
| 544 | xf_proxy_t *proxy = handle->proxy; |
| 545 | xf_proxy_msg_t msg; |
| 546 | |
| 547 | /* ...fill-in message parameters */ |
| 548 | msg.id = __XF_MSG_ID(__XF_AP_CLIENT(proxy->core, handle->client), __XF_PORT_SPEC2(handle->id, port)); |
| 549 | msg.opcode = opcode; |
| 550 | msg.length = length; |
| 551 | XF_CHK_ERR((msg.address = xf_proxy_b2a(proxy, buffer)) != XF_PROXY_BADADDR, -EINVAL); |
| 552 | |
| 553 | TRACE(CMD, _b("[%p]:[%08x]:(%08x,%u,%p)"), handle, msg.id, opcode, length, buffer); |
| 554 | |
| 555 | /* ...pass command to IPC layer */ |
| 556 | return XF_CHK_API(xf_ipc_send(&proxy->ipc, &msg, buffer)); |
| 557 | } |
| 558 | |
| 559 | /******************************************************************************* |
| 560 | * Buffer pool API |
| 561 | ******************************************************************************/ |
| 562 | |
| 563 | /* ...allocate buffer pool */ |
| 564 | int xf_pool_alloc(xf_proxy_t *proxy, u32 number, u32 length, xf_pool_type_t type, xf_pool_t **pool, s32 id, |
| 565 | xaf_mem_malloc_fxn_t xaf_malloc, xaf_mem_free_fxn_t xaf_free) |
| 566 | { |
| 567 | xf_pool_t *p; |
| 568 | xf_buffer_t *b; |
| 569 | void *data; |
| 570 | int r; |
| 571 | |
| 572 | /* ...unused arg */ |
| 573 | (void) type; |
| 574 | |
| 575 | /* ...basic validity checks; number of buffers is positive */ |
| 576 | XF_CHK_ERR(number > 0, -EINVAL); |
| 577 | |
| 578 | /* ...get properly aligned buffer length */ |
| 579 | length = (length + XF_PROXY_ALIGNMENT - 1) & ~(XF_PROXY_ALIGNMENT - 1); |
| 580 | |
| 581 | /* ...allocate data structure */ |
| 582 | p = xaf_malloc(offset_of(xf_pool_t, buffer) + number * sizeof(xf_buffer_t), id); |
| 583 | XF_CHK_ERR(p, -ENOMEM); |
| 584 | |
| 585 | /* ...issue memory pool allocation request to remote DSP */ |
| 586 | xf_proxy_lock(proxy); |
| 587 | r = xf_proxy_buffer_alloc(proxy, number * length, &p->p); |
| 588 | xf_proxy_unlock(proxy); |
| 589 | |
| 590 | /* ...if operation is failed, do cleanup */ |
| 591 | if (r < 0) |
| 592 | { |
| 593 | TRACE(ERROR, _x("failed to allocate buffer: %d"), r); |
| 594 | xaf_free(p, id); |
| 595 | return r; |
| 596 | } |
| 597 | else |
| 598 | { |
| 599 | /* ...set pool parameters */ |
| 600 | p->number = number, p->length = length; |
| 601 | p->proxy = proxy; |
| 602 | } |
| 603 | |
| 604 | /* ...create individual buffers and link them into free list */ |
| 605 | for (p->free = b = &p->buffer[0], data = p->p; number > 0; number--, b++) |
| 606 | { |
| 607 | /* ...set address of the buffer (no length there) */ |
| 608 | b->address = data; |
| 609 | |
| 610 | /* ...file buffer into the free list */ |
| 611 | b->link.next = b + 1; |
| 612 | |
| 613 | /* ...advance data pointer in contiguous buffer */ |
| 614 | data = (unsigned char *) data + length; |
| 615 | } |
| 616 | |
| 617 | /* ...terminate list of buffers (not too good - tbd) */ |
| 618 | b[-1].link.next = NULL; |
| 619 | |
| 620 | TRACE(BUFFER, _b("[%p]: pool[%p] created: %u * %u"), proxy, p, p->number, p->length); |
| 621 | |
| 622 | /* ...return buffer pointer */ |
| 623 | *pool = p; |
| 624 | |
| 625 | return 0; |
| 626 | } |
| 627 | |
| 628 | /* ...buffer pool destruction */ |
| 629 | void xf_pool_free(xf_pool_t *pool, s32 id, xaf_mem_free_fxn_t xaf_free) |
| 630 | { |
| 631 | xf_proxy_t *proxy = pool->proxy; |
| 632 | |
| 633 | /* ...check buffers are all freed - tbd */ |
| 634 | |
| 635 | /* ...use global proxy lock for pool operations protection */ |
| 636 | xf_proxy_lock(proxy); |
| 637 | |
| 638 | /* ...release allocated buffer on remote DSP */ |
| 639 | xf_proxy_buffer_free(proxy, pool->p, pool->length * pool->number); |
| 640 | |
| 641 | /* ...release global proxy lock */ |
| 642 | xf_proxy_unlock(proxy); |
| 643 | |
| 644 | /* ...deallocate pool structure itself */ |
| 645 | xaf_free(pool, id); |
| 646 | |
| 647 | TRACE(BUFFER, _b("[%p]::pool[%p] destroyed"), proxy, pool); |
| 648 | } |
| 649 | |
| 650 | /* ...get new buffer from a pool */ |
| 651 | xf_buffer_t * xf_buffer_get(xf_pool_t *pool) |
| 652 | { |
| 653 | xf_buffer_t *b; |
| 654 | |
| 655 | /* ...use global proxy lock for pool operations protection */ |
| 656 | xf_proxy_lock(pool->proxy); |
| 657 | |
| 658 | /* ...take buffer from a head of the free list */ |
| 659 | if ((b = pool->free) != NULL) |
| 660 | { |
| 661 | /* ...advance free list head */ |
| 662 | pool->free = b->link.next, b->link.pool = pool; |
| 663 | |
| 664 | TRACE(BUFFER, _b("pool[%p]::get[%p]"), pool, b); |
| 665 | } |
| 666 | |
| 667 | xf_proxy_unlock(pool->proxy); |
| 668 | |
| 669 | return b; |
| 670 | } |
| 671 | |
| 672 | /* ...return buffer back to pool */ |
| 673 | void xf_buffer_put(xf_buffer_t *buffer) |
| 674 | { |
| 675 | xf_pool_t *pool = buffer->link.pool; |
| 676 | |
| 677 | /* ...use global proxy lock for pool operations protection */ |
| 678 | xf_proxy_lock(pool->proxy); |
| 679 | |
| 680 | /* ...put buffer back to a pool */ |
| 681 | buffer->link.next = pool->free, pool->free = buffer; |
| 682 | |
| 683 | TRACE(BUFFER, _b("pool[%p]::put[%p]"), pool, buffer); |
| 684 | |
| 685 | xf_proxy_unlock(pool->proxy); |
| 686 | } |