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