1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/types.h>
20
21
22#include <dspbridge/host_os.h>
23
24
25#include <dspbridge/dbdefs.h>
26
27
28#include <dspbridge/dbc.h>
29
30
31#include <dspbridge/sync.h>
32
33
34#include <dspbridge/dspdefs.h>
35
36
37#include <dspbridge/nodepriv.h>
38
39
40#include <dspbridge/cmm.h>
41
42
43#include <dspbridge/strm.h>
44
45#include <dspbridge/resourcecleanup.h>
46
47
48#define DEFAULTTIMEOUT 10000
49#define DEFAULTNUMBUFS 2
50
51
52
53
54
55
56struct strm_mgr {
57 struct dev_object *dev_obj;
58 struct chnl_mgr *hchnl_mgr;
59
60 struct bridge_drv_interface *intf_fxns;
61};
62
63
64
65
66
67struct strm_object {
68 struct strm_mgr *strm_mgr_obj;
69 struct chnl_object *chnl_obj;
70 u32 dir;
71 u32 utimeout;
72 u32 num_bufs;
73 u32 un_bufs_in_strm;
74 u32 ul_n_bytes;
75
76 enum dsp_streamstate strm_state;
77 void *user_event;
78 enum dsp_strmmode strm_mode;
79 u32 udma_chnl_id;
80 u32 udma_priority;
81 u32 segment_id;
82 u32 buf_alignment;
83
84 struct cmm_xlatorobject *xlator;
85};
86
87
88static u32 refs;
89
90
91static int delete_strm(struct strm_object *stream_obj);
92
93
94
95
96
97
98int strm_allocate_buffer(struct strm_res_object *strmres, u32 usize,
99 u8 **ap_buffer, u32 num_bufs,
100 struct process_context *pr_ctxt)
101{
102 int status = 0;
103 u32 alloc_cnt = 0;
104 u32 i;
105 struct strm_object *stream_obj = strmres->hstream;
106
107 DBC_REQUIRE(refs > 0);
108 DBC_REQUIRE(ap_buffer != NULL);
109
110 if (stream_obj) {
111
112
113
114 if (usize == 0)
115 status = -EINVAL;
116
117 } else {
118 status = -EFAULT;
119 }
120
121 if (status)
122 goto func_end;
123
124 for (i = 0; i < num_bufs; i++) {
125 DBC_ASSERT(stream_obj->xlator != NULL);
126 (void)cmm_xlator_alloc_buf(stream_obj->xlator, &ap_buffer[i],
127 usize);
128 if (ap_buffer[i] == NULL) {
129 status = -ENOMEM;
130 alloc_cnt = i;
131 break;
132 }
133 }
134 if (status)
135 strm_free_buffer(strmres, ap_buffer, alloc_cnt, pr_ctxt);
136
137 if (status)
138 goto func_end;
139
140 drv_proc_update_strm_res(num_bufs, strmres);
141
142func_end:
143 return status;
144}
145
146
147
148
149
150
151int strm_close(struct strm_res_object *strmres,
152 struct process_context *pr_ctxt)
153{
154 struct bridge_drv_interface *intf_fxns;
155 struct chnl_info chnl_info_obj;
156 int status = 0;
157 struct strm_object *stream_obj = strmres->hstream;
158
159 DBC_REQUIRE(refs > 0);
160
161 if (!stream_obj) {
162 status = -EFAULT;
163 } else {
164
165
166 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
167 status =
168 (*intf_fxns->pfn_chnl_get_info) (stream_obj->chnl_obj,
169 &chnl_info_obj);
170 DBC_ASSERT(!status);
171
172 if (chnl_info_obj.cio_cs > 0 || chnl_info_obj.cio_reqs > 0)
173 status = -EPIPE;
174 else
175 status = delete_strm(stream_obj);
176 }
177
178 if (status)
179 goto func_end;
180
181 idr_remove(pr_ctxt->stream_id, strmres->id);
182func_end:
183 DBC_ENSURE(status == 0 || status == -EFAULT ||
184 status == -EPIPE || status == -EPERM);
185
186 dev_dbg(bridge, "%s: stream_obj: %p, status 0x%x\n", __func__,
187 stream_obj, status);
188 return status;
189}
190
191
192
193
194
195
196int strm_create(struct strm_mgr **strm_man,
197 struct dev_object *dev_obj)
198{
199 struct strm_mgr *strm_mgr_obj;
200 int status = 0;
201
202 DBC_REQUIRE(refs > 0);
203 DBC_REQUIRE(strm_man != NULL);
204 DBC_REQUIRE(dev_obj != NULL);
205
206 *strm_man = NULL;
207
208 strm_mgr_obj = kzalloc(sizeof(struct strm_mgr), GFP_KERNEL);
209 if (strm_mgr_obj == NULL)
210 status = -ENOMEM;
211 else
212 strm_mgr_obj->dev_obj = dev_obj;
213
214
215 if (!status) {
216 status = dev_get_chnl_mgr(dev_obj, &(strm_mgr_obj->hchnl_mgr));
217 if (!status) {
218 (void)dev_get_intf_fxns(dev_obj,
219 &(strm_mgr_obj->intf_fxns));
220 DBC_ASSERT(strm_mgr_obj->intf_fxns != NULL);
221 }
222 }
223
224 if (!status)
225 *strm_man = strm_mgr_obj;
226 else
227 kfree(strm_mgr_obj);
228
229 DBC_ENSURE((!status && *strm_man) || (status && *strm_man == NULL));
230
231 return status;
232}
233
234
235
236
237
238
239void strm_delete(struct strm_mgr *strm_mgr_obj)
240{
241 DBC_REQUIRE(refs > 0);
242 DBC_REQUIRE(strm_mgr_obj);
243
244 kfree(strm_mgr_obj);
245}
246
247
248
249
250
251
252void strm_exit(void)
253{
254 DBC_REQUIRE(refs > 0);
255
256 refs--;
257
258 DBC_ENSURE(refs >= 0);
259}
260
261
262
263
264
265
266int strm_free_buffer(struct strm_res_object *strmres, u8 ** ap_buffer,
267 u32 num_bufs, struct process_context *pr_ctxt)
268{
269 int status = 0;
270 u32 i = 0;
271 struct strm_object *stream_obj = strmres->hstream;
272
273 DBC_REQUIRE(refs > 0);
274 DBC_REQUIRE(ap_buffer != NULL);
275
276 if (!stream_obj)
277 status = -EFAULT;
278
279 if (!status) {
280 for (i = 0; i < num_bufs; i++) {
281 DBC_ASSERT(stream_obj->xlator != NULL);
282 status =
283 cmm_xlator_free_buf(stream_obj->xlator,
284 ap_buffer[i]);
285 if (status)
286 break;
287 ap_buffer[i] = NULL;
288 }
289 }
290 drv_proc_update_strm_res(num_bufs - i, strmres);
291
292 return status;
293}
294
295
296
297
298
299
300int strm_get_info(struct strm_object *stream_obj,
301 struct stream_info *stream_info,
302 u32 stream_info_size)
303{
304 struct bridge_drv_interface *intf_fxns;
305 struct chnl_info chnl_info_obj;
306 int status = 0;
307 void *virt_base = NULL;
308
309 DBC_REQUIRE(refs > 0);
310 DBC_REQUIRE(stream_info != NULL);
311 DBC_REQUIRE(stream_info_size >= sizeof(struct stream_info));
312
313 if (!stream_obj) {
314 status = -EFAULT;
315 } else {
316 if (stream_info_size < sizeof(struct stream_info)) {
317
318 status = -EINVAL;
319 }
320 }
321 if (status)
322 goto func_end;
323
324 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
325 status =
326 (*intf_fxns->pfn_chnl_get_info) (stream_obj->chnl_obj,
327 &chnl_info_obj);
328 if (status)
329 goto func_end;
330
331 if (stream_obj->xlator) {
332
333 DBC_ASSERT(stream_obj->segment_id > 0);
334 cmm_xlator_info(stream_obj->xlator, (u8 **) &virt_base, 0,
335 stream_obj->segment_id, false);
336 }
337 stream_info->segment_id = stream_obj->segment_id;
338 stream_info->strm_mode = stream_obj->strm_mode;
339 stream_info->virt_base = virt_base;
340 stream_info->user_strm->number_bufs_allowed = stream_obj->num_bufs;
341 stream_info->user_strm->number_bufs_in_stream = chnl_info_obj.cio_cs +
342 chnl_info_obj.cio_reqs;
343
344 stream_info->user_strm->ul_number_bytes = chnl_info_obj.bytes_tx;
345 stream_info->user_strm->sync_object_handle = chnl_info_obj.event_obj;
346
347 if (chnl_info_obj.dw_state & CHNL_STATEEOS) {
348 stream_info->user_strm->ss_stream_state = STREAM_DONE;
349 } else {
350 if (chnl_info_obj.cio_cs > 0)
351 stream_info->user_strm->ss_stream_state = STREAM_READY;
352 else if (chnl_info_obj.cio_reqs > 0)
353 stream_info->user_strm->ss_stream_state =
354 STREAM_PENDING;
355 else
356 stream_info->user_strm->ss_stream_state = STREAM_IDLE;
357
358 }
359func_end:
360 return status;
361}
362
363
364
365
366
367
368int strm_idle(struct strm_object *stream_obj, bool flush_data)
369{
370 struct bridge_drv_interface *intf_fxns;
371 int status = 0;
372
373 DBC_REQUIRE(refs > 0);
374
375 if (!stream_obj) {
376 status = -EFAULT;
377 } else {
378 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
379
380 status = (*intf_fxns->pfn_chnl_idle) (stream_obj->chnl_obj,
381 stream_obj->utimeout,
382 flush_data);
383 }
384
385 dev_dbg(bridge, "%s: stream_obj: %p flush_data: 0x%x status: 0x%x\n",
386 __func__, stream_obj, flush_data, status);
387 return status;
388}
389
390
391
392
393
394
395bool strm_init(void)
396{
397 bool ret = true;
398
399 DBC_REQUIRE(refs >= 0);
400
401 if (ret)
402 refs++;
403
404 DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
405
406 return ret;
407}
408
409
410
411
412
413
414int strm_issue(struct strm_object *stream_obj, u8 *pbuf, u32 ul_bytes,
415 u32 ul_buf_size, u32 dw_arg)
416{
417 struct bridge_drv_interface *intf_fxns;
418 int status = 0;
419 void *tmp_buf = NULL;
420
421 DBC_REQUIRE(refs > 0);
422 DBC_REQUIRE(pbuf != NULL);
423
424 if (!stream_obj) {
425 status = -EFAULT;
426 } else {
427 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
428
429 if (stream_obj->segment_id != 0) {
430 tmp_buf = cmm_xlator_translate(stream_obj->xlator,
431 (void *)pbuf,
432 CMM_VA2DSPPA);
433 if (tmp_buf == NULL)
434 status = -ESRCH;
435
436 }
437 if (!status) {
438 status = (*intf_fxns->pfn_chnl_add_io_req)
439 (stream_obj->chnl_obj, pbuf, ul_bytes, ul_buf_size,
440 (u32) tmp_buf, dw_arg);
441 }
442 if (status == -EIO)
443 status = -ENOSR;
444 }
445
446 dev_dbg(bridge, "%s: stream_obj: %p pbuf: %p ul_bytes: 0x%x dw_arg:"
447 " 0x%x status: 0x%x\n", __func__, stream_obj, pbuf,
448 ul_bytes, dw_arg, status);
449 return status;
450}
451
452
453
454
455
456
457
458int strm_open(struct node_object *hnode, u32 dir, u32 index,
459 struct strm_attr *pattr,
460 struct strm_res_object **strmres,
461 struct process_context *pr_ctxt)
462{
463 struct strm_mgr *strm_mgr_obj;
464 struct bridge_drv_interface *intf_fxns;
465 u32 ul_chnl_id;
466 struct strm_object *strm_obj = NULL;
467 s8 chnl_mode;
468 struct chnl_attr chnl_attr_obj;
469 int status = 0;
470 struct cmm_object *hcmm_mgr = NULL;
471
472 void *stream_res;
473
474 DBC_REQUIRE(refs > 0);
475 DBC_REQUIRE(strmres != NULL);
476 DBC_REQUIRE(pattr != NULL);
477 *strmres = NULL;
478 if (dir != DSP_TONODE && dir != DSP_FROMNODE) {
479 status = -EPERM;
480 } else {
481
482 status = node_get_channel_id(hnode, dir, index, &ul_chnl_id);
483 }
484 if (!status)
485 status = node_get_strm_mgr(hnode, &strm_mgr_obj);
486
487 if (!status) {
488 strm_obj = kzalloc(sizeof(struct strm_object), GFP_KERNEL);
489 if (strm_obj == NULL) {
490 status = -ENOMEM;
491 } else {
492 strm_obj->strm_mgr_obj = strm_mgr_obj;
493 strm_obj->dir = dir;
494 strm_obj->strm_state = STREAM_IDLE;
495 strm_obj->user_event = pattr->user_event;
496 if (pattr->stream_attr_in != NULL) {
497 strm_obj->utimeout =
498 pattr->stream_attr_in->utimeout;
499 strm_obj->num_bufs =
500 pattr->stream_attr_in->num_bufs;
501 strm_obj->strm_mode =
502 pattr->stream_attr_in->strm_mode;
503 strm_obj->segment_id =
504 pattr->stream_attr_in->segment_id;
505 strm_obj->buf_alignment =
506 pattr->stream_attr_in->buf_alignment;
507 strm_obj->udma_chnl_id =
508 pattr->stream_attr_in->udma_chnl_id;
509 strm_obj->udma_priority =
510 pattr->stream_attr_in->udma_priority;
511 chnl_attr_obj.uio_reqs =
512 pattr->stream_attr_in->num_bufs;
513 } else {
514 strm_obj->utimeout = DEFAULTTIMEOUT;
515 strm_obj->num_bufs = DEFAULTNUMBUFS;
516 strm_obj->strm_mode = STRMMODE_PROCCOPY;
517 strm_obj->segment_id = 0;
518 strm_obj->buf_alignment = 0;
519 strm_obj->udma_chnl_id = 0;
520 strm_obj->udma_priority = 0;
521 chnl_attr_obj.uio_reqs = DEFAULTNUMBUFS;
522 }
523 chnl_attr_obj.reserved1 = NULL;
524
525 chnl_attr_obj.reserved2 = strm_obj->utimeout;
526 chnl_attr_obj.event_obj = NULL;
527 if (pattr->user_event != NULL)
528 chnl_attr_obj.event_obj = pattr->user_event;
529
530 }
531 }
532 if (status)
533 goto func_cont;
534
535 if ((pattr->virt_base == NULL) || !(pattr->ul_virt_size > 0))
536 goto func_cont;
537
538
539 DBC_ASSERT(strm_obj->strm_mode != STRMMODE_LDMA);
540
541 status = dev_get_cmm_mgr(strm_mgr_obj->dev_obj, &hcmm_mgr);
542 if (!status) {
543
544 status = cmm_xlator_create(&strm_obj->xlator, hcmm_mgr, NULL);
545 if (!status) {
546 DBC_ASSERT(strm_obj->segment_id > 0);
547
548 status = cmm_xlator_info(strm_obj->xlator,
549 (u8 **) &pattr->virt_base,
550 pattr->ul_virt_size,
551 strm_obj->segment_id, true);
552 }
553 }
554func_cont:
555 if (!status) {
556
557 chnl_mode = (dir == DSP_TONODE) ?
558 CHNL_MODETODSP : CHNL_MODEFROMDSP;
559 intf_fxns = strm_mgr_obj->intf_fxns;
560 status = (*intf_fxns->pfn_chnl_open) (&(strm_obj->chnl_obj),
561 strm_mgr_obj->hchnl_mgr,
562 chnl_mode, ul_chnl_id,
563 &chnl_attr_obj);
564 if (status) {
565
566
567
568
569 if (status != -ENOMEM && status !=
570 -EINVAL && status != -EPERM) {
571
572
573
574
575
576
577
578 DBC_ASSERT(status == -ENOSR ||
579 status == -ECHRNG ||
580 status == -EALREADY ||
581 status == -EIO);
582 status = -EPERM;
583 }
584 }
585 }
586 if (!status) {
587 status = drv_proc_insert_strm_res_element(strm_obj,
588 &stream_res, pr_ctxt);
589 if (status)
590 delete_strm(strm_obj);
591 else
592 *strmres = (struct strm_res_object *)stream_res;
593 } else {
594 (void)delete_strm(strm_obj);
595 }
596
597
598 DBC_ENSURE((!status && strm_obj) ||
599 (*strmres == NULL && (status == -EFAULT ||
600 status == -EPERM
601 || status == -EINVAL)));
602
603 dev_dbg(bridge, "%s: hnode: %p dir: 0x%x index: 0x%x pattr: %p "
604 "strmres: %p status: 0x%x\n", __func__,
605 hnode, dir, index, pattr, strmres, status);
606 return status;
607}
608
609
610
611
612
613
614int strm_reclaim(struct strm_object *stream_obj, u8 ** buf_ptr,
615 u32 *nbytes, u32 *buff_size, u32 *pdw_arg)
616{
617 struct bridge_drv_interface *intf_fxns;
618 struct chnl_ioc chnl_ioc_obj;
619 int status = 0;
620 void *tmp_buf = NULL;
621
622 DBC_REQUIRE(refs > 0);
623 DBC_REQUIRE(buf_ptr != NULL);
624 DBC_REQUIRE(nbytes != NULL);
625 DBC_REQUIRE(pdw_arg != NULL);
626
627 if (!stream_obj) {
628 status = -EFAULT;
629 goto func_end;
630 }
631 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
632
633 status =
634 (*intf_fxns->pfn_chnl_get_ioc) (stream_obj->chnl_obj,
635 stream_obj->utimeout,
636 &chnl_ioc_obj);
637 if (!status) {
638 *nbytes = chnl_ioc_obj.byte_size;
639 if (buff_size)
640 *buff_size = chnl_ioc_obj.buf_size;
641
642 *pdw_arg = chnl_ioc_obj.dw_arg;
643 if (!CHNL_IS_IO_COMPLETE(chnl_ioc_obj)) {
644 if (CHNL_IS_TIMED_OUT(chnl_ioc_obj)) {
645 status = -ETIME;
646 } else {
647
648 if (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
649 status = -EPERM;
650
651 }
652 }
653
654 if (!status
655 && (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
656 && (stream_obj->strm_mode == STRMMODE_ZEROCOPY)) {
657
658
659
660
661
662
663
664 tmp_buf = cmm_xlator_translate(stream_obj->xlator,
665 chnl_ioc_obj.pbuf,
666 CMM_DSPPA2PA);
667 if (tmp_buf != NULL) {
668
669 tmp_buf = cmm_xlator_translate(stream_obj->
670 xlator,
671 tmp_buf,
672 CMM_PA2VA);
673 }
674 if (tmp_buf == NULL)
675 status = -ESRCH;
676
677 chnl_ioc_obj.pbuf = tmp_buf;
678 }
679 *buf_ptr = chnl_ioc_obj.pbuf;
680 }
681func_end:
682
683 DBC_ENSURE(!status || status == -EFAULT ||
684 status == -ETIME || status == -ESRCH ||
685 status == -EPERM);
686
687 dev_dbg(bridge, "%s: stream_obj: %p buf_ptr: %p nbytes: %p "
688 "pdw_arg: %p status 0x%x\n", __func__, stream_obj,
689 buf_ptr, nbytes, pdw_arg, status);
690 return status;
691}
692
693
694
695
696
697
698int strm_register_notify(struct strm_object *stream_obj, u32 event_mask,
699 u32 notify_type, struct dsp_notification
700 * hnotification)
701{
702 struct bridge_drv_interface *intf_fxns;
703 int status = 0;
704
705 DBC_REQUIRE(refs > 0);
706 DBC_REQUIRE(hnotification != NULL);
707
708 if (!stream_obj) {
709 status = -EFAULT;
710 } else if ((event_mask & ~((DSP_STREAMIOCOMPLETION) |
711 DSP_STREAMDONE)) != 0) {
712 status = -EINVAL;
713 } else {
714 if (notify_type != DSP_SIGNALEVENT)
715 status = -ENOSYS;
716
717 }
718 if (!status) {
719 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
720
721 status =
722 (*intf_fxns->pfn_chnl_register_notify) (stream_obj->
723 chnl_obj,
724 event_mask,
725 notify_type,
726 hnotification);
727 }
728
729 DBC_ENSURE(!status || status == -EFAULT ||
730 status == -ETIME || status == -ESRCH ||
731 status == -ENOSYS || status == -EPERM);
732 return status;
733}
734
735
736
737
738
739
740int strm_select(struct strm_object **strm_tab, u32 strms,
741 u32 *pmask, u32 utimeout)
742{
743 u32 index;
744 struct chnl_info chnl_info_obj;
745 struct bridge_drv_interface *intf_fxns;
746 struct sync_object **sync_events = NULL;
747 u32 i;
748 int status = 0;
749
750 DBC_REQUIRE(refs > 0);
751 DBC_REQUIRE(strm_tab != NULL);
752 DBC_REQUIRE(pmask != NULL);
753 DBC_REQUIRE(strms > 0);
754
755 *pmask = 0;
756 for (i = 0; i < strms; i++) {
757 if (!strm_tab[i]) {
758 status = -EFAULT;
759 break;
760 }
761 }
762 if (status)
763 goto func_end;
764
765
766 for (i = 0; i < strms; i++) {
767 intf_fxns = strm_tab[i]->strm_mgr_obj->intf_fxns;
768 status = (*intf_fxns->pfn_chnl_get_info) (strm_tab[i]->chnl_obj,
769 &chnl_info_obj);
770 if (status) {
771 break;
772 } else {
773 if (chnl_info_obj.cio_cs > 0)
774 *pmask |= (1 << i);
775
776 }
777 }
778 if (!status && utimeout > 0 && *pmask == 0) {
779
780 sync_events = kmalloc(strms * sizeof(struct sync_object *),
781 GFP_KERNEL);
782
783 if (sync_events == NULL) {
784 status = -ENOMEM;
785 } else {
786 for (i = 0; i < strms; i++) {
787 intf_fxns =
788 strm_tab[i]->strm_mgr_obj->intf_fxns;
789 status = (*intf_fxns->pfn_chnl_get_info)
790 (strm_tab[i]->chnl_obj, &chnl_info_obj);
791 if (status)
792 break;
793 else
794 sync_events[i] =
795 chnl_info_obj.sync_event;
796
797 }
798 }
799 if (!status) {
800 status =
801 sync_wait_on_multiple_events(sync_events, strms,
802 utimeout, &index);
803 if (!status) {
804
805
806 sync_set_event(sync_events[index]);
807 *pmask = 1 << index;
808 }
809 }
810 }
811func_end:
812 kfree(sync_events);
813
814 DBC_ENSURE((!status && (*pmask != 0 || utimeout == 0)) ||
815 (status && *pmask == 0));
816
817 return status;
818}
819
820
821
822
823
824
825static int delete_strm(struct strm_object *stream_obj)
826{
827 struct bridge_drv_interface *intf_fxns;
828 int status = 0;
829
830 if (stream_obj) {
831 if (stream_obj->chnl_obj) {
832 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
833
834
835 status = (*intf_fxns->pfn_chnl_close)
836 (stream_obj->chnl_obj);
837 }
838
839 kfree(stream_obj->xlator);
840 kfree(stream_obj);
841 } else {
842 status = -EFAULT;
843 }
844 return status;
845}
846