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 /******************************************************************************* 24 * xf-shmem.c 25 * 26 * DSP shared memory interface implementation 27 * 28 ******************************************************************************/ 29 30 #define MODULE_TAG SHMEM 31 32 /******************************************************************************* 33 * Includes 34 ******************************************************************************/ 35 36 #include "xf.h" 37 38 /******************************************************************************* 39 * Tracing tags 40 ******************************************************************************/ 41 42 /* ...general initialization sequence */ 43 TRACE_TAG(INIT, 1); 44 45 /* ...interface status change */ 46 TRACE_TAG(EXEC, 0); 47 48 /* ...command reception */ 49 TRACE_TAG(CMD, 1); 50 51 /* ...response generation */ 52 TRACE_TAG(RSP, 1); 53 54 #ifdef XAF_PROFILE_DSP 55 #include "xa_profiler.h" 56 #endif 57 /******************************************************************************* 58 * Local constants definitions 59 ******************************************************************************/ 60 61 /* ...local interface status change flag */ 62 #define XF_PROXY_STATUS_LOCAL (1 << 0) 63 64 /* ...remote status change notification flag */ 65 #define XF_PROXY_STATUS_REMOTE (1 << 1) 66 67 /******************************************************************************* 68 * Internal helpers 69 ******************************************************************************/ 70 71 /* ...put message into proxy queue */ 72 static inline void xf_msg_proxy_put(xf_message_t *m) 73 { 74 u32 dst = XF_MSG_DST_CORE(m->id); 75 u32 src = XF_MSG_SRC_CORE(m->id); 76 xf_core_rw_data_t *rw = XF_CORE_RW_DATA(dst); 77 int first; 78 79 /* ...get an access to shared rw-memory (we are running on "source" core) */ 80 xf_mutex_lock(src); 81 82 /* ...assure memory coherency if needed */ 83 if (XF_REMOTE_IPC_NON_COHERENT) 84 { 85 /* ...invalidate rw-shared memory region */ 86 XF_PROXY_INVALIDATE(rw, sizeof(*rw)); 87 88 /* ...put message into shared queue */ 89 first = xf_msg_enqueue(&rw->remote, m); 90 91 /* ...flush both message and shared queue data */ 92 XF_PROXY_FLUSH(rw, sizeof(*rw)), XF_PROXY_FLUSH(m, sizeof(*m)); 93 } 94 else 95 { 96 /* ...no memory coherency concerns; just place a message in the queue */ 97 first = xf_msg_enqueue(&rw->remote, m); 98 } 99 100 /* ...release rw-memory region lock */ 101 xf_mutex_unlock(src); 102 103 /* ...assert IPI interrupt on target ("destination") core if needed */ 104 if (first && (dst ^ src)) 105 { 106 xf_ipi_assert(dst); 107 } 108 } 109 110 /* ...retrieve message from proxy queue */ 111 static inline xf_message_t * xf_msg_proxy_get(u32 core) 112 { 113 xf_core_rw_data_t *rw = XF_CORE_RW_DATA(core); 114 xf_message_t *m; 115 116 /* ...retrieve message from queue in atomic fashion */ 117 xf_mutex_lock(core); 118 119 /* ...assure memory coherency if needed */ 120 if (XF_REMOTE_IPC_NON_COHERENT) 121 { 122 /* ...invalidate rw-memory */ 123 XF_PROXY_INVALIDATE(rw, sizeof(*rw)); 124 125 /* ...dequeue message from response queue */ 126 m = xf_msg_dequeue(&rw->remote); 127 128 /* ...flush rw memory */ 129 XF_PROXY_FLUSH(rw, sizeof(*rw)); 130 131 /* ...invalidate message data if found */ 132 (m ? XF_PROXY_INVALIDATE(m, sizeof(*m)) : 0); 133 } 134 else 135 { 136 /* ...just dequeue message from response queue */ 137 m = xf_msg_dequeue(&rw->remote); 138 } 139 140 /* ...release the rw-lock */ 141 xf_mutex_unlock(core); 142 143 return m; 144 } 145 146 /******************************************************************************* 147 * Internal functions definitions 148 ******************************************************************************/ 149 150 /* ...retrieve all incoming commands from shared memory ring-buffer */ 151 static u32 xf_shmem_process_input(u32 core) 152 { 153 xf_message_t *m; 154 u32 read_idx; 155 u32 write_idx; 156 u32 status = 0; 157 158 /* ...get current value of write pointer */ 159 read_idx = XF_PROXY_READ(core, cmd_read_idx); 160 write_idx = XF_PROXY_READ(core, cmd_write_idx); 161 162 TRACE(EXEC, _b("Command queue: write = %x / read = %x"), write_idx, read_idx); 163 164 /* ...process all committed commands */ 165 while (!XF_QUEUE_EMPTY(read_idx, write_idx)) 166 { 167 xf_proxy_message_t *command; 168 169 /* ...allocate message; the call should not fail */ 170 if ((m = xf_msg_pool_get(&XF_CORE_RO_DATA(core)->pool)) == NULL) 171 break; 172 173 /* ...if queue was full, set global proxy update flag */ 174 if (XF_QUEUE_FULL(read_idx, write_idx)) 175 status |= XF_PROXY_STATUS_REMOTE | XF_PROXY_STATUS_LOCAL; 176 else 177 status |= XF_PROXY_STATUS_LOCAL; 178 179 /* ...get oldest not processed command */ 180 command = XF_PROXY_COMMAND(core, XF_QUEUE_IDX(read_idx)); 181 182 /* ...synchronize memory contents */ 183 XF_PROXY_INVALIDATE(command, sizeof(*command)); 184 185 /* ...fill message parameters */ 186 m->id = command->session_id; 187 m->opcode = command->opcode; 188 m->length = command->length; 189 m->buffer = xf_ipc_a2b(core, command->address); 190 TRACE(CMD, _b("C[%x]:(%x,%u,%p)"), m->id, m->opcode, m->length, m->buffer); 191 192 /* ...invalidate message buffer contents as required - not here - tbd */ 193 (XF_OPCODE_CDATA(m->opcode) ? XF_PROXY_INVALIDATE(m->buffer, m->length) : 0); 194 195 /* ...advance local reading index copy */ 196 read_idx = XF_QUEUE_ADVANCE_IDX(read_idx); 197 198 /* ...update shadow copy of reading index */ 199 XF_PROXY_WRITE(core, cmd_read_idx, read_idx); 200 201 /* ...and schedule message execution on proper core */ 202 xf_msg_submit(m); 203 } 204 205 return status; 206 } 207 208 /* ...send out all pending outgoing responses to the shared memory ring-buffer */ 209 static u32 xf_shmem_process_output(u32 core) 210 { 211 xf_message_t *m; 212 u32 read_idx; 213 u32 write_idx; 214 u32 status = 0; 215 216 /* ...get current value of peer read pointer */ 217 write_idx = XF_PROXY_READ(core, rsp_write_idx); 218 read_idx = XF_PROXY_READ(core, rsp_read_idx); 219 220 TRACE(EXEC, _b("Response queue: write = %08X / read = %08X"), write_idx, read_idx); 221 222 /* ...while we have response messages and there's space to write out one */ 223 while (!XF_QUEUE_FULL(read_idx, write_idx)) 224 { 225 xf_proxy_message_t *response; 226 227 /* ...remove message from internal queue */ 228 if ((m = xf_msg_proxy_get(core)) == NULL) 229 break; 230 231 /* ...notify remote interface each time we send it a message (only if it was empty?) */ 232 status = XF_PROXY_STATUS_REMOTE | XF_PROXY_STATUS_LOCAL; 233 234 #if 0 235 /* ...need to decide on best strategy - tbd */ 236 if (XF_QUEUE_EMPTY(read_idx, write_idx)) 237 status |= XF_PROXY_STATUS_REMOTE | XF_PROXY_STATUS_LOCAL; 238 else 239 status |= XF_PROXY_STATUS_LOCAL; 240 #endif 241 242 /* ...flush message buffer contents to main memory as required - too late - different core - tbd */ 243 (XF_OPCODE_RDATA(m->opcode) ? XF_PROXY_FLUSH(m->buffer, m->length) : 0); 244 245 /* ...find place in a queue for next response */ 246 response = XF_PROXY_RESPONSE(core, XF_QUEUE_IDX(write_idx)); 247 248 /* ...put the response message fields */ 249 response->session_id = m->id; 250 response->opcode = m->opcode; 251 response->length = m->length; 252 response->address = xf_ipc_b2a(core, m->buffer); 253 /* ...flush the content of the caches to main memory */ 254 XF_PROXY_FLUSH(response, sizeof(*response)); 255 256 #ifdef XAF_PROFILE_DSP 257 if((m->opcode == XF_FILL_THIS_BUFFER)) 258 { 259 if((m->length != 0) && (m->length != 20)) 260 { 261 prof.g_output_bytes += (unsigned long)m->length; 262 } 263 else if (m->length == 20) 264 { 265 /* Profiler re-initialization */ 266 INIT_XA_PROFILER(prof,"DSP core"); 267 268 /* update stream params on re-init */ 269 xf_start_msg_t *sm = (xf_start_msg_t *)m->buffer; 270 prof.sample_rate = sm->sample_rate; 271 prof.channels = sm->channels; 272 prof.pcm_width = sm->pcm_width; 273 } 274 } 275 #endif 276 TRACE(RSP, _b("R[%x]:(%x,%u,%p)"), m->id, m->opcode, m->length, m->buffer); 277 278 /* ...return message back to the pool */ 279 xf_msg_pool_put(&XF_CORE_RO_DATA(core)->pool, m); 280 281 /* ...advance local writing index copy */ 282 write_idx = XF_QUEUE_ADVANCE_IDX(write_idx); 283 284 /* ...update shared copy of queue write pointer */ 285 XF_PROXY_WRITE(core, rsp_write_idx, write_idx); 286 } 287 288 /* ...return interface status change flags */ 289 return status; 290 } 291 292 /******************************************************************************* 293 * Entry points 294 ******************************************************************************/ 295 296 /* ...process local/remote shared memory interface status change */ 297 void xf_shmem_process_queues(u32 core) 298 { 299 u32 status; 300 301 do 302 { 303 /* ...acknowledge/clear any pending incoming interrupt */ 304 XF_PROXY_SYNC_PEER(core); 305 306 /* ...send out pending response messages (frees message buffers, so do it first) */ 307 status = xf_shmem_process_output(core); 308 309 /* ...receive and forward incoming command messages (allocates message buffers) */ 310 status |= xf_shmem_process_input(core); 311 312 /* ...assert remote mailbox interrupt if global update bit is set */ 313 if (status & XF_PROXY_STATUS_REMOTE) 314 { 315 XF_PROXY_NOTIFY_PEER(core); 316 } 317 } 318 while (status); 319 } 320 321 /* ...completion callback for message originating from remote proxy */ 322 void xf_msg_proxy_complete(xf_message_t *m) 323 { 324 /* ...place message into proxy response queue */ 325 xf_msg_proxy_put(m); 326 } 327 328 /* ...initialize shared memory interface (DSP side) */ 329 int xf_shmem_init(u32 core) 330 { 331 xf_core_rw_data_t *rw = XF_CORE_RW_DATA(core); 332 xf_core_ro_data_t *ro = XF_CORE_RO_DATA(core); 333 334 /* ...initialize local/remote message queues */ 335 xf_msg_queue_init(&rw->local); 336 xf_msg_queue_init(&rw->remote); 337 338 /* ...initialize global message list */ 339 XF_CHK_API(xf_msg_pool_init(&ro->pool, XF_CFG_MESSAGE_POOL_SIZE, core)); 340 341 /* ...flush memory content as needed */ 342 (XF_REMOTE_IPC_NON_COHERENT ? XF_PROXY_FLUSH(rw, sizeof(*rw)) : 0); 343 344 /* ...system-specific initialization of IPC layer */ 345 XF_CHK_API(xf_ipc_init(core)); 346 347 TRACE(INIT, _b("SHMEM-%u subsystem initialized"), core); 348 349 return 0; 350 } 351