Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cmm.c
Go to the documentation of this file.
1 /*
2  * cmm.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * The Communication(Shared) Memory Management(CMM) module provides
7  * shared memory management services for DSP/BIOS Bridge data streaming
8  * and messaging.
9  *
10  * Multiple shared memory segments can be registered with CMM.
11  * Each registered SM segment is represented by a SM "allocator" that
12  * describes a block of physically contiguous shared memory used for
13  * future allocations by CMM.
14  *
15  * Memory is coalesced back to the appropriate heap when a buffer is
16  * freed.
17  *
18  * Notes:
19  * Va: Virtual address.
20  * Pa: Physical or kernel system address.
21  *
22  * Copyright (C) 2005-2006 Texas Instruments, Inc.
23  *
24  * This package is free software; you can redistribute it and/or modify
25  * it under the terms of the GNU General Public License version 2 as
26  * published by the Free Software Foundation.
27  *
28  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31  */
32 #include <linux/types.h>
33 #include <linux/list.h>
34 
35 /* ----------------------------------- DSP/BIOS Bridge */
36 #include <dspbridge/dbdefs.h>
37 
38 /* ----------------------------------- OS Adaptation Layer */
39 #include <dspbridge/sync.h>
40 
41 /* ----------------------------------- Platform Manager */
42 #include <dspbridge/dev.h>
43 #include <dspbridge/proc.h>
44 
45 /* ----------------------------------- This */
46 #include <dspbridge/cmm.h>
47 
48 /* ----------------------------------- Defines, Data Structures, Typedefs */
49 #define NEXT_PA(pnode) (pnode->pa + pnode->size)
50 
51 /* Other bus/platform translations */
52 #define DSPPA2GPPPA(base, x, y) ((x)+(y))
53 #define GPPPA2DSPPA(base, x, y) ((x)-(y))
54 
55 /*
56  * Allocators define a block of contiguous memory used for future allocations.
57  *
58  * sma - shared memory allocator.
59  * vma - virtual memory allocator.(not used).
60  */
61 struct cmm_allocator { /* sma */
62  unsigned int shm_base; /* Start of physical SM block */
63  u32 sm_size; /* Size of SM block in bytes */
64  unsigned int vm_base; /* Start of VM block. (Dev driver
65  * context for 'sma') */
66  u32 dsp_phys_addr_offset; /* DSP PA to GPP PA offset for this
67  * SM space */
68  s8 c_factor; /* DSPPa to GPPPa Conversion Factor */
69  unsigned int dsp_base; /* DSP virt base byte address */
70  u32 dsp_size; /* DSP seg size in bytes */
71  struct cmm_object *cmm_mgr; /* back ref to parent mgr */
72  /* node list of available memory */
74  /* node list of memory in use */
76 };
77 
78 struct cmm_xlator { /* Pa<->Va translator object */
79  /* CMM object this translator associated */
81  /*
82  * Client process virtual base address that corresponds to phys SM
83  * base address for translator's seg_id.
84  * Only 1 segment ID currently supported.
85  */
86  unsigned int virt_base; /* virtual base address */
87  u32 virt_size; /* size of virt space in bytes */
88  u32 seg_id; /* Segment Id */
89 };
90 
91 /* CMM Mgr */
92 struct cmm_object {
93  /*
94  * Cmm Lock is used to serialize access mem manager for multi-threads.
95  */
96  struct mutex cmm_lock; /* Lock to access cmm mgr */
97  struct list_head node_free_list; /* Free list of memory nodes */
98  u32 min_block_size; /* Min SM block; default 16 bytes */
99  u32 page_size; /* Memory Page size (1k/4k) */
100  /* GPP SM segment ptrs */
102 };
103 
104 /* Default CMM Mgr attributes */
105 static struct cmm_mgrattrs cmm_dfltmgrattrs = {
106  /* min_block_size, min block size(bytes) allocated by cmm mgr */
107  16
108 };
109 
110 /* Default allocation attributes */
111 static struct cmm_attrs cmm_dfltalctattrs = {
112  1 /* seg_id, default segment Id for allocator */
113 };
114 
115 /* Address translator default attrs */
116 static struct cmm_xlatorattrs cmm_dfltxlatorattrs = {
117  /* seg_id, does not have to match cmm_dfltalctattrs ul_seg_id */
118  1,
119  0, /* dsp_bufs */
120  0, /* dsp_buf_size */
121  NULL, /* vm_base */
122  0, /* vm_size */
123 };
124 
125 /* SM node representing a block of memory. */
126 struct cmm_mnode {
127  struct list_head link; /* must be 1st element */
128  u32 pa; /* Phys addr */
129  u32 va; /* Virtual address in device process context */
130  u32 size; /* SM block size in bytes */
131  u32 client_proc; /* Process that allocated this mem block */
132 };
133 
134 /* ----------------------------------- Function Prototypes */
135 static void add_to_free_list(struct cmm_allocator *allocator,
136  struct cmm_mnode *pnode);
137 static struct cmm_allocator *get_allocator(struct cmm_object *cmm_mgr_obj,
138  u32 ul_seg_id);
139 static struct cmm_mnode *get_free_block(struct cmm_allocator *allocator,
140  u32 usize);
141 static struct cmm_mnode *get_node(struct cmm_object *cmm_mgr_obj, u32 dw_pa,
142  u32 dw_va, u32 ul_size);
143 /* get available slot for new allocator */
144 static s32 get_slot(struct cmm_object *cmm_mgr_obj);
145 static void un_register_gppsm_seg(struct cmm_allocator *psma);
146 
147 /*
148  * ======== cmm_calloc_buf ========
149  * Purpose:
150  * Allocate a SM buffer, zero contents, and return the physical address
151  * and optional driver context virtual address(pp_buf_va).
152  *
153  * The freelist is sorted in increasing size order. Get the first
154  * block that satifies the request and sort the remaining back on
155  * the freelist; if large enough. The kept block is placed on the
156  * inUseList.
157  */
158 void *cmm_calloc_buf(struct cmm_object *hcmm_mgr, u32 usize,
159  struct cmm_attrs *pattrs, void **pp_buf_va)
160 {
161  struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
162  void *buf_pa = NULL;
163  struct cmm_mnode *pnode = NULL;
164  struct cmm_mnode *new_node = NULL;
165  struct cmm_allocator *allocator = NULL;
166  u32 delta_size;
167  u8 *pbyte = NULL;
168  s32 cnt;
169 
170  if (pattrs == NULL)
171  pattrs = &cmm_dfltalctattrs;
172 
173  if (pp_buf_va != NULL)
174  *pp_buf_va = NULL;
175 
176  if (cmm_mgr_obj && (usize != 0)) {
177  if (pattrs->seg_id > 0) {
178  /* SegId > 0 is SM */
179  /* get the allocator object for this segment id */
180  allocator =
181  get_allocator(cmm_mgr_obj, pattrs->seg_id);
182  /* keep block size a multiple of min_block_size */
183  usize =
184  ((usize - 1) & ~(cmm_mgr_obj->min_block_size -
185  1))
186  + cmm_mgr_obj->min_block_size;
187  mutex_lock(&cmm_mgr_obj->cmm_lock);
188  pnode = get_free_block(allocator, usize);
189  }
190  if (pnode) {
191  delta_size = (pnode->size - usize);
192  if (delta_size >= cmm_mgr_obj->min_block_size) {
193  /* create a new block with the leftovers and
194  * add to freelist */
195  new_node =
196  get_node(cmm_mgr_obj, pnode->pa + usize,
197  pnode->va + usize,
198  (u32) delta_size);
199  /* leftovers go free */
200  add_to_free_list(allocator, new_node);
201  /* adjust our node's size */
202  pnode->size = usize;
203  }
204  /* Tag node with client process requesting allocation
205  * We'll need to free up a process's alloc'd SM if the
206  * client process goes away.
207  */
208  /* Return TGID instead of process handle */
209  pnode->client_proc = current->tgid;
210 
211  /* put our node on InUse list */
212  list_add_tail(&pnode->link, &allocator->in_use_list);
213  buf_pa = (void *)pnode->pa; /* physical address */
214  /* clear mem */
215  pbyte = (u8 *) pnode->va;
216  for (cnt = 0; cnt < (s32) usize; cnt++, pbyte++)
217  *pbyte = 0;
218 
219  if (pp_buf_va != NULL) {
220  /* Virtual address */
221  *pp_buf_va = (void *)pnode->va;
222  }
223  }
224  mutex_unlock(&cmm_mgr_obj->cmm_lock);
225  }
226  return buf_pa;
227 }
228 
229 /*
230  * ======== cmm_create ========
231  * Purpose:
232  * Create a communication memory manager object.
233  */
234 int cmm_create(struct cmm_object **ph_cmm_mgr,
235  struct dev_object *hdev_obj,
236  const struct cmm_mgrattrs *mgr_attrts)
237 {
238  struct cmm_object *cmm_obj = NULL;
239  int status = 0;
240 
241  *ph_cmm_mgr = NULL;
242  /* create, zero, and tag a cmm mgr object */
243  cmm_obj = kzalloc(sizeof(struct cmm_object), GFP_KERNEL);
244  if (!cmm_obj)
245  return -ENOMEM;
246 
247  if (mgr_attrts == NULL)
248  mgr_attrts = &cmm_dfltmgrattrs; /* set defaults */
249 
250  /* save away smallest block allocation for this cmm mgr */
251  cmm_obj->min_block_size = mgr_attrts->min_block_size;
252  cmm_obj->page_size = PAGE_SIZE;
253 
254  /* create node free list */
255  INIT_LIST_HEAD(&cmm_obj->node_free_list);
256  mutex_init(&cmm_obj->cmm_lock);
257  *ph_cmm_mgr = cmm_obj;
258 
259  return status;
260 }
261 
262 /*
263  * ======== cmm_destroy ========
264  * Purpose:
265  * Release the communication memory manager resources.
266  */
267 int cmm_destroy(struct cmm_object *hcmm_mgr, bool force)
268 {
269  struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
270  struct cmm_info temp_info;
271  int status = 0;
272  s32 slot_seg;
273  struct cmm_mnode *node, *tmp;
274 
275  if (!hcmm_mgr) {
276  status = -EFAULT;
277  return status;
278  }
279  mutex_lock(&cmm_mgr_obj->cmm_lock);
280  /* If not force then fail if outstanding allocations exist */
281  if (!force) {
282  /* Check for outstanding memory allocations */
283  status = cmm_get_info(hcmm_mgr, &temp_info);
284  if (!status) {
285  if (temp_info.total_in_use_cnt > 0) {
286  /* outstanding allocations */
287  status = -EPERM;
288  }
289  }
290  }
291  if (!status) {
292  /* UnRegister SM allocator */
293  for (slot_seg = 0; slot_seg < CMM_MAXGPPSEGS; slot_seg++) {
294  if (cmm_mgr_obj->pa_gppsm_seg_tab[slot_seg] != NULL) {
295  un_register_gppsm_seg
296  (cmm_mgr_obj->pa_gppsm_seg_tab[slot_seg]);
297  /* Set slot to NULL for future reuse */
298  cmm_mgr_obj->pa_gppsm_seg_tab[slot_seg] = NULL;
299  }
300  }
301  }
302  list_for_each_entry_safe(node, tmp, &cmm_mgr_obj->node_free_list,
303  link) {
304  list_del(&node->link);
305  kfree(node);
306  }
307  mutex_unlock(&cmm_mgr_obj->cmm_lock);
308  if (!status) {
309  /* delete CS & cmm mgr object */
310  mutex_destroy(&cmm_mgr_obj->cmm_lock);
311  kfree(cmm_mgr_obj);
312  }
313  return status;
314 }
315 
316 /*
317  * ======== cmm_free_buf ========
318  * Purpose:
319  * Free the given buffer.
320  */
321 int cmm_free_buf(struct cmm_object *hcmm_mgr, void *buf_pa, u32 ul_seg_id)
322 {
323  struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
324  int status = -EFAULT;
325  struct cmm_mnode *curr, *tmp;
326  struct cmm_allocator *allocator;
327  struct cmm_attrs *pattrs;
328 
329  if (ul_seg_id == 0) {
330  pattrs = &cmm_dfltalctattrs;
331  ul_seg_id = pattrs->seg_id;
332  }
333  if (!hcmm_mgr || !(ul_seg_id > 0)) {
334  status = -EFAULT;
335  return status;
336  }
337 
338  allocator = get_allocator(cmm_mgr_obj, ul_seg_id);
339  if (!allocator)
340  return status;
341 
342  mutex_lock(&cmm_mgr_obj->cmm_lock);
343  list_for_each_entry_safe(curr, tmp, &allocator->in_use_list, link) {
344  if (curr->pa == (u32) buf_pa) {
345  list_del(&curr->link);
346  add_to_free_list(allocator, curr);
347  status = 0;
348  break;
349  }
350  }
351  mutex_unlock(&cmm_mgr_obj->cmm_lock);
352 
353  return status;
354 }
355 
356 /*
357  * ======== cmm_get_handle ========
358  * Purpose:
359  * Return the communication memory manager object for this device.
360  * This is typically called from the client process.
361  */
362 int cmm_get_handle(void *hprocessor, struct cmm_object ** ph_cmm_mgr)
363 {
364  int status = 0;
365  struct dev_object *hdev_obj;
366 
367  if (hprocessor != NULL)
368  status = proc_get_dev_object(hprocessor, &hdev_obj);
369  else
370  hdev_obj = dev_get_first(); /* default */
371 
372  if (!status)
373  status = dev_get_cmm_mgr(hdev_obj, ph_cmm_mgr);
374 
375  return status;
376 }
377 
378 /*
379  * ======== cmm_get_info ========
380  * Purpose:
381  * Return the current memory utilization information.
382  */
383 int cmm_get_info(struct cmm_object *hcmm_mgr,
384  struct cmm_info *cmm_info_obj)
385 {
386  struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
387  u32 ul_seg;
388  int status = 0;
389  struct cmm_allocator *altr;
390  struct cmm_mnode *curr;
391 
392  if (!hcmm_mgr) {
393  status = -EFAULT;
394  return status;
395  }
396  mutex_lock(&cmm_mgr_obj->cmm_lock);
397  cmm_info_obj->num_gppsm_segs = 0; /* # of SM segments */
398  /* Total # of outstanding alloc */
399  cmm_info_obj->total_in_use_cnt = 0;
400  /* min block size */
401  cmm_info_obj->min_block_size = cmm_mgr_obj->min_block_size;
402  /* check SM memory segments */
403  for (ul_seg = 1; ul_seg <= CMM_MAXGPPSEGS; ul_seg++) {
404  /* get the allocator object for this segment id */
405  altr = get_allocator(cmm_mgr_obj, ul_seg);
406  if (!altr)
407  continue;
408  cmm_info_obj->num_gppsm_segs++;
409  cmm_info_obj->seg_info[ul_seg - 1].seg_base_pa =
410  altr->shm_base - altr->dsp_size;
411  cmm_info_obj->seg_info[ul_seg - 1].total_seg_size =
412  altr->dsp_size + altr->sm_size;
413  cmm_info_obj->seg_info[ul_seg - 1].gpp_base_pa =
414  altr->shm_base;
415  cmm_info_obj->seg_info[ul_seg - 1].gpp_size =
416  altr->sm_size;
417  cmm_info_obj->seg_info[ul_seg - 1].dsp_base_va =
418  altr->dsp_base;
419  cmm_info_obj->seg_info[ul_seg - 1].dsp_size =
420  altr->dsp_size;
421  cmm_info_obj->seg_info[ul_seg - 1].seg_base_va =
422  altr->vm_base - altr->dsp_size;
423  cmm_info_obj->seg_info[ul_seg - 1].in_use_cnt = 0;
424 
425  list_for_each_entry(curr, &altr->in_use_list, link) {
426  cmm_info_obj->total_in_use_cnt++;
427  cmm_info_obj->seg_info[ul_seg - 1].in_use_cnt++;
428  }
429  }
430  mutex_unlock(&cmm_mgr_obj->cmm_lock);
431  return status;
432 }
433 
434 /*
435  * ======== cmm_register_gppsm_seg ========
436  * Purpose:
437  * Register a block of SM with the CMM to be used for later GPP SM
438  * allocations.
439  */
440 int cmm_register_gppsm_seg(struct cmm_object *hcmm_mgr,
441  u32 dw_gpp_base_pa, u32 ul_size,
442  u32 dsp_addr_offset, s8 c_factor,
443  u32 dw_dsp_base, u32 ul_dsp_size,
444  u32 *sgmt_id, u32 gpp_base_va)
445 {
446  struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
447  struct cmm_allocator *psma = NULL;
448  int status = 0;
449  struct cmm_mnode *new_node;
450  s32 slot_seg;
451 
452  dev_dbg(bridge, "%s: dw_gpp_base_pa %x ul_size %x dsp_addr_offset %x "
453  "dw_dsp_base %x ul_dsp_size %x gpp_base_va %x\n",
454  __func__, dw_gpp_base_pa, ul_size, dsp_addr_offset,
455  dw_dsp_base, ul_dsp_size, gpp_base_va);
456 
457  if (!hcmm_mgr)
458  return -EFAULT;
459 
460  /* make sure we have room for another allocator */
461  mutex_lock(&cmm_mgr_obj->cmm_lock);
462 
463  slot_seg = get_slot(cmm_mgr_obj);
464  if (slot_seg < 0) {
465  status = -EPERM;
466  goto func_end;
467  }
468 
469  /* Check if input ul_size is big enough to alloc at least one block */
470  if (ul_size < cmm_mgr_obj->min_block_size) {
471  status = -EINVAL;
472  goto func_end;
473  }
474 
475  /* create, zero, and tag an SM allocator object */
476  psma = kzalloc(sizeof(struct cmm_allocator), GFP_KERNEL);
477  if (!psma) {
478  status = -ENOMEM;
479  goto func_end;
480  }
481 
482  psma->cmm_mgr = hcmm_mgr; /* ref to parent */
483  psma->shm_base = dw_gpp_base_pa; /* SM Base phys */
484  psma->sm_size = ul_size; /* SM segment size in bytes */
485  psma->vm_base = gpp_base_va;
486  psma->dsp_phys_addr_offset = dsp_addr_offset;
487  psma->c_factor = c_factor;
488  psma->dsp_base = dw_dsp_base;
489  psma->dsp_size = ul_dsp_size;
490  if (psma->vm_base == 0) {
491  status = -EPERM;
492  goto func_end;
493  }
494  /* return the actual segment identifier */
495  *sgmt_id = (u32) slot_seg + 1;
496 
497  INIT_LIST_HEAD(&psma->free_list);
498  INIT_LIST_HEAD(&psma->in_use_list);
499 
500  /* Get a mem node for this hunk-o-memory */
501  new_node = get_node(cmm_mgr_obj, dw_gpp_base_pa,
502  psma->vm_base, ul_size);
503  /* Place node on the SM allocator's free list */
504  if (new_node) {
505  list_add_tail(&new_node->link, &psma->free_list);
506  } else {
507  status = -ENOMEM;
508  goto func_end;
509  }
510  /* make entry */
511  cmm_mgr_obj->pa_gppsm_seg_tab[slot_seg] = psma;
512 
513 func_end:
514  /* Cleanup allocator */
515  if (status && psma)
516  un_register_gppsm_seg(psma);
517  mutex_unlock(&cmm_mgr_obj->cmm_lock);
518 
519  return status;
520 }
521 
522 /*
523  * ======== cmm_un_register_gppsm_seg ========
524  * Purpose:
525  * UnRegister GPP SM segments with the CMM.
526  */
528  u32 ul_seg_id)
529 {
530  struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
531  int status = 0;
532  struct cmm_allocator *psma;
533  u32 ul_id = ul_seg_id;
534 
535  if (!hcmm_mgr)
536  return -EFAULT;
537 
538  if (ul_seg_id == CMM_ALLSEGMENTS)
539  ul_id = 1;
540 
541  if ((ul_id <= 0) || (ul_id > CMM_MAXGPPSEGS))
542  return -EINVAL;
543 
544  /*
545  * FIXME: CMM_MAXGPPSEGS == 1. why use a while cycle? Seems to me like
546  * the ul_seg_id is not needed here. It must be always 1.
547  */
548  while (ul_id <= CMM_MAXGPPSEGS) {
549  mutex_lock(&cmm_mgr_obj->cmm_lock);
550  /* slot = seg_id-1 */
551  psma = cmm_mgr_obj->pa_gppsm_seg_tab[ul_id - 1];
552  if (psma != NULL) {
553  un_register_gppsm_seg(psma);
554  /* Set alctr ptr to NULL for future reuse */
555  cmm_mgr_obj->pa_gppsm_seg_tab[ul_id - 1] = NULL;
556  } else if (ul_seg_id != CMM_ALLSEGMENTS) {
557  status = -EPERM;
558  }
559  mutex_unlock(&cmm_mgr_obj->cmm_lock);
560  if (ul_seg_id != CMM_ALLSEGMENTS)
561  break;
562 
563  ul_id++;
564  } /* end while */
565  return status;
566 }
567 
568 /*
569  * ======== un_register_gppsm_seg ========
570  * Purpose:
571  * UnRegister the SM allocator by freeing all its resources and
572  * nulling cmm mgr table entry.
573  * Note:
574  * This routine is always called within cmm lock crit sect.
575  */
576 static void un_register_gppsm_seg(struct cmm_allocator *psma)
577 {
578  struct cmm_mnode *curr, *tmp;
579 
580  /* free nodes on free list */
581  list_for_each_entry_safe(curr, tmp, &psma->free_list, link) {
582  list_del(&curr->link);
583  kfree(curr);
584  }
585 
586  /* free nodes on InUse list */
587  list_for_each_entry_safe(curr, tmp, &psma->in_use_list, link) {
588  list_del(&curr->link);
589  kfree(curr);
590  }
591 
592  if ((void *)psma->vm_base != NULL)
593  MEM_UNMAP_LINEAR_ADDRESS((void *)psma->vm_base);
594 
595  /* Free allocator itself */
596  kfree(psma);
597 }
598 
599 /*
600  * ======== get_slot ========
601  * Purpose:
602  * An available slot # is returned. Returns negative on failure.
603  */
604 static s32 get_slot(struct cmm_object *cmm_mgr_obj)
605 {
606  s32 slot_seg = -1; /* neg on failure */
607  /* get first available slot in cmm mgr SMSegTab[] */
608  for (slot_seg = 0; slot_seg < CMM_MAXGPPSEGS; slot_seg++) {
609  if (cmm_mgr_obj->pa_gppsm_seg_tab[slot_seg] == NULL)
610  break;
611 
612  }
613  if (slot_seg == CMM_MAXGPPSEGS)
614  slot_seg = -1; /* failed */
615 
616  return slot_seg;
617 }
618 
619 /*
620  * ======== get_node ========
621  * Purpose:
622  * Get a memory node from freelist or create a new one.
623  */
624 static struct cmm_mnode *get_node(struct cmm_object *cmm_mgr_obj, u32 dw_pa,
625  u32 dw_va, u32 ul_size)
626 {
627  struct cmm_mnode *pnode;
628 
629  /* Check cmm mgr's node freelist */
630  if (list_empty(&cmm_mgr_obj->node_free_list)) {
631  pnode = kzalloc(sizeof(struct cmm_mnode), GFP_KERNEL);
632  if (!pnode)
633  return NULL;
634  } else {
635  /* surely a valid element */
636  pnode = list_first_entry(&cmm_mgr_obj->node_free_list,
637  struct cmm_mnode, link);
638  list_del_init(&pnode->link);
639  }
640 
641  pnode->pa = dw_pa;
642  pnode->va = dw_va;
643  pnode->size = ul_size;
644 
645  return pnode;
646 }
647 
648 /*
649  * ======== delete_node ========
650  * Purpose:
651  * Put a memory node on the cmm nodelist for later use.
652  * Doesn't actually delete the node. Heap thrashing friendly.
653  */
654 static void delete_node(struct cmm_object *cmm_mgr_obj, struct cmm_mnode *pnode)
655 {
656  list_add_tail(&pnode->link, &cmm_mgr_obj->node_free_list);
657 }
658 
659 /*
660  * ====== get_free_block ========
661  * Purpose:
662  * Scan the free block list and return the first block that satisfies
663  * the size.
664  */
665 static struct cmm_mnode *get_free_block(struct cmm_allocator *allocator,
666  u32 usize)
667 {
668  struct cmm_mnode *node, *tmp;
669 
670  if (!allocator)
671  return NULL;
672 
673  list_for_each_entry_safe(node, tmp, &allocator->free_list, link) {
674  if (usize <= node->size) {
675  list_del(&node->link);
676  return node;
677  }
678  }
679 
680  return NULL;
681 }
682 
683 /*
684  * ======== add_to_free_list ========
685  * Purpose:
686  * Coalesce node into the freelist in ascending size order.
687  */
688 static void add_to_free_list(struct cmm_allocator *allocator,
689  struct cmm_mnode *node)
690 {
691  struct cmm_mnode *curr;
692 
693  if (!node) {
694  pr_err("%s: failed - node is NULL\n", __func__);
695  return;
696  }
697 
698  list_for_each_entry(curr, &allocator->free_list, link) {
699  if (NEXT_PA(curr) == node->pa) {
700  curr->size += node->size;
701  delete_node(allocator->cmm_mgr, node);
702  return;
703  }
704  if (curr->pa == NEXT_PA(node)) {
705  curr->pa = node->pa;
706  curr->va = node->va;
707  curr->size += node->size;
708  delete_node(allocator->cmm_mgr, node);
709  return;
710  }
711  }
712  list_for_each_entry(curr, &allocator->free_list, link) {
713  if (curr->size >= node->size) {
714  list_add_tail(&node->link, &curr->link);
715  return;
716  }
717  }
718  list_add_tail(&node->link, &allocator->free_list);
719 }
720 
721 /*
722  * ======== get_allocator ========
723  * Purpose:
724  * Return the allocator for the given SM Segid.
725  * SegIds: 1,2,3..max.
726  */
727 static struct cmm_allocator *get_allocator(struct cmm_object *cmm_mgr_obj,
728  u32 ul_seg_id)
729 {
730  return cmm_mgr_obj->pa_gppsm_seg_tab[ul_seg_id - 1];
731 }
732 
733 /*
734  * The CMM_Xlator[xxx] routines below are used by Node and Stream
735  * to perform SM address translation to the client process address space.
736  * A "translator" object is created by a node/stream for each SM seg used.
737  */
738 
739 /*
740  * ======== cmm_xlator_create ========
741  * Purpose:
742  * Create an address translator object.
743  */
744 int cmm_xlator_create(struct cmm_xlatorobject **xlator,
745  struct cmm_object *hcmm_mgr,
746  struct cmm_xlatorattrs *xlator_attrs)
747 {
748  struct cmm_xlator *xlator_object = NULL;
749  int status = 0;
750 
751  *xlator = NULL;
752  if (xlator_attrs == NULL)
753  xlator_attrs = &cmm_dfltxlatorattrs; /* set defaults */
754 
755  xlator_object = kzalloc(sizeof(struct cmm_xlator), GFP_KERNEL);
756  if (xlator_object != NULL) {
757  xlator_object->cmm_mgr = hcmm_mgr; /* ref back to CMM */
758  /* SM seg_id */
759  xlator_object->seg_id = xlator_attrs->seg_id;
760  } else {
761  status = -ENOMEM;
762  }
763  if (!status)
764  *xlator = (struct cmm_xlatorobject *)xlator_object;
765 
766  return status;
767 }
768 
769 /*
770  * ======== cmm_xlator_alloc_buf ========
771  */
772 void *cmm_xlator_alloc_buf(struct cmm_xlatorobject *xlator, void *va_buf,
773  u32 pa_size)
774 {
775  struct cmm_xlator *xlator_obj = (struct cmm_xlator *)xlator;
776  void *pbuf = NULL;
777  void *tmp_va_buff;
778  struct cmm_attrs attrs;
779 
780  if (xlator_obj) {
781  attrs.seg_id = xlator_obj->seg_id;
782  __raw_writel(0, va_buf);
783  /* Alloc SM */
784  pbuf =
785  cmm_calloc_buf(xlator_obj->cmm_mgr, pa_size, &attrs, NULL);
786  if (pbuf) {
787  /* convert to translator(node/strm) process Virtual
788  * address */
789  tmp_va_buff = cmm_xlator_translate(xlator,
790  pbuf, CMM_PA2VA);
791  __raw_writel((u32)tmp_va_buff, va_buf);
792  }
793  }
794  return pbuf;
795 }
796 
797 /*
798  * ======== cmm_xlator_free_buf ========
799  * Purpose:
800  * Free the given SM buffer and descriptor.
801  * Does not free virtual memory.
802  */
803 int cmm_xlator_free_buf(struct cmm_xlatorobject *xlator, void *buf_va)
804 {
805  struct cmm_xlator *xlator_obj = (struct cmm_xlator *)xlator;
806  int status = -EPERM;
807  void *buf_pa = NULL;
808 
809  if (xlator_obj) {
810  /* convert Va to Pa so we can free it. */
811  buf_pa = cmm_xlator_translate(xlator, buf_va, CMM_VA2PA);
812  if (buf_pa) {
813  status = cmm_free_buf(xlator_obj->cmm_mgr, buf_pa,
814  xlator_obj->seg_id);
815  if (status) {
816  /* Uh oh, this shouldn't happen. Descriptor
817  * gone! */
818  pr_err("%s, line %d: Assertion failed\n",
819  __FILE__, __LINE__);
820  }
821  }
822  }
823  return status;
824 }
825 
826 /*
827  * ======== cmm_xlator_info ========
828  * Purpose:
829  * Set/Get translator info.
830  */
831 int cmm_xlator_info(struct cmm_xlatorobject *xlator, u8 ** paddr,
832  u32 ul_size, u32 segm_id, bool set_info)
833 {
834  struct cmm_xlator *xlator_obj = (struct cmm_xlator *)xlator;
835  int status = 0;
836 
837  if (xlator_obj) {
838  if (set_info) {
839  /* set translators virtual address range */
840  xlator_obj->virt_base = (u32) *paddr;
841  xlator_obj->virt_size = ul_size;
842  } else { /* return virt base address */
843  *paddr = (u8 *) xlator_obj->virt_base;
844  }
845  } else {
846  status = -EFAULT;
847  }
848  return status;
849 }
850 
851 /*
852  * ======== cmm_xlator_translate ========
853  */
854 void *cmm_xlator_translate(struct cmm_xlatorobject *xlator, void *paddr,
855  enum cmm_xlatetype xtype)
856 {
857  u32 dw_addr_xlate = 0;
858  struct cmm_xlator *xlator_obj = (struct cmm_xlator *)xlator;
859  struct cmm_object *cmm_mgr_obj = NULL;
860  struct cmm_allocator *allocator = NULL;
861  u32 dw_offset = 0;
862 
863  if (!xlator_obj)
864  goto loop_cont;
865 
866  cmm_mgr_obj = (struct cmm_object *)xlator_obj->cmm_mgr;
867  /* get this translator's default SM allocator */
868  allocator = cmm_mgr_obj->pa_gppsm_seg_tab[xlator_obj->seg_id - 1];
869  if (!allocator)
870  goto loop_cont;
871 
872  if ((xtype == CMM_VA2DSPPA) || (xtype == CMM_VA2PA) ||
873  (xtype == CMM_PA2VA)) {
874  if (xtype == CMM_PA2VA) {
875  /* Gpp Va = Va Base + offset */
876  dw_offset = (u8 *) paddr - (u8 *) (allocator->shm_base -
877  allocator->
878  dsp_size);
879  dw_addr_xlate = xlator_obj->virt_base + dw_offset;
880  /* Check if translated Va base is in range */
881  if ((dw_addr_xlate < xlator_obj->virt_base) ||
882  (dw_addr_xlate >=
883  (xlator_obj->virt_base +
884  xlator_obj->virt_size))) {
885  dw_addr_xlate = 0; /* bad address */
886  }
887  } else {
888  /* Gpp PA = Gpp Base + offset */
889  dw_offset =
890  (u8 *) paddr - (u8 *) xlator_obj->virt_base;
891  dw_addr_xlate =
892  allocator->shm_base - allocator->dsp_size +
893  dw_offset;
894  }
895  } else {
896  dw_addr_xlate = (u32) paddr;
897  }
898  /*Now convert address to proper target physical address if needed */
899  if ((xtype == CMM_VA2DSPPA) || (xtype == CMM_PA2DSPPA)) {
900  /* Got Gpp Pa now, convert to DSP Pa */
901  dw_addr_xlate =
902  GPPPA2DSPPA((allocator->shm_base - allocator->dsp_size),
903  dw_addr_xlate,
904  allocator->dsp_phys_addr_offset *
905  allocator->c_factor);
906  } else if (xtype == CMM_DSPPA2PA) {
907  /* Got DSP Pa, convert to GPP Pa */
908  dw_addr_xlate =
909  DSPPA2GPPPA(allocator->shm_base - allocator->dsp_size,
910  dw_addr_xlate,
911  allocator->dsp_phys_addr_offset *
912  allocator->c_factor);
913  }
914 loop_cont:
915  return (void *)dw_addr_xlate;
916 }