staging: ti dspbridge: use processor handle from context instead of user's
[deliverable/linux.git] / drivers / staging / tidspbridge / rmgr / drv.c
CommitLineData
7d55524d
ORL
1/*
2 * drv.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * DSP/BIOS Bridge resource allocation 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 */
2094f12d 18#include <linux/types.h>
7d55524d
ORL
19
20/* ----------------------------------- Host OS */
21#include <dspbridge/host_os.h>
22
23/* ----------------------------------- DSP/BIOS Bridge */
7d55524d
ORL
24#include <dspbridge/dbdefs.h>
25
26/* ----------------------------------- Trace & Debug */
27#include <dspbridge/dbc.h>
28
29/* ----------------------------------- OS Adaptation Layer */
30#include <dspbridge/cfg.h>
31#include <dspbridge/list.h>
32
33/* ----------------------------------- This */
34#include <dspbridge/drv.h>
35#include <dspbridge/dev.h>
36
37#include <dspbridge/node.h>
38#include <dspbridge/proc.h>
39#include <dspbridge/strm.h>
40#include <dspbridge/nodepriv.h>
41#include <dspbridge/dspchnl.h>
42#include <dspbridge/resourcecleanup.h>
43
44/* ----------------------------------- Defines, Data Structures, Typedefs */
45struct drv_object {
46 struct lst_list *dev_list;
47 struct lst_list *dev_node_string;
48};
49
50/*
51 * This is the Device Extension. Named with the Prefix
52 * DRV_ since it is living in this module
53 */
54struct drv_ext {
55 struct list_head link;
56 char sz_string[MAXREGPATHLENGTH];
57};
58
59/* ----------------------------------- Globals */
60static s32 refs;
61static bool ext_phys_mem_pool_enabled;
62struct ext_phys_mem_pool {
63 u32 phys_mem_base;
64 u32 phys_mem_size;
65 u32 virt_mem_base;
66 u32 next_phys_alloc_ptr;
67};
68static struct ext_phys_mem_pool ext_mem_pool;
69
70/* ----------------------------------- Function Prototypes */
71static int request_bridge_resources(struct cfg_hostres *res);
72
73
74/* GPP PROCESS CLEANUP CODE */
75
0624f52f 76static int drv_proc_free_node_res(int id, void *p, void *data);
7d55524d
ORL
77
78/* Allocate and add a node resource element
79* This function is called from .Node_Allocate. */
e6890692
RS
80int drv_insert_node_res_element(void *hnode, void *node_resource,
81 void *process_ctxt)
7d55524d
ORL
82{
83 struct node_res_object **node_res_obj =
e6890692
RS
84 (struct node_res_object **)node_resource;
85 struct process_context *ctxt = (struct process_context *)process_ctxt;
7d55524d 86 int status = 0;
0624f52f 87 int retval;
7d55524d
ORL
88
89 *node_res_obj = kzalloc(sizeof(struct node_res_object), GFP_KERNEL);
0624f52f
ER
90 if (!*node_res_obj) {
91 status = -ENOMEM;
92 goto func_end;
93 }
7d55524d 94
0624f52f
ER
95 (*node_res_obj)->hnode = hnode;
96 retval = idr_get_new(ctxt->node_id, *node_res_obj,
97 &(*node_res_obj)->id);
98 if (retval == -EAGAIN) {
99 if (!idr_pre_get(ctxt->node_id, GFP_KERNEL)) {
100 pr_err("%s: OUT OF MEMORY\n", __func__);
101 status = -ENOMEM;
102 goto func_end;
7d55524d 103 }
7d55524d 104
0624f52f
ER
105 retval = idr_get_new(ctxt->node_id, *node_res_obj,
106 &(*node_res_obj)->id);
107 }
108 if (retval) {
109 pr_err("%s: FAILED, IDR is FULL\n", __func__);
110 status = -EFAULT;
7d55524d 111 }
0624f52f
ER
112func_end:
113 if (status)
114 kfree(*node_res_obj);
7d55524d
ORL
115
116 return status;
117}
118
119/* Release all Node resources and its context
0624f52f
ER
120 * Actual Node De-Allocation */
121static int drv_proc_free_node_res(int id, void *p, void *data)
7d55524d 122{
0624f52f
ER
123 struct process_context *ctxt = data;
124 int status;
125 struct node_res_object *node_res_obj = p;
7d55524d
ORL
126 u32 node_state;
127
0624f52f
ER
128 if (node_res_obj->node_allocated) {
129 node_state = node_get_state(node_res_obj->hnode);
130 if (node_state <= NODE_DELETING) {
131 if ((node_state == NODE_RUNNING) ||
132 (node_state == NODE_PAUSED) ||
133 (node_state == NODE_TERMINATING))
134 node_terminate
135 (node_res_obj->hnode, &status);
7d55524d 136
0624f52f 137 node_delete(node_res_obj, ctxt);
7d55524d
ORL
138 }
139 }
0624f52f
ER
140
141 return 0;
7d55524d
ORL
142}
143
144/* Release all Mapped and Reserved DMM resources */
e6890692 145int drv_remove_all_dmm_res_elements(void *process_ctxt)
7d55524d 146{
e6890692 147 struct process_context *ctxt = (struct process_context *)process_ctxt;
7d55524d
ORL
148 int status = 0;
149 struct dmm_map_object *temp_map, *map_obj;
150 struct dmm_rsv_object *temp_rsv, *rsv_obj;
151
152 /* Free DMM mapped memory resources */
153 list_for_each_entry_safe(map_obj, temp_map, &ctxt->dmm_map_list, link) {
154 status = proc_un_map(ctxt->hprocessor,
155 (void *)map_obj->dsp_addr, ctxt);
b66e0986 156 if (status)
7d55524d
ORL
157 pr_err("%s: proc_un_map failed!"
158 " status = 0x%xn", __func__, status);
159 }
160
161 /* Free DMM reserved memory resources */
162 list_for_each_entry_safe(rsv_obj, temp_rsv, &ctxt->dmm_rsv_list, link) {
163 status = proc_un_reserve_memory(ctxt->hprocessor, (void *)
164 rsv_obj->dsp_reserved_addr,
165 ctxt);
b66e0986 166 if (status)
7d55524d
ORL
167 pr_err("%s: proc_un_reserve_memory failed!"
168 " status = 0x%xn", __func__, status);
169 }
170 return status;
171}
172
173/* Update Node allocation status */
e6890692 174void drv_proc_node_update_status(void *node_resource, s32 status)
7d55524d
ORL
175{
176 struct node_res_object *node_res_obj =
e6890692
RS
177 (struct node_res_object *)node_resource;
178 DBC_ASSERT(node_resource != NULL);
7d55524d
ORL
179 node_res_obj->node_allocated = status;
180}
181
182/* Update Node Heap status */
e6890692 183void drv_proc_node_update_heap_status(void *node_resource, s32 status)
7d55524d
ORL
184{
185 struct node_res_object *node_res_obj =
e6890692
RS
186 (struct node_res_object *)node_resource;
187 DBC_ASSERT(node_resource != NULL);
7d55524d
ORL
188 node_res_obj->heap_allocated = status;
189}
190
191/* Release all Node resources and its context
192* This is called from .bridge_release.
193 */
e6890692 194int drv_remove_all_node_res_elements(void *process_ctxt)
7d55524d 195{
0624f52f 196 struct process_context *ctxt = process_ctxt;
7d55524d 197
0624f52f
ER
198 idr_for_each(ctxt->node_id, drv_proc_free_node_res, ctxt);
199 idr_destroy(ctxt->node_id);
7d55524d 200
0624f52f 201 return 0;
7d55524d
ORL
202}
203
204/* Allocate the STRM resource element
205* This is called after the actual resource is allocated
206 */
c8c1ad8c
RS
207int drv_proc_insert_strm_res_element(void *stream_obj,
208 void *strm_res, void *process_ctxt)
7d55524d
ORL
209{
210 struct strm_res_object **pstrm_res =
c8c1ad8c 211 (struct strm_res_object **)strm_res;
e6890692 212 struct process_context *ctxt = (struct process_context *)process_ctxt;
7d55524d
ORL
213 int status = 0;
214 struct strm_res_object *temp_strm_res = NULL;
215
216 *pstrm_res = kzalloc(sizeof(struct strm_res_object), GFP_KERNEL);
217 if (*pstrm_res == NULL)
218 status = -EFAULT;
219
a741ea6e 220 if (!status) {
7d55524d
ORL
221 if (mutex_lock_interruptible(&ctxt->strm_mutex)) {
222 kfree(*pstrm_res);
223 return -EPERM;
224 }
c8c1ad8c 225 (*pstrm_res)->hstream = stream_obj;
7d55524d
ORL
226 if (ctxt->pstrm_list != NULL) {
227 temp_strm_res = ctxt->pstrm_list;
228 while (temp_strm_res->next != NULL)
229 temp_strm_res = temp_strm_res->next;
230
231 temp_strm_res->next = *pstrm_res;
232 } else {
233 ctxt->pstrm_list = *pstrm_res;
234 }
235 mutex_unlock(&ctxt->strm_mutex);
236 }
237 return status;
238}
239
240/* Release Stream resource element context
241* This function called after the actual resource is freed
242 */
c8c1ad8c 243int drv_proc_remove_strm_res_element(void *strm_res, void *process_ctxt)
7d55524d 244{
c8c1ad8c 245 struct strm_res_object *pstrm_res = (struct strm_res_object *)strm_res;
e6890692 246 struct process_context *ctxt = (struct process_context *)process_ctxt;
7d55524d
ORL
247 struct strm_res_object *temp_strm_res;
248 int status = 0;
249
250 if (mutex_lock_interruptible(&ctxt->strm_mutex))
251 return -EPERM;
252 temp_strm_res = ctxt->pstrm_list;
253
254 if (ctxt->pstrm_list == pstrm_res) {
255 ctxt->pstrm_list = pstrm_res->next;
256 } else {
257 while (temp_strm_res && temp_strm_res->next != pstrm_res)
258 temp_strm_res = temp_strm_res->next;
259 if (temp_strm_res == NULL)
260 status = -ENOENT;
261 else
262 temp_strm_res->next = pstrm_res->next;
263 }
264 mutex_unlock(&ctxt->strm_mutex);
265 kfree(pstrm_res);
266 return status;
267}
268
269/* Release all Stream resources and its context
270* This is called from .bridge_release.
271 */
e6890692 272int drv_remove_all_strm_res_elements(void *process_ctxt)
7d55524d 273{
e6890692 274 struct process_context *ctxt = (struct process_context *)process_ctxt;
7d55524d
ORL
275 int status = 0;
276 struct strm_res_object *strm_res = NULL;
277 struct strm_res_object *strm_tmp = NULL;
278 struct stream_info strm_info;
279 struct dsp_streaminfo user;
280 u8 **ap_buffer = NULL;
281 u8 *buf_ptr;
282 u32 ul_bytes;
283 u32 dw_arg;
284 s32 ul_buf_size;
285
286 strm_tmp = ctxt->pstrm_list;
287 while (strm_tmp) {
288 strm_res = strm_tmp;
289 strm_tmp = strm_tmp->next;
290 if (strm_res->num_bufs) {
291 ap_buffer = kmalloc((strm_res->num_bufs *
292 sizeof(u8 *)), GFP_KERNEL);
293 if (ap_buffer) {
294 status = strm_free_buffer(strm_res->hstream,
295 ap_buffer,
296 strm_res->num_bufs,
297 ctxt);
298 kfree(ap_buffer);
299 }
300 }
301 strm_info.user_strm = &user;
302 user.number_bufs_in_stream = 0;
303 strm_get_info(strm_res->hstream, &strm_info, sizeof(strm_info));
304 while (user.number_bufs_in_stream--)
305 strm_reclaim(strm_res->hstream, &buf_ptr, &ul_bytes,
306 (u32 *) &ul_buf_size, &dw_arg);
307 status = strm_close(strm_res->hstream, ctxt);
308 }
309 return status;
310}
311
312/* Getting the stream resource element */
c8c1ad8c 313int drv_get_strm_res_element(void *stream_obj, void *strm_resources,
e6890692 314 void *process_ctxt)
7d55524d
ORL
315{
316 struct strm_res_object **strm_res =
c8c1ad8c 317 (struct strm_res_object **)strm_resources;
e6890692 318 struct process_context *ctxt = (struct process_context *)process_ctxt;
7d55524d
ORL
319 int status = 0;
320 struct strm_res_object *temp_strm2 = NULL;
321 struct strm_res_object *temp_strm;
322
323 if (mutex_lock_interruptible(&ctxt->strm_mutex))
324 return -EPERM;
325
326 temp_strm = ctxt->pstrm_list;
95870a88 327 while ((temp_strm != NULL) && (temp_strm->hstream != stream_obj)) {
7d55524d
ORL
328 temp_strm2 = temp_strm;
329 temp_strm = temp_strm->next;
330 }
331
332 mutex_unlock(&ctxt->strm_mutex);
333
334 if (temp_strm != NULL)
335 *strm_res = temp_strm;
336 else
337 status = -ENOENT;
338
339 return status;
340}
341
342/* Updating the stream resource element */
c8c1ad8c 343int drv_proc_update_strm_res(u32 num_bufs, void *strm_resources)
7d55524d
ORL
344{
345 int status = 0;
346 struct strm_res_object **strm_res =
c8c1ad8c 347 (struct strm_res_object **)strm_resources;
7d55524d
ORL
348
349 (*strm_res)->num_bufs = num_bufs;
350 return status;
351}
352
353/* GPP PROCESS CLEANUP CODE END */
354
355/*
356 * ======== = drv_create ======== =
357 * Purpose:
358 * DRV Object gets created only once during Driver Loading.
359 */
e6bf74f0 360int drv_create(struct drv_object **drv_obj)
7d55524d
ORL
361{
362 int status = 0;
363 struct drv_object *pdrv_object = NULL;
364
e436d07d 365 DBC_REQUIRE(drv_obj != NULL);
7d55524d
ORL
366 DBC_REQUIRE(refs > 0);
367
368 pdrv_object = kzalloc(sizeof(struct drv_object), GFP_KERNEL);
369 if (pdrv_object) {
370 /* Create and Initialize List of device objects */
371 pdrv_object->dev_list = kzalloc(sizeof(struct lst_list),
372 GFP_KERNEL);
373 if (pdrv_object->dev_list) {
374 /* Create and Initialize List of device Extension */
375 pdrv_object->dev_node_string =
376 kzalloc(sizeof(struct lst_list), GFP_KERNEL);
377 if (!(pdrv_object->dev_node_string)) {
378 status = -EPERM;
379 } else {
380 INIT_LIST_HEAD(&pdrv_object->
381 dev_node_string->head);
382 INIT_LIST_HEAD(&pdrv_object->dev_list->head);
383 }
384 } else {
385 status = -ENOMEM;
386 }
387 } else {
388 status = -ENOMEM;
389 }
390 /* Store the DRV Object in the Registry */
a741ea6e 391 if (!status)
7d55524d 392 status = cfg_set_object((u32) pdrv_object, REG_DRV_OBJECT);
a741ea6e 393 if (!status) {
e436d07d 394 *drv_obj = pdrv_object;
7d55524d
ORL
395 } else {
396 kfree(pdrv_object->dev_list);
397 kfree(pdrv_object->dev_node_string);
398 /* Free the DRV Object */
399 kfree(pdrv_object);
400 }
401
b66e0986 402 DBC_ENSURE(status || pdrv_object);
7d55524d
ORL
403 return status;
404}
405
406/*
407 * ======== drv_exit ========
408 * Purpose:
409 * Discontinue usage of the DRV module.
410 */
411void drv_exit(void)
412{
413 DBC_REQUIRE(refs > 0);
414
415 refs--;
416
417 DBC_ENSURE(refs >= 0);
418}
419
420/*
421 * ======== = drv_destroy ======== =
422 * purpose:
423 * Invoked during bridge de-initialization
424 */
e6890692 425int drv_destroy(struct drv_object *driver_obj)
7d55524d
ORL
426{
427 int status = 0;
e6890692 428 struct drv_object *pdrv_object = (struct drv_object *)driver_obj;
7d55524d
ORL
429
430 DBC_REQUIRE(refs > 0);
431 DBC_REQUIRE(pdrv_object);
432
433 /*
434 * Delete the List if it exists.Should not come here
435 * as the drv_remove_dev_object and the Last drv_request_resources
436 * removes the list if the lists are empty.
437 */
438 kfree(pdrv_object->dev_list);
439 kfree(pdrv_object->dev_node_string);
440 kfree(pdrv_object);
441 /* Update the DRV Object in Registry to be 0 */
442 (void)cfg_set_object(0, REG_DRV_OBJECT);
443
444 return status;
445}
446
447/*
448 * ======== drv_get_dev_object ========
449 * Purpose:
450 * Given a index, returns a handle to DevObject from the list.
451 */
452int drv_get_dev_object(u32 index, struct drv_object *hdrv_obj,
e436d07d 453 struct dev_object **device_obj)
7d55524d
ORL
454{
455 int status = 0;
b3d23688 456#ifdef CONFIG_TIDSPBRIDGE_DEBUG
7d55524d
ORL
457 /* used only for Assertions and debug messages */
458 struct drv_object *pdrv_obj = (struct drv_object *)hdrv_obj;
459#endif
460 struct dev_object *dev_obj;
461 u32 i;
462 DBC_REQUIRE(pdrv_obj);
e436d07d 463 DBC_REQUIRE(device_obj != NULL);
7d55524d
ORL
464 DBC_REQUIRE(index >= 0);
465 DBC_REQUIRE(refs > 0);
466 DBC_ASSERT(!(LST_IS_EMPTY(pdrv_obj->dev_list)));
467
468 dev_obj = (struct dev_object *)drv_get_first_dev_object();
469 for (i = 0; i < index; i++) {
470 dev_obj =
471 (struct dev_object *)drv_get_next_dev_object((u32) dev_obj);
472 }
473 if (dev_obj) {
e436d07d 474 *device_obj = (struct dev_object *)dev_obj;
7d55524d 475 } else {
e436d07d 476 *device_obj = NULL;
7d55524d
ORL
477 status = -EPERM;
478 }
479
480 return status;
481}
482
483/*
484 * ======== drv_get_first_dev_object ========
485 * Purpose:
486 * Retrieve the first Device Object handle from an internal linked list of
487 * of DEV_OBJECTs maintained by DRV.
488 */
489u32 drv_get_first_dev_object(void)
490{
491 u32 dw_dev_object = 0;
492 struct drv_object *pdrv_obj;
493
a741ea6e 494 if (!cfg_get_object((u32 *) &pdrv_obj, REG_DRV_OBJECT)) {
7d55524d
ORL
495 if ((pdrv_obj->dev_list != NULL) &&
496 !LST_IS_EMPTY(pdrv_obj->dev_list))
497 dw_dev_object = (u32) lst_first(pdrv_obj->dev_list);
498 }
499
500 return dw_dev_object;
501}
502
503/*
504 * ======== DRV_GetFirstDevNodeString ========
505 * Purpose:
506 * Retrieve the first Device Extension from an internal linked list of
507 * of Pointer to dev_node Strings maintained by DRV.
508 */
509u32 drv_get_first_dev_extension(void)
510{
511 u32 dw_dev_extension = 0;
512 struct drv_object *pdrv_obj;
513
a741ea6e 514 if (!cfg_get_object((u32 *) &pdrv_obj, REG_DRV_OBJECT)) {
7d55524d
ORL
515
516 if ((pdrv_obj->dev_node_string != NULL) &&
517 !LST_IS_EMPTY(pdrv_obj->dev_node_string)) {
518 dw_dev_extension =
519 (u32) lst_first(pdrv_obj->dev_node_string);
520 }
521 }
522
523 return dw_dev_extension;
524}
525
526/*
527 * ======== drv_get_next_dev_object ========
528 * Purpose:
529 * Retrieve the next Device Object handle from an internal linked list of
530 * of DEV_OBJECTs maintained by DRV, after having previously called
531 * drv_get_first_dev_object() and zero or more DRV_GetNext.
532 */
533u32 drv_get_next_dev_object(u32 hdev_obj)
534{
535 u32 dw_next_dev_object = 0;
536 struct drv_object *pdrv_obj;
537
538 DBC_REQUIRE(hdev_obj != 0);
539
a741ea6e 540 if (!cfg_get_object((u32 *) &pdrv_obj, REG_DRV_OBJECT)) {
7d55524d
ORL
541
542 if ((pdrv_obj->dev_list != NULL) &&
543 !LST_IS_EMPTY(pdrv_obj->dev_list)) {
544 dw_next_dev_object = (u32) lst_next(pdrv_obj->dev_list,
545 (struct list_head *)
546 hdev_obj);
547 }
548 }
549 return dw_next_dev_object;
550}
551
552/*
553 * ======== drv_get_next_dev_extension ========
554 * Purpose:
555 * Retrieve the next Device Extension from an internal linked list of
556 * of pointer to DevNodeString maintained by DRV, after having previously
557 * called drv_get_first_dev_extension() and zero or more
558 * drv_get_next_dev_extension().
559 */
e6890692 560u32 drv_get_next_dev_extension(u32 dev_extension)
7d55524d
ORL
561{
562 u32 dw_dev_extension = 0;
563 struct drv_object *pdrv_obj;
564
e6890692 565 DBC_REQUIRE(dev_extension != 0);
7d55524d 566
a741ea6e 567 if (!cfg_get_object((u32 *) &pdrv_obj, REG_DRV_OBJECT)) {
7d55524d
ORL
568 if ((pdrv_obj->dev_node_string != NULL) &&
569 !LST_IS_EMPTY(pdrv_obj->dev_node_string)) {
570 dw_dev_extension =
571 (u32) lst_next(pdrv_obj->dev_node_string,
e6890692 572 (struct list_head *)dev_extension);
7d55524d
ORL
573 }
574 }
575
576 return dw_dev_extension;
577}
578
579/*
580 * ======== drv_init ========
581 * Purpose:
582 * Initialize DRV module private state.
583 */
584int drv_init(void)
585{
586 s32 ret = 1; /* function return value */
587
588 DBC_REQUIRE(refs >= 0);
589
590 if (ret)
591 refs++;
592
593 DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
594
595 return ret;
596}
597
598/*
599 * ======== drv_insert_dev_object ========
600 * Purpose:
601 * Insert a DevObject into the list of Manager object.
602 */
e6890692 603int drv_insert_dev_object(struct drv_object *driver_obj,
7d55524d
ORL
604 struct dev_object *hdev_obj)
605{
e6890692 606 struct drv_object *pdrv_object = (struct drv_object *)driver_obj;
7d55524d
ORL
607
608 DBC_REQUIRE(refs > 0);
609 DBC_REQUIRE(hdev_obj != NULL);
610 DBC_REQUIRE(pdrv_object);
611 DBC_ASSERT(pdrv_object->dev_list);
612
613 lst_put_tail(pdrv_object->dev_list, (struct list_head *)hdev_obj);
614
a741ea6e 615 DBC_ENSURE(!LST_IS_EMPTY(pdrv_object->dev_list));
7d55524d 616
a741ea6e 617 return 0;
7d55524d
ORL
618}
619
620/*
621 * ======== drv_remove_dev_object ========
622 * Purpose:
623 * Search for and remove a DeviceObject from the given list of DRV
624 * objects.
625 */
e6890692 626int drv_remove_dev_object(struct drv_object *driver_obj,
7d55524d
ORL
627 struct dev_object *hdev_obj)
628{
629 int status = -EPERM;
e6890692 630 struct drv_object *pdrv_object = (struct drv_object *)driver_obj;
7d55524d
ORL
631 struct list_head *cur_elem;
632
633 DBC_REQUIRE(refs > 0);
634 DBC_REQUIRE(pdrv_object);
635 DBC_REQUIRE(hdev_obj != NULL);
636
637 DBC_REQUIRE(pdrv_object->dev_list != NULL);
638 DBC_REQUIRE(!LST_IS_EMPTY(pdrv_object->dev_list));
639
640 /* Search list for p_proc_object: */
641 for (cur_elem = lst_first(pdrv_object->dev_list); cur_elem != NULL;
642 cur_elem = lst_next(pdrv_object->dev_list, cur_elem)) {
643 /* If found, remove it. */
644 if ((struct dev_object *)cur_elem == hdev_obj) {
645 lst_remove_elem(pdrv_object->dev_list, cur_elem);
646 status = 0;
647 break;
648 }
649 }
650 /* Remove list if empty. */
651 if (LST_IS_EMPTY(pdrv_object->dev_list)) {
652 kfree(pdrv_object->dev_list);
653 pdrv_object->dev_list = NULL;
654 }
655 DBC_ENSURE((pdrv_object->dev_list == NULL) ||
656 !LST_IS_EMPTY(pdrv_object->dev_list));
657
658 return status;
659}
660
661/*
662 * ======== drv_request_resources ========
663 * Purpose:
664 * Requests resources from the OS.
665 */
aa09b091 666int drv_request_resources(u32 dw_context, u32 *dev_node_strg)
7d55524d
ORL
667{
668 int status = 0;
669 struct drv_object *pdrv_object;
670 struct drv_ext *pszdev_node;
671
672 DBC_REQUIRE(dw_context != 0);
aa09b091 673 DBC_REQUIRE(dev_node_strg != NULL);
7d55524d
ORL
674
675 /*
676 * Allocate memory to hold the string. This will live untill
677 * it is freed in the Release resources. Update the driver object
678 * list.
679 */
680
681 status = cfg_get_object((u32 *) &pdrv_object, REG_DRV_OBJECT);
a741ea6e 682 if (!status) {
7d55524d
ORL
683 pszdev_node = kzalloc(sizeof(struct drv_ext), GFP_KERNEL);
684 if (pszdev_node) {
685 lst_init_elem(&pszdev_node->link);
686 strncpy(pszdev_node->sz_string,
687 (char *)dw_context, MAXREGPATHLENGTH - 1);
688 pszdev_node->sz_string[MAXREGPATHLENGTH - 1] = '\0';
689 /* Update the Driver Object List */
aa09b091 690 *dev_node_strg = (u32) pszdev_node->sz_string;
7d55524d
ORL
691 lst_put_tail(pdrv_object->dev_node_string,
692 (struct list_head *)pszdev_node);
693 } else {
694 status = -ENOMEM;
aa09b091 695 *dev_node_strg = 0;
7d55524d
ORL
696 }
697 } else {
698 dev_dbg(bridge, "%s: Failed to get Driver Object from Registry",
699 __func__);
aa09b091 700 *dev_node_strg = 0;
7d55524d
ORL
701 }
702
a741ea6e 703 DBC_ENSURE((!status && dev_node_strg != NULL &&
7d55524d 704 !LST_IS_EMPTY(pdrv_object->dev_node_string)) ||
b66e0986 705 (status && *dev_node_strg == 0));
7d55524d
ORL
706
707 return status;
708}
709
710/*
711 * ======== drv_release_resources ========
712 * Purpose:
713 * Releases resources from the OS.
714 */
715int drv_release_resources(u32 dw_context, struct drv_object *hdrv_obj)
716{
717 int status = 0;
718 struct drv_object *pdrv_object = (struct drv_object *)hdrv_obj;
719 struct drv_ext *pszdev_node;
720
721 /*
722 * Irrespective of the status go ahead and clean it
723 * The following will over write the status.
724 */
725 for (pszdev_node = (struct drv_ext *)drv_get_first_dev_extension();
726 pszdev_node != NULL; pszdev_node = (struct drv_ext *)
727 drv_get_next_dev_extension((u32) pszdev_node)) {
728 if (!pdrv_object->dev_node_string) {
729 /* When this could happen? */
730 continue;
731 }
732 if ((u32) pszdev_node == dw_context) {
733 /* Found it */
734 /* Delete from the Driver object list */
735 lst_remove_elem(pdrv_object->dev_node_string,
736 (struct list_head *)pszdev_node);
737 kfree((void *)pszdev_node);
738 break;
739 }
740 /* Delete the List if it is empty */
741 if (LST_IS_EMPTY(pdrv_object->dev_node_string)) {
742 kfree(pdrv_object->dev_node_string);
743 pdrv_object->dev_node_string = NULL;
744 }
745 }
746 return status;
747}
748
749/*
750 * ======== request_bridge_resources ========
751 * Purpose:
752 * Reserves shared memory for bridge.
753 */
754static int request_bridge_resources(struct cfg_hostres *res)
755{
7d55524d
ORL
756 struct cfg_hostres *host_res = res;
757
758 /* num_mem_windows must not be more than CFG_MAXMEMREGISTERS */
759 host_res->num_mem_windows = 2;
760
761 /* First window is for DSP internal memory */
762 host_res->dw_sys_ctrl_base = ioremap(OMAP_SYSC_BASE, OMAP_SYSC_SIZE);
763 dev_dbg(bridge, "dw_mem_base[0] 0x%x\n", host_res->dw_mem_base[0]);
764 dev_dbg(bridge, "dw_mem_base[3] 0x%x\n", host_res->dw_mem_base[3]);
765 dev_dbg(bridge, "dw_dmmu_base %p\n", host_res->dw_dmmu_base);
766
767 /* for 24xx base port is not mapping the mamory for DSP
768 * internal memory TODO Do a ioremap here */
769 /* Second window is for DSP external memory shared with MPU */
770
771 /* These are hard-coded values */
772 host_res->birq_registers = 0;
773 host_res->birq_attrib = 0;
774 host_res->dw_offset_for_monitor = 0;
775 host_res->dw_chnl_offset = 0;
776 /* CHNL_MAXCHANNELS */
777 host_res->dw_num_chnls = CHNL_MAXCHANNELS;
778 host_res->dw_chnl_buf_size = 0x400;
779
a741ea6e 780 return 0;
7d55524d
ORL
781}
782
783/*
784 * ======== drv_request_bridge_res_dsp ========
785 * Purpose:
786 * Reserves shared memory for bridge.
787 */
788int drv_request_bridge_res_dsp(void **phost_resources)
789{
790 int status = 0;
791 struct cfg_hostres *host_res;
792 u32 dw_buff_size;
793 u32 dma_addr;
794 u32 shm_size;
795 struct drv_data *drv_datap = dev_get_drvdata(bridge);
796
797 dw_buff_size = sizeof(struct cfg_hostres);
798
799 host_res = kzalloc(dw_buff_size, GFP_KERNEL);
800
801 if (host_res != NULL) {
802 request_bridge_resources(host_res);
803 /* num_mem_windows must not be more than CFG_MAXMEMREGISTERS */
804 host_res->num_mem_windows = 4;
805
806 host_res->dw_mem_base[0] = 0;
807 host_res->dw_mem_base[2] = (u32) ioremap(OMAP_DSP_MEM1_BASE,
808 OMAP_DSP_MEM1_SIZE);
809 host_res->dw_mem_base[3] = (u32) ioremap(OMAP_DSP_MEM2_BASE,
810 OMAP_DSP_MEM2_SIZE);
811 host_res->dw_mem_base[4] = (u32) ioremap(OMAP_DSP_MEM3_BASE,
812 OMAP_DSP_MEM3_SIZE);
813 host_res->dw_per_base = ioremap(OMAP_PER_CM_BASE,
814 OMAP_PER_CM_SIZE);
815 host_res->dw_per_pm_base = (u32) ioremap(OMAP_PER_PRM_BASE,
816 OMAP_PER_PRM_SIZE);
817 host_res->dw_core_pm_base = (u32) ioremap(OMAP_CORE_PRM_BASE,
818 OMAP_CORE_PRM_SIZE);
819 host_res->dw_dmmu_base = ioremap(OMAP_DMMU_BASE,
820 OMAP_DMMU_SIZE);
821
822 dev_dbg(bridge, "dw_mem_base[0] 0x%x\n",
823 host_res->dw_mem_base[0]);
824 dev_dbg(bridge, "dw_mem_base[1] 0x%x\n",
825 host_res->dw_mem_base[1]);
826 dev_dbg(bridge, "dw_mem_base[2] 0x%x\n",
827 host_res->dw_mem_base[2]);
828 dev_dbg(bridge, "dw_mem_base[3] 0x%x\n",
829 host_res->dw_mem_base[3]);
830 dev_dbg(bridge, "dw_mem_base[4] 0x%x\n",
831 host_res->dw_mem_base[4]);
832 dev_dbg(bridge, "dw_dmmu_base %p\n", host_res->dw_dmmu_base);
833
834 shm_size = drv_datap->shm_size;
835 if (shm_size >= 0x10000) {
836 /* Allocate Physically contiguous,
837 * non-cacheable memory */
838 host_res->dw_mem_base[1] =
839 (u32) mem_alloc_phys_mem(shm_size, 0x100000,
840 &dma_addr);
841 if (host_res->dw_mem_base[1] == 0) {
842 status = -ENOMEM;
843 pr_err("shm reservation Failed\n");
844 } else {
845 host_res->dw_mem_length[1] = shm_size;
846 host_res->dw_mem_phys[1] = dma_addr;
847
848 dev_dbg(bridge, "%s: Bridge shm address 0x%x "
849 "dma_addr %x size %x\n", __func__,
850 host_res->dw_mem_base[1],
851 dma_addr, shm_size);
852 }
853 }
a741ea6e 854 if (!status) {
7d55524d
ORL
855 /* These are hard-coded values */
856 host_res->birq_registers = 0;
857 host_res->birq_attrib = 0;
858 host_res->dw_offset_for_monitor = 0;
859 host_res->dw_chnl_offset = 0;
860 /* CHNL_MAXCHANNELS */
861 host_res->dw_num_chnls = CHNL_MAXCHANNELS;
862 host_res->dw_chnl_buf_size = 0x400;
863 dw_buff_size = sizeof(struct cfg_hostres);
864 }
865 *phost_resources = host_res;
866 }
867 /* End Mem alloc */
868 return status;
869}
870
fb6aabb7 871void mem_ext_phys_pool_init(u32 pool_phys_base, u32 pool_size)
7d55524d
ORL
872{
873 u32 pool_virt_base;
874
875 /* get the virtual address for the physical memory pool passed */
fb6aabb7 876 pool_virt_base = (u32) ioremap(pool_phys_base, pool_size);
7d55524d
ORL
877
878 if ((void **)pool_virt_base == NULL) {
879 pr_err("%s: external physical memory map failed\n", __func__);
880 ext_phys_mem_pool_enabled = false;
881 } else {
fb6aabb7
RS
882 ext_mem_pool.phys_mem_base = pool_phys_base;
883 ext_mem_pool.phys_mem_size = pool_size;
7d55524d 884 ext_mem_pool.virt_mem_base = pool_virt_base;
fb6aabb7 885 ext_mem_pool.next_phys_alloc_ptr = pool_phys_base;
7d55524d
ORL
886 ext_phys_mem_pool_enabled = true;
887 }
888}
889
890void mem_ext_phys_pool_release(void)
891{
892 if (ext_phys_mem_pool_enabled) {
893 iounmap((void *)(ext_mem_pool.virt_mem_base));
894 ext_phys_mem_pool_enabled = false;
895 }
896}
897
898/*
899 * ======== mem_ext_phys_mem_alloc ========
900 * Purpose:
901 * Allocate physically contiguous, uncached memory from external memory pool
902 */
903
e6bf74f0 904static void *mem_ext_phys_mem_alloc(u32 bytes, u32 align, u32 * phys_addr)
7d55524d
ORL
905{
906 u32 new_alloc_ptr;
907 u32 offset;
908 u32 virt_addr;
909
910 if (align == 0)
911 align = 1;
912
913 if (bytes > ((ext_mem_pool.phys_mem_base + ext_mem_pool.phys_mem_size)
914 - ext_mem_pool.next_phys_alloc_ptr)) {
13b18c29 915 phys_addr = NULL;
7d55524d
ORL
916 return NULL;
917 } else {
918 offset = (ext_mem_pool.next_phys_alloc_ptr & (align - 1));
919 if (offset == 0)
920 new_alloc_ptr = ext_mem_pool.next_phys_alloc_ptr;
921 else
922 new_alloc_ptr = (ext_mem_pool.next_phys_alloc_ptr) +
923 (align - offset);
924 if ((new_alloc_ptr + bytes) <=
925 (ext_mem_pool.phys_mem_base + ext_mem_pool.phys_mem_size)) {
926 /* we can allocate */
13b18c29 927 *phys_addr = new_alloc_ptr;
7d55524d
ORL
928 ext_mem_pool.next_phys_alloc_ptr =
929 new_alloc_ptr + bytes;
930 virt_addr =
931 ext_mem_pool.virt_mem_base + (new_alloc_ptr -
932 ext_mem_pool.
933 phys_mem_base);
934 return (void *)virt_addr;
935 } else {
13b18c29 936 *phys_addr = 0;
7d55524d
ORL
937 return NULL;
938 }
939 }
940}
941
942/*
943 * ======== mem_alloc_phys_mem ========
944 * Purpose:
945 * Allocate physically contiguous, uncached memory
946 */
0cd343a4 947void *mem_alloc_phys_mem(u32 byte_size, u32 align_mask,
e6bf74f0 948 u32 *physical_address)
7d55524d
ORL
949{
950 void *va_mem = NULL;
951 dma_addr_t pa_mem;
952
953 if (byte_size > 0) {
954 if (ext_phys_mem_pool_enabled) {
0cd343a4 955 va_mem = mem_ext_phys_mem_alloc(byte_size, align_mask,
7d55524d
ORL
956 (u32 *) &pa_mem);
957 } else
958 va_mem = dma_alloc_coherent(NULL, byte_size, &pa_mem,
959 GFP_KERNEL);
960 if (va_mem == NULL)
13b18c29 961 *physical_address = 0;
7d55524d 962 else
13b18c29 963 *physical_address = pa_mem;
7d55524d
ORL
964 }
965 return va_mem;
966}
967
968/*
969 * ======== mem_free_phys_mem ========
970 * Purpose:
971 * Free the given block of physically contiguous memory.
972 */
318b5df9 973void mem_free_phys_mem(void *virtual_address, u32 physical_address,
7d55524d
ORL
974 u32 byte_size)
975{
318b5df9 976 DBC_REQUIRE(virtual_address != NULL);
7d55524d
ORL
977
978 if (!ext_phys_mem_pool_enabled)
318b5df9 979 dma_free_coherent(NULL, byte_size, virtual_address,
13b18c29 980 physical_address);
7d55524d 981}
This page took 0.076038 seconds and 5 git commands to generate.