/drivers/staging/tidspbridge/pmgr/dmm.c
C | 533 lines | 314 code | 68 blank | 151 comment | 56 complexity | 70255c569686f2e0ca7c6df972fb081c MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- /*
- * dmm.c
- *
- * DSP-BIOS Bridge driver support functions for TI OMAP processors.
- *
- * The Dynamic Memory Manager (DMM) module manages the DSP Virtual address
- * space that can be directly mapped to any MPU buffer or memory region
- *
- * Notes:
- * Region: Generic memory entitiy having a start address and a size
- * Chunk: Reserved region
- *
- * Copyright (C) 2005-2006 Texas Instruments, Inc.
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
- #include <linux/types.h>
- /* ----------------------------------- Host OS */
- #include <dspbridge/host_os.h>
- /* ----------------------------------- DSP/BIOS Bridge */
- #include <dspbridge/dbdefs.h>
- /* ----------------------------------- Trace & Debug */
- #include <dspbridge/dbc.h>
- /* ----------------------------------- OS Adaptation Layer */
- #include <dspbridge/sync.h>
- /* ----------------------------------- Platform Manager */
- #include <dspbridge/dev.h>
- #include <dspbridge/proc.h>
- /* ----------------------------------- This */
- #include <dspbridge/dmm.h>
- /* ----------------------------------- Defines, Data Structures, Typedefs */
- #define DMM_ADDR_VIRTUAL(a) \
- (((struct map_page *)(a) - virtual_mapping_table) * PG_SIZE4K +\
- dyn_mem_map_beg)
- #define DMM_ADDR_TO_INDEX(a) (((a) - dyn_mem_map_beg) / PG_SIZE4K)
- /* DMM Mgr */
- struct dmm_object {
- /* Dmm Lock is used to serialize access mem manager for
- * multi-threads. */
- spinlock_t dmm_lock; /* Lock to access dmm mgr */
- };
- /* ----------------------------------- Globals */
- static u32 refs; /* module reference count */
- struct map_page {
- u32 region_size:15;
- u32 mapped_size:15;
- u32 reserved:1;
- u32 mapped:1;
- };
- /* Create the free list */
- static struct map_page *virtual_mapping_table;
- static u32 free_region; /* The index of free region */
- static u32 free_size;
- static u32 dyn_mem_map_beg; /* The Beginning of dynamic memory mapping */
- static u32 table_size; /* The size of virt and phys pages tables */
- /* ----------------------------------- Function Prototypes */
- static struct map_page *get_region(u32 addr);
- static struct map_page *get_free_region(u32 len);
- static struct map_page *get_mapped_region(u32 addrs);
- /* ======== dmm_create_tables ========
- * Purpose:
- * Create table to hold the information of physical address
- * the buffer pages that is passed by the user, and the table
- * to hold the information of the virtual memory that is reserved
- * for DSP.
- */
- int dmm_create_tables(struct dmm_object *dmm_mgr, u32 addr, u32 size)
- {
- struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
- int status = 0;
- status = dmm_delete_tables(dmm_obj);
- if (!status) {
- dyn_mem_map_beg = addr;
- table_size = PG_ALIGN_HIGH(size, PG_SIZE4K) / PG_SIZE4K;
- /* Create the free list */
- virtual_mapping_table = __vmalloc(table_size *
- sizeof(struct map_page), GFP_KERNEL |
- __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
- if (virtual_mapping_table == NULL)
- status = -ENOMEM;
- else {
- /* On successful allocation,
- * all entries are zero ('free') */
- free_region = 0;
- free_size = table_size * PG_SIZE4K;
- virtual_mapping_table[0].region_size = table_size;
- }
- }
- if (status)
- pr_err("%s: failure, status 0x%x\n", __func__, status);
- return status;
- }
- /*
- * ======== dmm_create ========
- * Purpose:
- * Create a dynamic memory manager object.
- */
- int dmm_create(struct dmm_object **dmm_manager,
- struct dev_object *hdev_obj,
- const struct dmm_mgrattrs *mgr_attrts)
- {
- struct dmm_object *dmm_obj = NULL;
- int status = 0;
- DBC_REQUIRE(refs > 0);
- DBC_REQUIRE(dmm_manager != NULL);
- *dmm_manager = NULL;
- /* create, zero, and tag a cmm mgr object */
- dmm_obj = kzalloc(sizeof(struct dmm_object), GFP_KERNEL);
- if (dmm_obj != NULL) {
- spin_lock_init(&dmm_obj->dmm_lock);
- *dmm_manager = dmm_obj;
- } else {
- status = -ENOMEM;
- }
- return status;
- }
- /*
- * ======== dmm_destroy ========
- * Purpose:
- * Release the communication memory manager resources.
- */
- int dmm_destroy(struct dmm_object *dmm_mgr)
- {
- struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
- int status = 0;
- DBC_REQUIRE(refs > 0);
- if (dmm_mgr) {
- status = dmm_delete_tables(dmm_obj);
- if (!status)
- kfree(dmm_obj);
- } else
- status = -EFAULT;
- return status;
- }
- /*
- * ======== dmm_delete_tables ========
- * Purpose:
- * Delete DMM Tables.
- */
- int dmm_delete_tables(struct dmm_object *dmm_mgr)
- {
- int status = 0;
- DBC_REQUIRE(refs > 0);
- /* Delete all DMM tables */
- if (dmm_mgr)
- vfree(virtual_mapping_table);
- else
- status = -EFAULT;
- return status;
- }
- /*
- * ======== dmm_exit ========
- * Purpose:
- * Discontinue usage of module; free resources when reference count
- * reaches 0.
- */
- void dmm_exit(void)
- {
- DBC_REQUIRE(refs > 0);
- refs--;
- }
- /*
- * ======== dmm_get_handle ========
- * Purpose:
- * Return the dynamic memory manager object for this device.
- * This is typically called from the client process.
- */
- int dmm_get_handle(void *hprocessor, struct dmm_object **dmm_manager)
- {
- int status = 0;
- struct dev_object *hdev_obj;
- DBC_REQUIRE(refs > 0);
- DBC_REQUIRE(dmm_manager != NULL);
- if (hprocessor != NULL)
- status = proc_get_dev_object(hprocessor, &hdev_obj);
- else
- hdev_obj = dev_get_first(); /* default */
- if (!status)
- status = dev_get_dmm_mgr(hdev_obj, dmm_manager);
- return status;
- }
- /*
- * ======== dmm_init ========
- * Purpose:
- * Initializes private state of DMM module.
- */
- bool dmm_init(void)
- {
- bool ret = true;
- DBC_REQUIRE(refs >= 0);
- if (ret)
- refs++;
- DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
- virtual_mapping_table = NULL;
- table_size = 0;
- return ret;
- }
- /*
- * ======== dmm_map_memory ========
- * Purpose:
- * Add a mapping block to the reserved chunk. DMM assumes that this block
- * will be mapped in the DSP/IVA's address space. DMM returns an error if a
- * mapping overlaps another one. This function stores the info that will be
- * required later while unmapping the block.
- */