1/* 2 * msg_sm.c 3 * 4 * DSP-BIOS Bridge driver support functions for TI OMAP processors. 5 * 6 * Implements upper edge functions for Bridge message module. 7 * 8 * Copyright (C) 2005-2006 Texas Instruments, Inc. 9 * 10 * This package is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 * 14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 17 */ 18#include <linux/types.h> 19 20/* ----------------------------------- DSP/BIOS Bridge */ 21#include <dspbridge/dbdefs.h> 22 23/* ----------------------------------- OS Adaptation Layer */ 24#include <dspbridge/sync.h> 25 26/* ----------------------------------- Platform Manager */ 27#include <dspbridge/dev.h> 28 29/* ----------------------------------- Others */ 30#include <dspbridge/io_sm.h> 31 32/* ----------------------------------- This */ 33#include <_msg_sm.h> 34#include <dspbridge/dspmsg.h> 35 36/* ----------------------------------- Function Prototypes */ 37static int add_new_msg(struct list_head *msg_list); 38static void delete_msg_mgr(struct msg_mgr *hmsg_mgr); 39static void delete_msg_queue(struct msg_queue *msg_queue_obj, u32 num_to_dsp); 40static void free_msg_list(struct list_head *msg_list); 41 42/* 43 * ======== bridge_msg_create ======== 44 * Create an object to manage message queues. Only one of these objects 45 * can exist per device object. 46 */ 47int bridge_msg_create(struct msg_mgr **msg_man, 48 struct dev_object *hdev_obj, 49 msg_onexit msg_callback) 50{ 51 struct msg_mgr *msg_mgr_obj; 52 struct io_mgr *hio_mgr; 53 int status = 0; 54 55 if (!msg_man || !msg_callback || !hdev_obj) 56 return -EFAULT; 57 58 dev_get_io_mgr(hdev_obj, &hio_mgr); 59 if (!hio_mgr) 60 return -EFAULT; 61 62 *msg_man = NULL; 63 /* Allocate msg_ctrl manager object */ 64 msg_mgr_obj = kzalloc(sizeof(struct msg_mgr), GFP_KERNEL); 65 if (!msg_mgr_obj) 66 return -ENOMEM; 67 68 msg_mgr_obj->on_exit = msg_callback; 69 msg_mgr_obj->iomgr = hio_mgr; 70 /* List of MSG_QUEUEs */ 71 INIT_LIST_HEAD(&msg_mgr_obj->queue_list); 72 /* 73 * Queues of message frames for messages to the DSP. Message 74 * frames will only be added to the free queue when a 75 * msg_queue object is created. 76 */ 77 INIT_LIST_HEAD(&msg_mgr_obj->msg_free_list); 78 INIT_LIST_HEAD(&msg_mgr_obj->msg_used_list); 79 spin_lock_init(&msg_mgr_obj->msg_mgr_lock); 80 81 /* 82 * Create an event to be used by bridge_msg_put() in waiting 83 * for an available free frame from the message manager. 84 */ 85 msg_mgr_obj->sync_event = 86 kzalloc(sizeof(struct sync_object), GFP_KERNEL); 87 if (!msg_mgr_obj->sync_event) { 88 kfree(msg_mgr_obj); 89 return -ENOMEM; 90 } 91 sync_init_event(msg_mgr_obj->sync_event); 92 93 *msg_man = msg_mgr_obj; 94 95 return status; 96} 97 98/* 99 * ======== bridge_msg_create_queue ======== 100 * Create a msg_queue for sending/receiving messages to/from a node 101 * on the DSP. 102 */ 103int bridge_msg_create_queue(struct msg_mgr *hmsg_mgr, struct msg_queue **msgq, 104 u32 msgq_id, u32 max_msgs, void *arg) 105{ 106 u32 i; 107 u32 num_allocated = 0; 108 struct msg_queue *msg_q; 109 int status = 0; 110 111 if (!hmsg_mgr || msgq == NULL) 112 return -EFAULT; 113 114 *msgq = NULL; 115 /* Allocate msg_queue object */ 116 msg_q = kzalloc(sizeof(struct msg_queue), GFP_KERNEL); 117 if (!msg_q) 118 return -ENOMEM; 119 120 msg_q->max_msgs = max_msgs; 121 msg_q->msg_mgr = hmsg_mgr; 122 msg_q->arg = arg; /* Node handle */ 123 msg_q->msgq_id = msgq_id; /* Node env (not valid yet) */ 124 /* Queues of Message frames for messages from the DSP */ 125 INIT_LIST_HEAD(&msg_q->msg_free_list); 126 INIT_LIST_HEAD(&msg_q->msg_used_list); 127 128 /* Create event that will be signalled when a message from 129 * the DSP is available. */ 130 msg_q->sync_event = kzalloc(sizeof(struct sync_object), GFP_KERNEL); 131 if (!msg_q->sync_event) { 132 status = -ENOMEM; 133 goto out_err; 134 135 } 136 sync_init_event(msg_q->sync_event); 137 138 /* Create a notification list for message ready notification. */ 139 msg_q->ntfy_obj = kmalloc(sizeof(struct ntfy_object), GFP_KERNEL); 140 if (!msg_q->ntfy_obj) { 141 status = -ENOMEM; 142 goto out_err; 143 } 144 ntfy_init(msg_q->ntfy_obj); 145 146 /* Create events that will be used to synchronize cleanup 147 * when the object is deleted. sync_done will be set to 148 * unblock threads in MSG_Put() or MSG_Get(). sync_done_ack 149 * will be set by the unblocked thread to signal that it 150 * is unblocked and will no longer reference the object. */ 151 msg_q->sync_done = kzalloc(sizeof(struct sync_object), GFP_KERNEL); 152 if (!msg_q->sync_done) { 153 status = -ENOMEM; 154 goto out_err; 155 } 156 sync_init_event(msg_q->sync_done); 157 158 msg_q->sync_done_ack = kzalloc(sizeof(struct sync_object), GFP_KERNEL); 159 if (!msg_q->sync_done_ack) { 160 status = -ENOMEM; 161 goto out_err; 162 } 163 sync_init_event(msg_q->sync_done_ack); 164 165 /* Enter critical section */ 166 spin_lock_bh(&hmsg_mgr->msg_mgr_lock); 167 /* Initialize message frames and put in appropriate queues */ 168 for (i = 0; i < max_msgs && !status; i++) { 169 status = add_new_msg(&hmsg_mgr->msg_free_list); 170 if (!status) { 171 num_allocated++; 172 status = add_new_msg(&msg_q->msg_free_list); 173 } 174 } 175 if (status) { 176 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 177 goto out_err; 178 } 179 180 list_add_tail(&msg_q->list_elem, &hmsg_mgr->queue_list); 181 *msgq = msg_q; 182 /* Signal that free frames are now available */ 183 if (!list_empty(&hmsg_mgr->msg_free_list)) 184 sync_set_event(hmsg_mgr->sync_event); 185 186 /* Exit critical section */ 187 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 188 189 return 0; 190out_err: 191 delete_msg_queue(msg_q, num_allocated); 192 return status; 193} 194 195/* 196 * ======== bridge_msg_delete ======== 197 * Delete a msg_ctrl manager allocated in bridge_msg_create(). 198 */ 199void bridge_msg_delete(struct msg_mgr *hmsg_mgr) 200{ 201 if (hmsg_mgr) 202 delete_msg_mgr(hmsg_mgr); 203} 204 205/* 206 * ======== bridge_msg_delete_queue ======== 207 * Delete a msg_ctrl queue allocated in bridge_msg_create_queue. 208 */ 209void bridge_msg_delete_queue(struct msg_queue *msg_queue_obj) 210{ 211 struct msg_mgr *hmsg_mgr; 212 u32 io_msg_pend; 213 214 if (!msg_queue_obj || !msg_queue_obj->msg_mgr) 215 return; 216 217 hmsg_mgr = msg_queue_obj->msg_mgr; 218 msg_queue_obj->done = true; 219 /* Unblock all threads blocked in MSG_Get() or MSG_Put(). */ 220 io_msg_pend = msg_queue_obj->io_msg_pend; 221 while (io_msg_pend) { 222 /* Unblock thread */ 223 sync_set_event(msg_queue_obj->sync_done); 224 /* Wait for acknowledgement */ 225 sync_wait_on_event(msg_queue_obj->sync_done_ack, SYNC_INFINITE); 226 io_msg_pend = msg_queue_obj->io_msg_pend; 227 } 228 /* Remove message queue from hmsg_mgr->queue_list */ 229 spin_lock_bh(&hmsg_mgr->msg_mgr_lock); 230 list_del(&msg_queue_obj->list_elem); 231 /* Free the message queue object */ 232 delete_msg_queue(msg_queue_obj, msg_queue_obj->max_msgs); 233 if (list_empty(&hmsg_mgr->msg_free_list)) 234 sync_reset_event(hmsg_mgr->sync_event); 235 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 236} 237 238/* 239 * ======== bridge_msg_get ======== 240 * Get a message from a msg_ctrl queue. 241 */ 242int bridge_msg_get(struct msg_queue *msg_queue_obj, 243 struct dsp_msg *pmsg, u32 utimeout) 244{ 245 struct msg_frame *msg_frame_obj; 246 struct msg_mgr *hmsg_mgr; 247 struct sync_object *syncs[2]; 248 u32 index; 249 int status = 0; 250 251 if (!msg_queue_obj || pmsg == NULL) 252 return -ENOMEM; 253 254 hmsg_mgr = msg_queue_obj->msg_mgr; 255 256 spin_lock_bh(&hmsg_mgr->msg_mgr_lock); 257 /* If a message is already there, get it */ 258 if (!list_empty(&msg_queue_obj->msg_used_list)) { 259 msg_frame_obj = list_first_entry(&msg_queue_obj->msg_used_list, 260 struct msg_frame, list_elem); 261 list_del(&msg_frame_obj->list_elem); 262 *pmsg = msg_frame_obj->msg_data.msg; 263 list_add_tail(&msg_frame_obj->list_elem, 264 &msg_queue_obj->msg_free_list); 265 if (list_empty(&msg_queue_obj->msg_used_list)) 266 sync_reset_event(msg_queue_obj->sync_event); 267 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 268 return 0; 269 } 270 271 if (msg_queue_obj->done) { 272 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 273 return -EPERM; 274 } 275 msg_queue_obj->io_msg_pend++; 276 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 277 278 /* 279 * Wait til message is available, timeout, or done. We don't 280 * have to schedule the DPC, since the DSP will send messages 281 * when they are available. 282 */ 283 syncs[0] = msg_queue_obj->sync_event; 284 syncs[1] = msg_queue_obj->sync_done; 285 status = sync_wait_on_multiple_events(syncs, 2, utimeout, &index); 286 287 spin_lock_bh(&hmsg_mgr->msg_mgr_lock); 288 if (msg_queue_obj->done) { 289 msg_queue_obj->io_msg_pend--; 290 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 291 /* 292 * Signal that we're not going to access msg_queue_obj 293 * anymore, so it can be deleted. 294 */ 295 sync_set_event(msg_queue_obj->sync_done_ack); 296 return -EPERM; 297 } 298 if (!status && !list_empty(&msg_queue_obj->msg_used_list)) { 299 /* Get msg from used list */ 300 msg_frame_obj = list_first_entry(&msg_queue_obj->msg_used_list, 301 struct msg_frame, list_elem); 302 list_del(&msg_frame_obj->list_elem); 303 /* Copy message into pmsg and put frame on the free list */ 304 *pmsg = msg_frame_obj->msg_data.msg; 305 list_add_tail(&msg_frame_obj->list_elem, 306 &msg_queue_obj->msg_free_list); 307 } 308 msg_queue_obj->io_msg_pend--; 309 /* Reset the event if there are still queued messages */ 310 if (!list_empty(&msg_queue_obj->msg_used_list)) 311 sync_set_event(msg_queue_obj->sync_event); 312 313 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 314 315 return status; 316} 317 318/* 319 * ======== bridge_msg_put ======== 320 * Put a message onto a msg_ctrl queue. 321 */ 322int bridge_msg_put(struct msg_queue *msg_queue_obj, 323 const struct dsp_msg *pmsg, u32 utimeout) 324{ 325 struct msg_frame *msg_frame_obj; 326 struct msg_mgr *hmsg_mgr; 327 struct sync_object *syncs[2]; 328 u32 index; 329 int status; 330 331 if (!msg_queue_obj || !pmsg || !msg_queue_obj->msg_mgr) 332 return -EFAULT; 333 334 hmsg_mgr = msg_queue_obj->msg_mgr; 335 336 spin_lock_bh(&hmsg_mgr->msg_mgr_lock); 337 338 /* If a message frame is available, use it */ 339 if (!list_empty(&hmsg_mgr->msg_free_list)) { 340 msg_frame_obj = list_first_entry(&hmsg_mgr->msg_free_list, 341 struct msg_frame, list_elem); 342 list_del(&msg_frame_obj->list_elem); 343 msg_frame_obj->msg_data.msg = *pmsg; 344 msg_frame_obj->msg_data.msgq_id = 345 msg_queue_obj->msgq_id; 346 list_add_tail(&msg_frame_obj->list_elem, 347 &hmsg_mgr->msg_used_list); 348 hmsg_mgr->msgs_pending++; 349 350 if (list_empty(&hmsg_mgr->msg_free_list)) 351 sync_reset_event(hmsg_mgr->sync_event); 352 353 /* Release critical section before scheduling DPC */ 354 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 355 /* Schedule a DPC, to do the actual data transfer: */ 356 iosm_schedule(hmsg_mgr->iomgr); 357 return 0; 358 } 359 360 if (msg_queue_obj->done) { 361 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 362 return -EPERM; 363 } 364 msg_queue_obj->io_msg_pend++; 365 366 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 367 368 /* Wait til a free message frame is available, timeout, or done */ 369 syncs[0] = hmsg_mgr->sync_event; 370 syncs[1] = msg_queue_obj->sync_done; 371 status = sync_wait_on_multiple_events(syncs, 2, utimeout, &index); 372 if (status) 373 return status; 374 375 /* Enter critical section */ 376 spin_lock_bh(&hmsg_mgr->msg_mgr_lock); 377 if (msg_queue_obj->done) { 378 msg_queue_obj->io_msg_pend--; 379 /* Exit critical section */ 380 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 381 /* 382 * Signal that we're not going to access msg_queue_obj 383 * anymore, so it can be deleted. 384 */ 385 sync_set_event(msg_queue_obj->sync_done_ack); 386 return -EPERM; 387 } 388 389 if (list_empty(&hmsg_mgr->msg_free_list)) { 390 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 391 return -EFAULT; 392 } 393 394 /* Get msg from free list */ 395 msg_frame_obj = list_first_entry(&hmsg_mgr->msg_free_list, 396 struct msg_frame, list_elem); 397 /* 398 * Copy message into pmsg and put frame on the 399 * used list. 400 */ 401 list_del(&msg_frame_obj->list_elem); 402 msg_frame_obj->msg_data.msg = *pmsg; 403 msg_frame_obj->msg_data.msgq_id = msg_queue_obj->msgq_id; 404 list_add_tail(&msg_frame_obj->list_elem, &hmsg_mgr->msg_used_list); 405 hmsg_mgr->msgs_pending++; 406 /* 407 * Schedule a DPC, to do the actual 408 * data transfer. 409 */ 410 iosm_schedule(hmsg_mgr->iomgr); 411 412 msg_queue_obj->io_msg_pend--; 413 /* Reset event if there are still frames available */ 414 if (!list_empty(&hmsg_mgr->msg_free_list)) 415 sync_set_event(hmsg_mgr->sync_event); 416 417 /* Exit critical section */ 418 spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); 419 420 return 0; 421} 422 423/* 424 * ======== bridge_msg_register_notify ======== 425 */ 426int bridge_msg_register_notify(struct msg_queue *msg_queue_obj, 427 u32 event_mask, u32 notify_type, 428 struct dsp_notification *hnotification) 429{ 430 int status = 0; 431 432 if (!msg_queue_obj || !hnotification) { 433 status = -ENOMEM; 434 goto func_end; 435 } 436 437 if (!(event_mask == DSP_NODEMESSAGEREADY || event_mask == 0)) { 438 status = -EPERM; 439 goto func_end; 440 } 441 442 if (notify_type != DSP_SIGNALEVENT) { 443 status = -EBADR; 444 goto func_end; 445 } 446 447 if (event_mask) 448 status = ntfy_register(msg_queue_obj->ntfy_obj, hnotification, 449 event_mask, notify_type); 450 else 451 status = ntfy_unregister(msg_queue_obj->ntfy_obj, 452 hnotification); 453 454 if (status == -EINVAL) { 455 /* Not registered. Ok, since we couldn't have known. Node 456 * notifications are split between node state change handled 457 * by NODE, and message ready handled by msg_ctrl. */ 458 status = 0; 459 } 460func_end: 461 return status; 462} 463 464/* 465 * ======== bridge_msg_set_queue_id ======== 466 */ 467void bridge_msg_set_queue_id(struct msg_queue *msg_queue_obj, u32 msgq_id) 468{ 469 /* 470 * A message queue must be created when a node is allocated, 471 * so that node_register_notify() can be called before the node 472 * is created. Since we don't know the node environment until the 473 * node is created, we need this function to set msg_queue_obj->msgq_id 474 * to the node environment, after the node is created. 475 */ 476 if (msg_queue_obj) 477 msg_queue_obj->msgq_id = msgq_id; 478} 479 480/* 481 * ======== add_new_msg ======== 482 * Must be called in message manager critical section. 483 */ 484static int add_new_msg(struct list_head *msg_list) 485{ 486 struct msg_frame *pmsg; 487 488 pmsg = kzalloc(sizeof(struct msg_frame), GFP_ATOMIC); 489 if (!pmsg) 490 return -ENOMEM; 491 492 list_add_tail(&pmsg->list_elem, msg_list); 493 494 return 0; 495} 496 497/* 498 * ======== delete_msg_mgr ======== 499 */ 500static void delete_msg_mgr(struct msg_mgr *hmsg_mgr) 501{ 502 if (!hmsg_mgr) 503 return; 504 505 /* FIXME: free elements from queue_list? */ 506 free_msg_list(&hmsg_mgr->msg_free_list); 507 free_msg_list(&hmsg_mgr->msg_used_list); 508 kfree(hmsg_mgr->sync_event); 509 kfree(hmsg_mgr); 510} 511 512/* 513 * ======== delete_msg_queue ======== 514 */ 515static void delete_msg_queue(struct msg_queue *msg_queue_obj, u32 num_to_dsp) 516{ 517 struct msg_mgr *hmsg_mgr; 518 struct msg_frame *pmsg, *tmp; 519 u32 i; 520 521 if (!msg_queue_obj || !msg_queue_obj->msg_mgr) 522 return; 523 524 hmsg_mgr = msg_queue_obj->msg_mgr; 525 526 /* Pull off num_to_dsp message frames from Msg manager and free */ 527 i = 0; 528 list_for_each_entry_safe(pmsg, tmp, &hmsg_mgr->msg_free_list, 529 list_elem) { 530 list_del(&pmsg->list_elem); 531 kfree(pmsg); 532 if (i++ >= num_to_dsp) 533 break; 534 } 535 536 free_msg_list(&msg_queue_obj->msg_free_list); 537 free_msg_list(&msg_queue_obj->msg_used_list); 538 539 if (msg_queue_obj->ntfy_obj) { 540 ntfy_delete(msg_queue_obj->ntfy_obj); 541 kfree(msg_queue_obj->ntfy_obj); 542 } 543 544 kfree(msg_queue_obj->sync_event); 545 kfree(msg_queue_obj->sync_done); 546 kfree(msg_queue_obj->sync_done_ack); 547 548 kfree(msg_queue_obj); 549} 550 551/* 552 * ======== free_msg_list ======== 553 */ 554static void free_msg_list(struct list_head *msg_list) 555{ 556 struct msg_frame *pmsg, *tmp; 557 558 if (!msg_list) 559 return; 560 561 list_for_each_entry_safe(pmsg, tmp, msg_list, list_elem) { 562 list_del(&pmsg->list_elem); 563 kfree(pmsg); 564 } 565} 566