]> Pileus Git - ~andy/linux/blob - drivers/staging/tidspbridge/core/msg_sm.c
Merge branch 'x86-boot-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[~andy/linux] / drivers / staging / tidspbridge / core / msg_sm.c
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 */
37 static int add_new_msg(struct list_head *msg_list);
38 static void delete_msg_mgr(struct msg_mgr *hmsg_mgr);
39 static void delete_msg_queue(struct msg_queue *msg_queue_obj, u32 num_to_dsp);
40 static 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  */
47 int 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  */
103 int 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;
190 out_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  */
199 void 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  */
209 void 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  */
242 int 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  */
322 int 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  */
426 int 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         }
460 func_end:
461         return status;
462 }
463
464 /*
465  *  ======== bridge_msg_set_queue_id ========
466  */
467 void 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  */
484 static 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  */
500 static 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  */
515 static 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  */
554 static 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 }