GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Copyright (c) XMEDIA. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/list.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <linux/version.h>
|
||||
#include "allocator.h"
|
||||
|
||||
#ifndef fallthrough
|
||||
#define fallthrough
|
||||
#endif
|
||||
|
||||
extern struct osal_list_head mmz_list;
|
||||
|
||||
long long max_malloc_size = 0x40000000UL;
|
||||
|
||||
static unsigned long _strtoul_ex(const char *s, char **ep, unsigned int base)
|
||||
{
|
||||
char *__end_p = NULL;
|
||||
unsigned long __value;
|
||||
|
||||
__value = simple_strtoul(s, &__end_p, base);
|
||||
|
||||
switch (*__end_p) {
|
||||
case 'm':
|
||||
fallthrough;
|
||||
case 'M':
|
||||
__value <<= 10;
|
||||
fallthrough;
|
||||
case 'k':
|
||||
fallthrough;
|
||||
case 'K':
|
||||
__value <<= 10;
|
||||
if (ep != NULL) {
|
||||
(*ep) = __end_p + 1;
|
||||
}
|
||||
fallthrough;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return __value;
|
||||
}
|
||||
|
||||
static unsigned long find_fixed_region(unsigned long *region_len,
|
||||
mmz_mmz_t *mmz,
|
||||
unsigned long size,
|
||||
unsigned long align)
|
||||
{
|
||||
unsigned long start;
|
||||
unsigned long fixed_start = 0;
|
||||
unsigned long fixed_len = -1;
|
||||
unsigned long len = 0;
|
||||
unsigned long blank_len = 0;
|
||||
mmz_mmb_t *p = NULL;
|
||||
|
||||
mmz_trace_func();
|
||||
align = mmz_grain_align(align);
|
||||
if (align == 0) {
|
||||
align = MMZ_GRAIN;
|
||||
}
|
||||
start = mmz_align2(mmz->phys_start, align);
|
||||
len = mmz_grain_align(size);
|
||||
|
||||
list_for_each_entry(p, &mmz->mmb_list, list) {
|
||||
mmz_mmb_t *next = NULL;
|
||||
mmz_trace(4, "p->phys_addr=0x%08lX p->length = %luKB \t",
|
||||
p->phys_addr, p->length / SZ_1K);
|
||||
next = list_entry(p->list.next, typeof(*p), list);
|
||||
mmz_trace(4, ",next = 0x%08lX\n\n", next->phys_addr);
|
||||
/*
|
||||
* if p is the first entry or not.
|
||||
*/
|
||||
if (list_first_entry(&mmz->mmb_list, typeof(*p), list) == p) {
|
||||
blank_len = p->phys_addr - start;
|
||||
if ((blank_len < fixed_len) && (blank_len >= len)) {
|
||||
fixed_len = blank_len;
|
||||
fixed_start = start;
|
||||
mmz_trace(4, "%d: fixed_region: start=0x%08lX, len=%luKB\n",
|
||||
__LINE__, fixed_start, fixed_len / SZ_1K);
|
||||
}
|
||||
}
|
||||
start = mmz_align2((p->phys_addr + p->length), align);
|
||||
/*
|
||||
* if aglin is larger than mmz->nbytes, it would trigger the BUG_ON
|
||||
*/
|
||||
// BUG_ON((start < mmz->phys_start) || (start > (mmz->phys_start + mmz->nbytes)));
|
||||
/*
|
||||
* if we have to alloc after the last node.
|
||||
*/
|
||||
if (osal_list_is_last(&p->list, &mmz->mmb_list)) {
|
||||
blank_len = mmz->phys_start + mmz->nbytes - start;
|
||||
if ((blank_len < fixed_len) && (blank_len >= len)) {
|
||||
fixed_len = blank_len;
|
||||
fixed_start = start;
|
||||
mmz_trace(4, "fixed_region: start=0x%08lX, len=%luKB\n",
|
||||
fixed_start, fixed_len / SZ_1K);
|
||||
break;
|
||||
} else {
|
||||
if (fixed_len != -1) {
|
||||
goto out;
|
||||
}
|
||||
fixed_start = 0;
|
||||
mmz_trace(4, "fixed_region: start=0x%08lX, len=%luKB\n",
|
||||
fixed_start, fixed_len / SZ_1K);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* blank is too small */
|
||||
if ((start + len) > next->phys_addr) {
|
||||
mmz_trace(4, "start=0x%08lX ,len=%lu,next=0x%08lX\n",
|
||||
start, len, next->phys_addr);
|
||||
continue;
|
||||
}
|
||||
blank_len = next->phys_addr - start;
|
||||
if ((blank_len < fixed_len) && (blank_len >= len)) {
|
||||
fixed_len = blank_len;
|
||||
fixed_start = start;
|
||||
mmz_trace(4, "fixed_region: start=0x%08lX, len=%luKB\n",
|
||||
fixed_start, fixed_len / SZ_1K);
|
||||
}
|
||||
}
|
||||
|
||||
if ((mmz_grain_align(start + len) <= (mmz->phys_start + mmz->nbytes)) &&
|
||||
(start >= mmz->phys_start) &&
|
||||
(start < (mmz->phys_start + mmz->nbytes))) {
|
||||
fixed_len = len;
|
||||
fixed_start = start;
|
||||
mmz_trace(4, "fixed_region: start=0x%08lX, len=%luKB\n",
|
||||
fixed_start, fixed_len / SZ_1K);
|
||||
} else {
|
||||
fixed_start = 0;
|
||||
mmz_trace(4, "fixed_region: start=0x%08lX, len=%luKB\n",
|
||||
fixed_start, len / SZ_1K);
|
||||
}
|
||||
out:
|
||||
*region_len = len;
|
||||
return fixed_start;
|
||||
}
|
||||
|
||||
static int do_mmb_alloc(mmz_mmb_t *mmb)
|
||||
{
|
||||
mmz_mmb_t *p = NULL;
|
||||
mmz_trace_func();
|
||||
|
||||
/* add mmb sorted */
|
||||
osal_list_for_each_entry(p, &mmb->zone->mmb_list, list) {
|
||||
if (mmb->phys_addr < p->phys_addr) {
|
||||
break;
|
||||
}
|
||||
if (mmb->phys_addr == p->phys_addr) {
|
||||
printk(KERN_ERR "ERROR: media-mem allocator bad in %s! (%s, %d)",
|
||||
mmb->zone->name, __FUNCTION__, __LINE__);
|
||||
}
|
||||
}
|
||||
osal_list_add(&mmb->list, p->list.prev);
|
||||
|
||||
mmz_trace(1, MMZ_MMB_FMT_S, mmz_mmb_fmt_arg(mmb));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mmz_mmb_t *__mmb_alloc(const char *name,
|
||||
unsigned long size,
|
||||
unsigned long align,
|
||||
unsigned long gfp,
|
||||
const char *mmz_name,
|
||||
mmz_mmz_t *_user_mmz)
|
||||
{
|
||||
mmz_mmz_t *mmz = NULL;
|
||||
mmz_mmb_t *mmb = NULL;
|
||||
|
||||
unsigned long start;
|
||||
unsigned long region_len;
|
||||
|
||||
unsigned long fixed_start = 0;
|
||||
unsigned long fixed_len = ~1;
|
||||
mmz_mmz_t *fixed_mmz = NULL;
|
||||
|
||||
mmz_trace_func();
|
||||
|
||||
if ((size == 0) || (size > max_malloc_size)) {
|
||||
return NULL;
|
||||
}
|
||||
if (align == 0) {
|
||||
align = MMZ_GRAIN;
|
||||
}
|
||||
|
||||
size = mmz_grain_align(size);
|
||||
|
||||
mmz_trace(1, "size=%luKB, align=%lu", size / SZ_1K, align);
|
||||
|
||||
begin_list_for_each_mmz(mmz, gfp, mmz_name)
|
||||
|
||||
if ((_user_mmz != NULL) && (_user_mmz != mmz)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
start = find_fixed_region(®ion_len, mmz, size, align);
|
||||
if ((fixed_len > region_len) && (start != 0)) {
|
||||
fixed_len = region_len;
|
||||
fixed_start = start;
|
||||
fixed_mmz = mmz;
|
||||
}
|
||||
end_list_for_each_mmz()
|
||||
|
||||
if (fixed_mmz == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mmb = kmalloc(sizeof(mmz_mmb_t), GFP_KERNEL);
|
||||
if (mmb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(mmb, 0, sizeof(mmz_mmb_t));
|
||||
mmb->zone = fixed_mmz;
|
||||
mmb->phys_addr = fixed_start;
|
||||
mmb->length = size;
|
||||
if (name != NULL) {
|
||||
strlcpy(mmb->name, name, MMZ_MMB_NAME_LEN);
|
||||
} else {
|
||||
strncpy(mmb->name, "<null>", MMZ_MMB_NAME_LEN);
|
||||
}
|
||||
|
||||
if (do_mmb_alloc(mmb)) {
|
||||
kfree(mmb);
|
||||
mmb = NULL;
|
||||
}
|
||||
|
||||
return mmb;
|
||||
}
|
||||
|
||||
static void *__mmb_map2kern(mmz_mmb_t *mmb, int cached)
|
||||
{
|
||||
/*
|
||||
* already mapped? no need to remap again,
|
||||
* just return mmb's kernel virtual address.
|
||||
*/
|
||||
if (mmb->flags & MMZ_MMB_MAP2KERN) {
|
||||
if ((!!cached * MMZ_MMB_MAP2KERN_CACHED) != (mmb->flags & MMZ_MMB_MAP2KERN_CACHED)) {
|
||||
printk(KERN_ERR "mmb<%s> has been kernel-mapped as %s, \
|
||||
can not be re-mapped as %s.",
|
||||
mmb->name,
|
||||
(mmb->flags & MMZ_MMB_MAP2KERN_CACHED) ? "cached" : "non-cached",
|
||||
(cached) ? "cached" : "non-cached");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mmb->map_ref++;
|
||||
|
||||
return mmb->kvirt;
|
||||
}
|
||||
|
||||
if (cached) {
|
||||
mmb->flags |= MMZ_MMB_MAP2KERN_CACHED;
|
||||
mmb->kvirt = ioremap_cache(mmb->phys_addr, mmb->length);
|
||||
} else {
|
||||
mmb->flags &= ~MMZ_MMB_MAP2KERN_CACHED;
|
||||
/* ioremap_wc has better performance */
|
||||
mmb->kvirt = ioremap_wc(mmb->phys_addr, mmb->length);
|
||||
}
|
||||
|
||||
if (mmb->kvirt) {
|
||||
mmb->flags |= MMZ_MMB_MAP2KERN;
|
||||
mmb->map_ref++;
|
||||
} else {
|
||||
mmb->flags &= ~MMZ_MMB_MAP2KERN_CACHED;
|
||||
}
|
||||
|
||||
return mmb->kvirt;
|
||||
}
|
||||
|
||||
static void __mmb_free(mmz_mmb_t *mmb)
|
||||
{
|
||||
if (mmb->flags & MMZ_MMB_MAP2KERN_CACHED) {
|
||||
#ifdef CONFIG_64BIT
|
||||
__flush_dcache_area((void *)mmb->kvirt, (size_t)mmb->length);
|
||||
#else
|
||||
__cpuc_flush_dcache_area((void *)mmb->kvirt, (size_t)mmb->length);
|
||||
outer_flush_range(mmb->phys_addr, mmb->phys_addr + mmb->length);
|
||||
#endif
|
||||
}
|
||||
|
||||
osal_list_del(&mmb->list);
|
||||
kfree(mmb);
|
||||
}
|
||||
|
||||
static int __mmb_unmap(mmz_mmb_t *mmb)
|
||||
{
|
||||
int ref;
|
||||
|
||||
if (mmb->flags & MMZ_MMB_MAP2KERN_CACHED) {
|
||||
#ifdef CONFIG_64BIT
|
||||
__flush_dcache_area((void *)mmb->kvirt, (size_t)mmb->length);
|
||||
#else
|
||||
__cpuc_flush_dcache_area((void *)mmb->kvirt, (size_t)mmb->length);
|
||||
outer_flush_range(mmb->phys_addr, mmb->phys_addr + mmb->length);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (mmb->flags & MMZ_MMB_MAP2KERN) {
|
||||
ref = --mmb->map_ref;
|
||||
if (mmb->map_ref != 0) {
|
||||
return ref;
|
||||
}
|
||||
iounmap(mmb->kvirt);
|
||||
}
|
||||
|
||||
mmb->kvirt = NULL;
|
||||
mmb->flags &= ~MMZ_MMB_MAP2KERN;
|
||||
mmb->flags &= ~MMZ_MMB_MAP2KERN_CACHED;
|
||||
|
||||
if ((mmb->flags & MMZ_MMB_RELEASED) && (mmb->phy_ref == 0)) {
|
||||
__mmb_free(mmb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *__mmf_map(phys_addr_t phys, int len, int cache)
|
||||
{
|
||||
void *virt = NULL;
|
||||
if (cache) {
|
||||
virt = ioremap_cache(phys, len);
|
||||
} else {
|
||||
virt = ioremap_wc(phys, len);
|
||||
}
|
||||
|
||||
return virt;
|
||||
}
|
||||
|
||||
static void __mmf_unmap(void *virt)
|
||||
{
|
||||
if (virt != NULL) {
|
||||
iounmap(virt);
|
||||
}
|
||||
}
|
||||
|
||||
static int __allocator_init(char *s)
|
||||
{
|
||||
mmz_mmz_t *zone = NULL;
|
||||
char *line = NULL;
|
||||
unsigned long phys_end = 0;
|
||||
|
||||
while ((line = strsep(&s, ":")) != NULL) {
|
||||
int i;
|
||||
char *argv[6];
|
||||
|
||||
for (i = 0; (argv[i] = strsep(&line, ",")) != NULL;)
|
||||
if (++i == ARRAY_SIZE(argv)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 4) {
|
||||
zone = mmz_mmz_create("null", 0, 0, 0);
|
||||
if (zone == NULL) {
|
||||
continue;
|
||||
}
|
||||
strlcpy(zone->name, argv[0], MMZ_MMZ_NAME_LEN);
|
||||
zone->gfp = _strtoul_ex(argv[1], NULL, 0);
|
||||
zone->phys_start = _strtoul_ex(argv[2], NULL, 0);
|
||||
zone->nbytes = _strtoul_ex(argv[3], NULL, 0);
|
||||
if (zone->nbytes > max_malloc_size) {
|
||||
max_malloc_size = zone->nbytes;
|
||||
}
|
||||
} else {
|
||||
printk(KERN_ERR "error parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// mmz_info_phys_start = zone->phys_start + zone->nbytes - 0x2000;
|
||||
|
||||
if (mmz_mmz_register(zone)) {
|
||||
printk(KERN_WARNING "Add MMZ failed: " MMZ_MMZ_FMT_S "\n", mmz_mmz_fmt_arg(zone));
|
||||
mmz_mmz_destroy(zone);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if phys_end is 0xFFFFFFFF (32bit)
|
||||
phys_end = (zone->phys_start + zone->nbytes);
|
||||
|
||||
if ((phys_end == 0) && (zone->nbytes >= PAGE_SIZE)) {
|
||||
// reserve last PAGE_SIZE memory
|
||||
zone->nbytes = zone->nbytes - PAGE_SIZE;
|
||||
}
|
||||
|
||||
// if phys_end exceed 0xFFFFFFFF (32bit), wraping error
|
||||
if ((zone->phys_start > phys_end) && (phys_end != 0)) {
|
||||
printk(KERN_ERR "MMZ: parameter is not correct! Address exceeds 0xFFFFFFFF\n");
|
||||
mmz_mmz_unregister(zone);
|
||||
mmz_mmz_destroy(zone);
|
||||
return -1;
|
||||
}
|
||||
zone = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int allocator_setopt(struct mmz_allocator *allocator)
|
||||
{
|
||||
allocator->init = __allocator_init;
|
||||
allocator->mmb_alloc = __mmb_alloc;
|
||||
allocator->mmb_map2kern = __mmb_map2kern;
|
||||
allocator->mmb_unmap = __mmb_unmap;
|
||||
allocator->mmb_free = __mmb_free;
|
||||
allocator->mmf_map = __mmf_map;
|
||||
allocator->mmf_unmap = __mmf_unmap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) XMEDIA. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __ALLOCATOR_H__
|
||||
#define __ALLOCATOR_H__
|
||||
|
||||
#include <linux/device.h>
|
||||
#include "osal_mmz.h"
|
||||
|
||||
#define NAME_LEN_MAX 64
|
||||
|
||||
struct mmz_allocator {
|
||||
int (*init)(char *args);
|
||||
mmz_mmb_t *(*mmb_alloc)(const char *name,
|
||||
unsigned long size,
|
||||
unsigned long align,
|
||||
unsigned long gfp,
|
||||
const char *mmz_name,
|
||||
mmz_mmz_t *_user_mmz);
|
||||
void *(*mmb_map2kern)(mmz_mmb_t *mmb, int cached);
|
||||
int (*mmb_unmap)(mmz_mmb_t *mmb);
|
||||
void (*mmb_free)(mmz_mmb_t *mmb);
|
||||
void *(*mmf_map)(phys_addr_t phys, int len, int cache);
|
||||
void (*mmf_unmap)(void *virt);
|
||||
};
|
||||
|
||||
int cma_allocator_setopt(struct mmz_allocator *allocator);
|
||||
int allocator_setopt(struct mmz_allocator *allocator);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Copyright (c) XMEDIA. All rights reserved.
|
||||
*/
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/list.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include <asm/memory.h>
|
||||
#include <linux/dma-contiguous.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <asm/memory.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "allocator.h"
|
||||
#include "mmz_arm.h"
|
||||
|
||||
#define __use_vmalloc_space 1
|
||||
|
||||
struct cma_zone {
|
||||
struct device pdev;
|
||||
char name[NAME_LEN_MAX];
|
||||
unsigned long gfp;
|
||||
unsigned long phys_start;
|
||||
unsigned long nbytes;
|
||||
unsigned int alloc_type;
|
||||
unsigned long block_align;
|
||||
};
|
||||
|
||||
extern struct osal_list_head mmz_list;
|
||||
|
||||
long long max_malloc_size = 0x40000000UL;
|
||||
|
||||
static int do_mmb_alloc(mmz_mmb_t *mmb)
|
||||
{
|
||||
mmz_mmb_t *p = NULL;
|
||||
mmz_trace_func();
|
||||
|
||||
/* add mmb into zone, sorted */
|
||||
osal_list_for_each_entry(p, &mmb->zone->mmb_list, list) {
|
||||
if (mmb->phys_addr < p->phys_addr) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mmb->phys_addr == p->phys_addr) {
|
||||
pr_err("ERROR:cma allocator bad in %s(%s, %d)",
|
||||
mmb->zone->name, __func__, __LINE__);
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
osal_list_add(&mmb->list, p->list.prev);
|
||||
mmz_trace(1, MMZ_MMB_FMT_S, mmz_mmb_fmt_arg(mmb));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mmz_mmb_t *__mmb_alloc(const char *name,
|
||||
unsigned long size,
|
||||
unsigned long align,
|
||||
unsigned long gfp,
|
||||
const char *mmz_name,
|
||||
mmz_mmz_t *_user_mmz)
|
||||
{
|
||||
mmz_mmz_t *mmz = NULL;
|
||||
mmz_mmb_t *mmb = NULL;
|
||||
unsigned long order = get_order(size);
|
||||
size_t count = size >> PAGE_SHIFT;
|
||||
struct page *page = NULL;
|
||||
|
||||
mmz_trace_func();
|
||||
|
||||
/*
|
||||
* No zero length memory request, no supper
|
||||
* large memory (4GB and above) request.
|
||||
*/
|
||||
if ((size == 0) || (size > max_malloc_size)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (align == 0) {
|
||||
align = MMZ_GRAIN;
|
||||
}
|
||||
|
||||
size = mmz_grain_align(size);
|
||||
order = get_order(size);
|
||||
count = size >> PAGE_SHIFT;
|
||||
|
||||
mmz_trace(1, "anonymous=%s,size=%luKB,align=%lu", mmz_name, size / SZ_1K, align);
|
||||
|
||||
begin_list_for_each_mmz(mmz, gfp, mmz_name)
|
||||
|
||||
if ((_user_mmz != NULL) && (_user_mmz != mmz)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
page = dma_alloc_from_contiguous(mmz->cma_dev, count, order);
|
||||
if (page == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get it */
|
||||
break;
|
||||
end_list_for_each_mmz()
|
||||
|
||||
if (page == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* clear the allocated buffer, if needed! */
|
||||
dma_buffer_clear(page, size);
|
||||
|
||||
mmb = kmalloc(sizeof(mmz_mmb_t), GFP_KERNEL);
|
||||
if (mmb == NULL) {
|
||||
pr_err("<%s,%d> mmb struct alloc failed\n", __func__, __LINE__);
|
||||
goto cma_free;
|
||||
}
|
||||
|
||||
memset(mmb, 0, sizeof(mmz_mmb_t));
|
||||
mmb->zone = mmz;
|
||||
mmb->phys_addr = page_to_phys(page);
|
||||
mmb->length = size;
|
||||
|
||||
if (name != NULL) {
|
||||
strlcpy(mmb->name, name, MMZ_MMB_NAME_LEN);
|
||||
} else {
|
||||
strncpy(mmb->name, "<null>", MMZ_MMB_NAME_LEN - 1);
|
||||
}
|
||||
|
||||
if (do_mmb_alloc(mmb)) {
|
||||
goto mmb_free;
|
||||
}
|
||||
|
||||
return mmb;
|
||||
|
||||
mmb_free:
|
||||
kfree(mmb);
|
||||
cma_free:
|
||||
dma_release_from_contiguous(mmz->cma_dev, page, count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void __mmb_free(mmz_mmb_t *mmb)
|
||||
{
|
||||
size_t count = mmb->length >> PAGE_SHIFT;
|
||||
struct page *page = phys_to_page(mmb->phys_addr);
|
||||
|
||||
mmz_mmz_t *mmz = mmb->zone;
|
||||
|
||||
if (mmb->flags & MMZ_MMB_MAP2KERN_CACHED) {
|
||||
mmb_dcache_flush(mmb);
|
||||
}
|
||||
|
||||
dma_release_from_contiguous(mmz->cma_dev, page, count);
|
||||
|
||||
osal_list_del(&mmb->list);
|
||||
kfree(mmb);
|
||||
}
|
||||
|
||||
static void *__mmb_map2kern(mmz_mmb_t *mmb, int cached)
|
||||
{
|
||||
pgprot_t prot;
|
||||
struct page *page = phys_to_page(mmb->phys_addr);
|
||||
|
||||
mmz_trace(1, "mmb[phys_addr=%lx,kvirt=%pK,length=%lx]",
|
||||
mmb->phys_addr, mmb->kvirt, mmb->length);
|
||||
|
||||
if (mmb->flags & MMZ_MMB_MAP2KERN) {
|
||||
if ((!!cached * MMZ_MMB_MAP2KERN_CACHED) != (mmb->flags & MMZ_MMB_MAP2KERN_CACHED)) {
|
||||
pr_err("mmb<%s> has been kernel-mapped %s, \
|
||||
can not be re-mapped as %s.",
|
||||
mmb->name,
|
||||
(mmb->flags & MMZ_MMB_MAP2KERN_CACHED) ? "cached" : "non-cached",
|
||||
(cached) ? "cached" : "non-cached");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mmz_trace(1, "map[%lx --> %pK]", mmb->phys_addr, mmb->kvirt);
|
||||
|
||||
mmb->map_ref++;
|
||||
return mmb->kvirt;
|
||||
}
|
||||
|
||||
prot = arch_kern_pgprot(cached);
|
||||
|
||||
#if __use_vmalloc_space
|
||||
/*
|
||||
* Map into vmalloc space
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
struct page **pages = NULL;
|
||||
unsigned int pagesnr = mmb->length / PAGE_SIZE;
|
||||
struct page *tmp = page;
|
||||
int array_size = sizeof(struct page *) * pagesnr;
|
||||
|
||||
/*
|
||||
* Noted: mmb->length would be very large in some cases(for example:
|
||||
* more than one Giga Bytes). and array_size would be very large as
|
||||
* well. So, don't use kmalloc here.
|
||||
*/
|
||||
pages = vmalloc(array_size);
|
||||
if (pages == NULL) {
|
||||
pr_err("ptr array(0x%x) vmalloc failed.\n", array_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < pagesnr; i++) {
|
||||
*(pages + i) = tmp;
|
||||
tmp++;
|
||||
}
|
||||
|
||||
mmb->kvirt = vmap(pages, pagesnr, VM_MAP, prot);
|
||||
vfree(pages);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Map into linear space
|
||||
*/
|
||||
{
|
||||
dma_pages_remap(page, mmb->length, prot);
|
||||
mmb->kvirt = __va(mmb->phys_addr);
|
||||
}
|
||||
#endif
|
||||
if (mmb->kvirt == NULL) {
|
||||
/*
|
||||
* you should never get here.
|
||||
*/
|
||||
printk(KERN_ERR "mmb[0x%lx, 0x%lx] map to kernel failed\n",
|
||||
mmb->phys_addr, mmb->length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cached) {
|
||||
mmb->flags |= MMZ_MMB_MAP2KERN_CACHED;
|
||||
} else {
|
||||
mmb->flags &= ~MMZ_MMB_MAP2KERN_CACHED;
|
||||
}
|
||||
mmb->flags |= MMZ_MMB_MAP2KERN;
|
||||
mmb->map_ref++;
|
||||
|
||||
mmz_trace(1, "map[%lx --> %pK]", mmb->phys_addr, mmb->kvirt);
|
||||
|
||||
return mmb->kvirt;
|
||||
}
|
||||
|
||||
static int __mmb_unmap(mmz_mmb_t *mmb)
|
||||
{
|
||||
int ref;
|
||||
|
||||
mmz_trace(1, "mmb[phys_addr=%lx,kvirt=%pK,length=%lx]",
|
||||
mmb->phys_addr, mmb->kvirt, mmb->length);
|
||||
|
||||
if (mmb->flags & MMZ_MMB_MAP2KERN_CACHED) {
|
||||
mmb_dcache_flush(mmb);
|
||||
}
|
||||
|
||||
if (mmb->flags & MMZ_MMB_MAP2KERN) {
|
||||
ref = --mmb->map_ref;
|
||||
if (mmb->map_ref != 0) {
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
|
||||
#if __use_vmalloc_space
|
||||
/*
|
||||
* unmap from vmalloc space.
|
||||
*/
|
||||
{
|
||||
vunmap(mmb->kvirt);
|
||||
}
|
||||
#endif
|
||||
mmb->kvirt = NULL;
|
||||
mmb->flags &= ~MMZ_MMB_MAP2KERN;
|
||||
mmb->flags &= ~MMZ_MMB_MAP2KERN_CACHED;
|
||||
|
||||
if ((mmb->flags & MMZ_MMB_RELEASED) && (mmb->phy_ref == 0)) {
|
||||
__mmb_free(mmb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map any valid phys address passed by users, to virtual address.
|
||||
* The input phys may not be 4Kbytes aligned.
|
||||
* FIXME
|
||||
*/
|
||||
static void *__mmf_map(phys_addr_t phys, int len, int cache)
|
||||
{
|
||||
struct page **pages = NULL;
|
||||
unsigned int pagesnr = len / PAGE_SIZE;
|
||||
int i;
|
||||
void *virt = NULL;
|
||||
pgprot_t prot;
|
||||
struct page *page = phys_to_page(phys);
|
||||
struct page *tmp = page;
|
||||
int array_size;
|
||||
|
||||
mmz_trace(1, "phys=%lx, len=0x%x, cache=%d", (unsigned long)phys, len, cache);
|
||||
|
||||
/*
|
||||
* if the given phys is not page aligned, we need to
|
||||
* map one more page for the leftover.
|
||||
*/
|
||||
if (((phys & 0xfff) + len) > PAGE_SIZE) {
|
||||
pagesnr += 1;
|
||||
}
|
||||
|
||||
array_size = sizeof(struct page *) * pagesnr;
|
||||
|
||||
prot = arch_kern_pgprot(cache);
|
||||
|
||||
#if __use_vmalloc_space
|
||||
/*
|
||||
* Map into vmalloc space.
|
||||
*/
|
||||
{
|
||||
/*
|
||||
* Noted: length of region may be very large in some cases(for example:
|
||||
* more than one Giga Bytes). and array_size would be very large as
|
||||
* well. So, don't use kmalloc here.
|
||||
*/
|
||||
pages = vmalloc(array_size);
|
||||
if (pages == NULL) {
|
||||
printk(KERN_ERR "ptr vmalloc %d failed.\n", array_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < pagesnr; i++) {
|
||||
*(pages + i) = tmp;
|
||||
tmp++;
|
||||
}
|
||||
|
||||
virt = vmap(pages, pagesnr, VM_MAP, prot);
|
||||
vfree(pages);
|
||||
|
||||
if (virt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virt += (phys & 0xfff);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Map into linear space
|
||||
*/
|
||||
{
|
||||
dma_pages_remap(page, len, prot);
|
||||
virt = __va(phys);
|
||||
}
|
||||
#endif
|
||||
|
||||
mmz_trace(1, "map[%lx --> %pK]", (unsigned long)phys, virt);
|
||||
|
||||
return virt;
|
||||
}
|
||||
|
||||
static void __mmf_unmap(void *virt)
|
||||
{
|
||||
unsigned long vaddr = (unsigned long)(uintptr_t)virt;
|
||||
|
||||
mmz_trace(1, "virt=%pK", virt);
|
||||
|
||||
/*
|
||||
* virtual address to be vunmaped should be page aligned
|
||||
*/
|
||||
vaddr &= 0xfffff000;
|
||||
|
||||
if ((vaddr >= VMALLOC_START) && (vaddr < VMALLOC_END)) {
|
||||
vunmap ((void *)(uintptr_t)vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
static int __allocator_init(char *s)
|
||||
{
|
||||
#ifdef CONFIG_CMA
|
||||
mmz_mmz_t *zone = NULL;
|
||||
char *line = NULL;
|
||||
struct cma_zone *cma_zone = NULL;
|
||||
|
||||
while ((line = strsep(&s, ":")) != NULL) {
|
||||
int i;
|
||||
char *argv[6];
|
||||
extern struct cma_zone *get_cma_zone(const char *name);
|
||||
/*
|
||||
* FIXME: We got 4 args in "line", formated as
|
||||
* "argv[0],argv[1],argv[2],argv[3],argv[4]".
|
||||
* eg: "<mmz_name>,<gfp>,<phys_start>,<size>,<alloc_type>"
|
||||
* For more convenient, "hard code" are used such as "arg[0]", i.e.
|
||||
*/
|
||||
for (i = 0; (argv[i] = strsep(&line, ",")) != NULL;)
|
||||
if (++i == ARRAY_SIZE(argv)) {
|
||||
break;
|
||||
}
|
||||
|
||||
cma_zone = get_cma_zone(argv[0]);
|
||||
if (cma_zone == NULL) {
|
||||
printk(KERN_ERR "can't get cma zone info:%s\n", argv[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 4) {
|
||||
zone = mmz_mmz_create("null", 0, 0, 0);
|
||||
if (zone == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
strlcpy(zone->name, argv[0], MMZ_MMZ_NAME_LEN);
|
||||
|
||||
printk("cmz zone gfp 0x%lx, phys 0x%lx, nbytes 0x%lx\n",
|
||||
cma_zone->gfp,
|
||||
cma_zone->phys_start,
|
||||
cma_zone->nbytes);
|
||||
zone->gfp = cma_zone->gfp;
|
||||
zone->phys_start = cma_zone->phys_start;
|
||||
zone->nbytes = cma_zone->nbytes;
|
||||
zone->cma_dev = &cma_zone->pdev;
|
||||
|
||||
if (zone->nbytes > max_malloc_size) {
|
||||
max_malloc_size = zone->nbytes;
|
||||
}
|
||||
} else {
|
||||
printk(KERN_ERR "Input parameter num incorrect!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mmz_mmz_register(zone)) {
|
||||
printk(KERN_WARNING "Add MMZ failed: " MMZ_MMZ_FMT_S "\n",
|
||||
mmz_mmz_fmt_arg(zone));
|
||||
mmz_mmz_destroy(zone);
|
||||
}
|
||||
|
||||
zone = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cma_allocator_setopt(struct mmz_allocator *allocator)
|
||||
{
|
||||
allocator->init = __allocator_init;
|
||||
allocator->mmb_alloc = __mmb_alloc;
|
||||
allocator->mmb_map2kern = __mmb_map2kern;
|
||||
allocator->mmb_unmap = __mmb_unmap;
|
||||
allocator->mmb_free = __mmb_free;
|
||||
allocator->mmf_map = __mmf_map;
|
||||
allocator->mmf_unmap = __mmf_unmap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) XMEDIA. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/slab.h>
|
||||
#include "osal.h"
|
||||
#include "osal_mmz.h"
|
||||
#define MMZ_NAME "anonymous"
|
||||
|
||||
unsigned long long mmz_alloc(const char *mmz_name, const char *buf_name, unsigned long size)
|
||||
{
|
||||
mmz_mmb_t *pmmb = NULL;
|
||||
|
||||
pmmb = mmz_mmb_alloc(buf_name, size, 0, 0, mmz_name);
|
||||
if (pmmb == NULL) {
|
||||
osal_printk("Mmz malloc failed!\n");
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
return mmz_mmb_phys(pmmb);
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_alloc);
|
||||
|
||||
void mmz_free(unsigned long long phy_addr)
|
||||
{
|
||||
mmz_mmb_freeby_phys(phy_addr);
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_free);
|
||||
|
||||
void *mmz_map(unsigned long long phy_addr, unsigned long size, bool cached)
|
||||
{
|
||||
mmz_mmb_t *pmmb = NULL;
|
||||
void *vir_addr = NULL;
|
||||
unsigned long offset;
|
||||
|
||||
pmmb = mmz_mmb_getby_phys_2(phy_addr, &offset);
|
||||
if ( pmmb == NULL ) {
|
||||
osal_printk("mmz remap cache get mmz_mmb failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size == 0 || size + offset > pmmb->length) {
|
||||
osal_printk("mmz remap size(0x%lx) is zero or bigger than mmb size(0x%lx)", size, pmmb->length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( cached == 1 ) {
|
||||
vir_addr = mmz_mmb_map2kern_cached(pmmb);
|
||||
} else {
|
||||
vir_addr = mmz_mmb_map2kern(pmmb);
|
||||
}
|
||||
if (vir_addr == NULL) {
|
||||
osal_printk("mmz remap failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vir_addr + offset;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_map);
|
||||
|
||||
void mmz_unmap(void *vir_addr)
|
||||
{
|
||||
if (vir_addr != NULL) {
|
||||
mmz_mmb_t *pmmb = mmz_mmb_getby_kvirt(vir_addr);
|
||||
|
||||
if (pmmb != NULL) {
|
||||
mmz_mmb_unmap(pmmb);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_unmap);
|
||||
|
||||
int mmz_check_phyaddr(unsigned long long phy_addr, unsigned long len)
|
||||
{
|
||||
/* if address in mmz of current system */
|
||||
if (mmz_is_phys_in_mmz(phy_addr, len))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_check_phyaddr);
|
||||
|
||||
int mmz_flush_cache(unsigned long phy_addr, void *kvirt, unsigned long length)
|
||||
{
|
||||
mmz_mmb_t *pmmb = NULL;
|
||||
unsigned long offset;
|
||||
|
||||
/*err address flush maybe panic so judge input parameter*/
|
||||
pmmb = mmz_mmb_getby_phys_2(phy_addr, &offset);
|
||||
if ( pmmb == NULL ) {
|
||||
osal_printk("mmz flush cache get mmz_mmb failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( mmz_mmb_flush_dcache_byaddr(kvirt, phy_addr, length) != 0 )
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_flush_cache);
|
||||
+956
@@ -0,0 +1,956 @@
|
||||
/*
|
||||
* Copyright (c) XMEDIA. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <generated/autoconf.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/version.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#ifndef CONFIG_64BIT
|
||||
#include <linux/highmem.h>
|
||||
#include <asm/pgtable.h>
|
||||
#endif
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "osal.h"
|
||||
#include "allocator.h"
|
||||
#include "version.h"
|
||||
#include <linux/lotus/kapi.h>
|
||||
|
||||
|
||||
OSAL_LIST_HEAD(mmz_list);
|
||||
|
||||
static DEFINE_SEMAPHORE(mmz_lock);
|
||||
|
||||
#define MMZ_SETUP_CMDLINE_LEN 256
|
||||
#define MMZ_ALLOCATOR_NAME_LEN 32
|
||||
#define MMZ_DEFAULT_ALLOCATOR "xmedia"
|
||||
#ifndef MODULE
|
||||
|
||||
static char setup_zones[MMZ_SETUP_CMDLINE_LEN] = {'\0'};
|
||||
static int __init parse_kern_mmz(char *line)
|
||||
{
|
||||
strlcpy(setup_zones, line, sizeof(setup_zones));
|
||||
|
||||
return 1;
|
||||
}
|
||||
__setup("mmz=", parse_kern_mmz);
|
||||
|
||||
static char setup_allocator[MMZ_ALLOCATOR_NAME_LEN] = MMZ_DEFAULT_ALLOCATOR;
|
||||
static int __init parse_kern_allocator(char *line)
|
||||
{
|
||||
strlcpy(setup_allocator, line, sizeof(setup_allocator));
|
||||
return 1;
|
||||
}
|
||||
__setup("mmz_allocator=", parse_kern_allocator);
|
||||
|
||||
#else
|
||||
static char setup_zones[MMZ_SETUP_CMDLINE_LEN]={'\0'};
|
||||
static char setup_allocator[MMZ_ALLOCATOR_NAME_LEN] = MMZ_DEFAULT_ALLOCATOR; //default setting
|
||||
module_param_string(mmz, setup_zones, MMZ_SETUP_CMDLINE_LEN, 0600);
|
||||
module_param_string(mmz_allocator, setup_allocator, MMZ_ALLOCATOR_NAME_LEN, 0600);
|
||||
MODULE_PARM_DESC(mmz,"mmz_allocator=allocator mmz=name,0,start,size,type,eqsize:[others] map_mmz=start,size:[others]");
|
||||
#endif
|
||||
|
||||
static struct mmz_allocator the_allocator;
|
||||
|
||||
mmz_mmz_t *mmz_mmz_create(const char *name,
|
||||
unsigned long gfp,
|
||||
unsigned long phys_start,
|
||||
unsigned long nbytes)
|
||||
{
|
||||
mmz_mmz_t *p = NULL;
|
||||
|
||||
mmz_trace_func();
|
||||
|
||||
if(name == NULL) {
|
||||
printk(KERN_ERR "%s: 'name' should not be NULL!", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = kmalloc(sizeof(mmz_mmz_t) + 1, GFP_KERNEL);
|
||||
if (p == NULL) {
|
||||
printk(KERN_ERR "%s: System OOM!\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(p, 0, sizeof(mmz_mmz_t)+1);
|
||||
strlcpy(p->name, name, MMZ_MMZ_NAME_LEN);
|
||||
p->gfp = gfp;
|
||||
p->phys_start = phys_start;
|
||||
p->nbytes = nbytes;
|
||||
|
||||
OSAL_INIT_LIST_HEAD(&p->list);
|
||||
OSAL_INIT_LIST_HEAD(&p->mmb_list);
|
||||
|
||||
p->destructor = kfree;
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmz_create);
|
||||
|
||||
int mmz_mmz_destroy(mmz_mmz_t *zone)
|
||||
{
|
||||
if(zone == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(zone->destructor) {
|
||||
zone->destructor(zone);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmz_destroy);
|
||||
|
||||
static int _check_mmz(mmz_mmz_t *zone)
|
||||
{
|
||||
mmz_mmz_t *p = NULL;
|
||||
|
||||
unsigned long new_start=zone->phys_start;
|
||||
unsigned long new_end=zone->phys_start+zone->nbytes;
|
||||
|
||||
if (zone->nbytes == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!((new_start >= __pa((uintptr_t)high_memory)) ||
|
||||
((new_start < PHYS_OFFSET) && (new_end <= PHYS_OFFSET)))) {
|
||||
printk(KERN_ERR "ERROR: Conflict MMZ:\n");
|
||||
printk(KERN_ERR MMZ_MMZ_FMT_S "\n", mmz_mmz_fmt_arg(zone));
|
||||
printk(KERN_ERR "MMZ conflict to kernel memory (0x%08lX, 0x%08lX)\n",
|
||||
(long unsigned int)PHYS_OFFSET,
|
||||
(long unsigned int)(__pa((uintptr_t)high_memory) - 1));
|
||||
return -1;
|
||||
}
|
||||
|
||||
osal_list_for_each_entry(p, &mmz_list, list) {
|
||||
unsigned long start, end;
|
||||
start = p->phys_start;
|
||||
end = p->phys_start + p->nbytes;
|
||||
|
||||
if(new_start >= end) {
|
||||
continue;
|
||||
} else if (new_start < start && new_end <= start) {
|
||||
continue;
|
||||
} else {
|
||||
;
|
||||
}
|
||||
|
||||
printk(KERN_ERR "ERROR: Conflict MMZ:\n");
|
||||
printk(KERN_ERR "MMZ new: " MMZ_MMZ_FMT_S "\n", mmz_mmz_fmt_arg(zone));
|
||||
printk(KERN_ERR "MMZ exist: " MMZ_MMZ_FMT_S "\n", mmz_mmz_fmt_arg(p));
|
||||
printk(KERN_ERR "Add new MMZ failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmz_mmz_register(mmz_mmz_t *zone)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mmz_trace(1, MMZ_MMZ_FMT_S, mmz_mmz_fmt_arg(zone));
|
||||
|
||||
if(zone == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
down(&mmz_lock);
|
||||
|
||||
if (0 == strcmp(setup_allocator, "xmedia")) {
|
||||
ret = _check_mmz(zone);
|
||||
if (ret) {
|
||||
up(&mmz_lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
OSAL_INIT_LIST_HEAD(&zone->mmb_list);
|
||||
|
||||
osal_list_add(&zone->list, &mmz_list);
|
||||
|
||||
up(&mmz_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmz_mmz_unregister(mmz_mmz_t *zone)
|
||||
{
|
||||
int losts = 0;
|
||||
mmz_mmb_t *p = NULL;
|
||||
|
||||
if(zone == NULL)
|
||||
return -1;
|
||||
|
||||
mmz_trace_func();
|
||||
|
||||
down(&mmz_lock);
|
||||
osal_list_for_each_entry(p, &zone->mmb_list, list) {
|
||||
printk(KERN_WARNING "MB Lost: " MMZ_MMB_FMT_S "\n",
|
||||
mmz_mmb_fmt_arg(p));
|
||||
losts++;
|
||||
}
|
||||
|
||||
if (losts) {
|
||||
printk(KERN_ERR "%d mmbs not free, mmz<%s> can not be unregistered!\n",
|
||||
losts, zone->name);
|
||||
up(&mmz_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
osal_list_del(&zone->list);
|
||||
up(&mmz_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
mmz_mmb_t *mmz_mmb_alloc(const char *name,
|
||||
unsigned long size,
|
||||
unsigned long align,
|
||||
unsigned long gfp,
|
||||
const char *mmz_name)
|
||||
{
|
||||
mmz_mmb_t *mmb = NULL;
|
||||
|
||||
down(&mmz_lock);
|
||||
mmb = the_allocator.mmb_alloc(name, size, align, gfp, mmz_name, NULL);
|
||||
up(&mmz_lock);
|
||||
|
||||
return mmb;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmb_alloc);
|
||||
|
||||
void *mmz_mmb_map2kern(mmz_mmb_t *mmb)
|
||||
{
|
||||
void *p = NULL;
|
||||
|
||||
if(mmb == NULL)
|
||||
return NULL;
|
||||
|
||||
down(&mmz_lock);
|
||||
p = the_allocator.mmb_map2kern(mmb, 0);
|
||||
up(&mmz_lock);
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmb_map2kern);
|
||||
|
||||
/* mmf: media-memory fragment */
|
||||
void *mmz_mmf_map2kern_nocache(unsigned long phys, int len)
|
||||
{
|
||||
void *virt = the_allocator.mmf_map(phys, len, 0);
|
||||
if (virt != NULL)
|
||||
return virt;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmf_map2kern_nocache);
|
||||
|
||||
void *mmz_mmf_map2kern_cache(unsigned long phys, int len)
|
||||
{
|
||||
void *virt = the_allocator.mmf_map(phys, len, 1);
|
||||
if (virt != NULL)
|
||||
return virt;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmf_map2kern_cache);
|
||||
|
||||
void mmz_mmf_unmap(void *virt)
|
||||
{
|
||||
the_allocator.mmf_unmap(virt);
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmf_unmap);
|
||||
|
||||
void *mmz_mmb_map2kern_cached(mmz_mmb_t *mmb)
|
||||
{
|
||||
void *p = NULL;
|
||||
|
||||
if(mmb == NULL)
|
||||
return NULL;
|
||||
|
||||
down(&mmz_lock);
|
||||
p = the_allocator.mmb_map2kern(mmb, 1);
|
||||
up(&mmz_lock);
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmb_map2kern_cached);
|
||||
|
||||
int mmz_mmb_flush_dcache_byaddr(void *kvirt,
|
||||
unsigned long phys_addr,
|
||||
unsigned long length)
|
||||
{
|
||||
if (kvirt == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Use flush range to instead flush_cache_all,
|
||||
* because flush_cache_all only flush local cpu.
|
||||
* And on_each_cpu macro cannot used to flush
|
||||
* all cpus with irq disabled.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
__flush_dcache_area(kvirt, length);
|
||||
#else
|
||||
/*
|
||||
* dmac_map_area is invalid in kernel,
|
||||
* arm9 is not supported yet
|
||||
*/
|
||||
__cpuc_flush_dcache_area(kvirt, length);
|
||||
#endif
|
||||
#if defined(CONFIG_CACHE_L2V200) || defined(CONFIG_CACHE_L2X0)
|
||||
/* flush l2 cache, use paddr */
|
||||
/*
|
||||
* if length > L2 cache size, then this interface
|
||||
* will call <outer_flush_all>
|
||||
*/
|
||||
outer_flush_range(phys_addr, phys_addr + length);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmb_flush_dcache_byaddr);
|
||||
|
||||
int mmz_mmb_invalid_cache_byaddr(void *kvirt,
|
||||
unsigned long phys_addr,
|
||||
unsigned long length)
|
||||
{
|
||||
if (kvirt == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
__flush_dcache_area(kvirt, length);
|
||||
#else
|
||||
/*
|
||||
* dmac_map_area is invalid in kernel,
|
||||
* arm9 is not supported yet
|
||||
*/
|
||||
__cpuc_flush_dcache_area(kvirt, length);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmb_invalid_cache_byaddr);
|
||||
|
||||
int mmz_mmb_unmap(mmz_mmb_t *mmb)
|
||||
{
|
||||
int ref;
|
||||
|
||||
if(mmb == NULL)
|
||||
return -1;
|
||||
|
||||
down(&mmz_lock);
|
||||
|
||||
ref = the_allocator.mmb_unmap(mmb);
|
||||
|
||||
up(&mmz_lock);
|
||||
|
||||
return ref;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmb_unmap);
|
||||
|
||||
int mmz_mmb_get(mmz_mmb_t *mmb)
|
||||
{
|
||||
int ref;
|
||||
|
||||
if(mmb == NULL)
|
||||
return -1;
|
||||
|
||||
down(&mmz_lock);
|
||||
|
||||
if(mmb->flags & MMZ_MMB_RELEASED)
|
||||
printk(KERN_WARNING "mmz_mmb_get: amazing, mmb<%s> is released!\n", mmb->name);
|
||||
ref = ++mmb->phy_ref;
|
||||
|
||||
up(&mmz_lock);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
int mmz_mmb_put(mmz_mmb_t *mmb)
|
||||
{
|
||||
int ref;
|
||||
|
||||
if(mmb == NULL)
|
||||
return -1;
|
||||
|
||||
down(&mmz_lock);
|
||||
|
||||
if(mmb->flags & MMZ_MMB_RELEASED)
|
||||
printk(KERN_WARNING "mmz_mmb_put: amazing, mmb<%s> is released!\n", mmb->name);
|
||||
|
||||
ref = --mmb->phy_ref;
|
||||
|
||||
if ((mmb->flags & MMZ_MMB_RELEASED) && (mmb->phy_ref ==0) && (mmb->map_ref ==0)) {
|
||||
the_allocator.mmb_free(mmb);
|
||||
}
|
||||
|
||||
up(&mmz_lock);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
int mmz_mmb_free(mmz_mmb_t *mmb)
|
||||
{
|
||||
mmz_trace_func();
|
||||
|
||||
if(mmb == NULL)
|
||||
return -1;
|
||||
|
||||
mmz_trace(1,MMZ_MMB_FMT_S,mmz_mmb_fmt_arg(mmb));
|
||||
down(&mmz_lock);
|
||||
|
||||
if(mmb->flags & MMZ_MMB_RELEASED) {
|
||||
printk(KERN_WARNING "mmz_mmb_free: amazing, mmb<%s> has been released,\
|
||||
but is still in use!\n", mmb->name);
|
||||
up(&mmz_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mmb->phy_ref > 0) {
|
||||
printk(KERN_WARNING "mmz_mmb_free: free mmb<%s> delayed \
|
||||
for which ref-count is %d!\n",
|
||||
mmb->name, mmb->map_ref);
|
||||
mmb->flags |= MMZ_MMB_RELEASED;
|
||||
up(&mmz_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mmb->flags & MMZ_MMB_MAP2KERN) {
|
||||
printk(KERN_WARNING "mmz_mmb_free: free mmb<%s> delayed for which \
|
||||
is kernel-mapped to 0x%pK with map_ref %d!\n",
|
||||
mmb->name, mmb->kvirt, mmb->map_ref);
|
||||
mmb->flags |= MMZ_MMB_RELEASED;
|
||||
up(&mmz_lock);
|
||||
return 0;
|
||||
}
|
||||
the_allocator.mmb_free(mmb);
|
||||
up(&mmz_lock);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmb_free);
|
||||
|
||||
#define MACH_MMB(p, val, member) do {\
|
||||
mmz_mmz_t *__mach_mmb_zone__ = NULL; \
|
||||
(p) = NULL;\
|
||||
list_for_each_entry(__mach_mmb_zone__, &mmz_list, list) { \
|
||||
mmz_mmb_t *__mach_mmb__ = NULL;\
|
||||
list_for_each_entry(__mach_mmb__, &__mach_mmb_zone__->mmb_list, list) { \
|
||||
if (__mach_mmb__->member == (val)) { \
|
||||
(p) = __mach_mmb__; \
|
||||
break;\
|
||||
} \
|
||||
} \
|
||||
if (p != NULL)break;\
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
mmz_mmb_t *mmz_mmb_getby_phys(unsigned long addr)
|
||||
{
|
||||
mmz_mmb_t *p = NULL;
|
||||
down(&mmz_lock);
|
||||
MACH_MMB(p, addr, phys_addr);
|
||||
up(&mmz_lock);
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmb_getby_phys);
|
||||
|
||||
unsigned long usr_virt_to_phys(unsigned long virt)
|
||||
{
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||
pgd_t* pgd = NULL;
|
||||
pud_t* pud = NULL;
|
||||
#endif
|
||||
pmd_t* pmd = NULL;
|
||||
pte_t* pte = NULL;
|
||||
unsigned int cacheable = 0;
|
||||
unsigned long page_addr = 0;
|
||||
unsigned long page_offset = 0;
|
||||
unsigned long phys_addr = 0;
|
||||
|
||||
if (virt & 0x3) {
|
||||
printk("invalid virt addr 0x%08lx[not 4 bytes align]\n", virt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (virt >= PAGE_OFFSET) {
|
||||
printk("invalid user space virt addr 0x%08lx\n", virt);
|
||||
return 0;
|
||||
}
|
||||
// in kernel 5.10 just use pmd_off is ok
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||
pgd = pgd_offset(current->mm, virt);
|
||||
|
||||
if (pgd_none(*pgd)) {
|
||||
printk("printk: not mapped in pgd!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pud = pud_offset(pgd, virt);
|
||||
|
||||
if (pud_none(*pud)) {
|
||||
printk("printk: not mapped in pud!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pmd = pmd_offset(pud, virt);
|
||||
#else
|
||||
pmd = pmd_off(current->mm, virt);
|
||||
#endif
|
||||
if (pmd_none(*pmd)) {
|
||||
printk("printk: not mapped in pmd!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pte = pte_offset_map(pmd, virt);
|
||||
|
||||
if (pte_none(*pte)) {
|
||||
printk("printk: not mapped in pte!\n");
|
||||
pte_unmap(pte);
|
||||
return 0;
|
||||
}
|
||||
|
||||
page_addr = (pte_val(*pte) & PHYS_MASK) & PAGE_MASK;
|
||||
page_offset = virt & ~PAGE_MASK;
|
||||
phys_addr = page_addr | page_offset;
|
||||
#ifdef CONFIG_64BIT
|
||||
if (pte_val(*pte) & (1 << 4))
|
||||
#else
|
||||
if (pte_val(*pte) & (1 << 3))
|
||||
#endif
|
||||
{ cacheable = 1; }
|
||||
|
||||
/*
|
||||
* phys_addr: the lowest bit indicates its cache attribute
|
||||
* 1: cacheable
|
||||
* 0: uncacheable
|
||||
*/
|
||||
phys_addr |= cacheable;
|
||||
|
||||
pte_unmap(pte);
|
||||
|
||||
return phys_addr;
|
||||
}
|
||||
EXPORT_SYMBOL(usr_virt_to_phys);
|
||||
|
||||
#define MACH_MMB_2(p, val, member, Outoffset) do {\
|
||||
mmz_mmz_t *__mach_mmb_zone__ = NULL; \
|
||||
(p) = NULL;\
|
||||
list_for_each_entry(__mach_mmb_zone__, &mmz_list, list) { \
|
||||
mmz_mmb_t *__mach_mmb__ = NULL;\
|
||||
list_for_each_entry(__mach_mmb__, &__mach_mmb_zone__->mmb_list, list) { \
|
||||
if ((__mach_mmb__->member <= (val)) && ((__mach_mmb__->length + __mach_mmb__->member) > (val))) { \
|
||||
(p) = __mach_mmb__; \
|
||||
Outoffset = val - __mach_mmb__->member;\
|
||||
break;\
|
||||
}\
|
||||
} \
|
||||
if (p != NULL)break;\
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
|
||||
mmz_mmb_t *mmz_mmb_getby_kvirt(void *virt)
|
||||
{
|
||||
mmz_mmb_t *p = NULL;
|
||||
unsigned long Outoffset;
|
||||
|
||||
if (virt == NULL)
|
||||
return NULL;
|
||||
|
||||
down(&mmz_lock);
|
||||
MACH_MMB_2(p, virt, kvirt, Outoffset);
|
||||
up(&mmz_lock);
|
||||
|
||||
mmz_trace(1, "Outoffset %lu \n", Outoffset);
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmb_getby_kvirt);
|
||||
|
||||
mmz_mmb_t *mmz_mmb_getby_phys_2(unsigned long addr, unsigned long *Outoffset)
|
||||
{
|
||||
mmz_mmb_t *p = NULL;
|
||||
|
||||
down(&mmz_lock);
|
||||
MACH_MMB_2(p, addr, phys_addr, *Outoffset);
|
||||
up(&mmz_lock);
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmb_getby_phys_2);
|
||||
|
||||
mmz_mmz_t *mmz_mmz_find(unsigned long gfp, const char *mmz_name)
|
||||
{
|
||||
mmz_mmz_t *p = NULL;
|
||||
|
||||
down(&mmz_lock);
|
||||
begin_list_for_each_mmz(p, gfp, mmz_name)
|
||||
up(&mmz_lock);
|
||||
return p;
|
||||
end_list_for_each_mmz()
|
||||
up(&mmz_lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmz_find);
|
||||
|
||||
unsigned long mmz_mmz_get_phys(const char *zone_name)
|
||||
{
|
||||
mmz_mmz_t *zone = NULL;
|
||||
|
||||
zone = mmz_mmz_find(0, zone_name);
|
||||
if (zone != NULL)
|
||||
return zone->phys_start;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmz_get_phys);
|
||||
|
||||
int mmz_map_mmz_unregister(mmz_mmz_t *zone)
|
||||
{
|
||||
int losts = 0;
|
||||
mmz_mmb_t *p = NULL;
|
||||
|
||||
if (zone == NULL)
|
||||
return -1;
|
||||
|
||||
mmz_trace_func();
|
||||
|
||||
down(&mmz_lock);
|
||||
osal_list_for_each_entry(p, &zone->mmb_list, list) {
|
||||
printk(KERN_WARNING "MB Lost: " MMZ_MMB_FMT_S "\n",
|
||||
mmz_mmb_fmt_arg(p));
|
||||
losts++;
|
||||
}
|
||||
|
||||
if (losts) {
|
||||
printk(KERN_ERR "%d mmbs not free, mmz<%s> can not be unregistered!\n",
|
||||
losts, zone->name);
|
||||
up(&mmz_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
osal_list_del(&zone->list);
|
||||
up(&mmz_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmz_vma_check(unsigned long vm_start, unsigned long vm_end)
|
||||
{
|
||||
struct vm_area_struct *pvma1;
|
||||
struct vm_area_struct *pvma2;
|
||||
|
||||
pvma1 = find_vma(current->mm, vm_start);
|
||||
if (pvma1 == NULL) {
|
||||
printk(KERN_ERR "ERROR: pvma1 is null\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pvma2 = find_vma(current->mm, vm_end-1);
|
||||
if (pvma2 == NULL) {
|
||||
printk(KERN_ERR "ERROR: pvma2 is null\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pvma1 != pvma2) {
|
||||
printk(KERN_ERR "ERROR: pvma1:[0x%lx,0x%lx) and pvma2:[0x%lx,0x%lx) are not equal\n",
|
||||
pvma1->vm_start, pvma1->vm_end, pvma2->vm_start, pvma2->vm_end);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(pvma1->vm_flags & VM_WRITE)) {
|
||||
printk(KERN_ERR "ERROR vma flag:0x%lx\n", pvma1->vm_flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pvma1->vm_start > vm_start) {
|
||||
printk("cannot find corresponding vma, vm[%lx, %lx], user range[%lx,%lx]\n", pvma1->vm_start, pvma1->vm_end, vm_start, vm_end);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_vma_check);
|
||||
|
||||
int mmz_is_phys_in_mmz(unsigned long addr_start, unsigned long addr_len)
|
||||
{
|
||||
mmz_mmz_t *p = NULL;
|
||||
unsigned long addr_end = addr_start + addr_len;
|
||||
unsigned long temp_start, temp_end;
|
||||
|
||||
osal_list_for_each_entry(p, &mmz_list, list) {
|
||||
temp_start = p->phys_start;
|
||||
temp_end = p->phys_start + p->nbytes;
|
||||
if ((addr_start >= temp_start) && (addr_end <= temp_end)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_is_phys_in_mmz);
|
||||
|
||||
|
||||
int mmz_mmb_flush_dcache_byaddr_safe(void *kvirt,
|
||||
unsigned long phys_addr,
|
||||
unsigned long length)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mm_struct *mm = current->mm;
|
||||
|
||||
if (kvirt == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||
down_read(&mm->mmap_sem);
|
||||
#else
|
||||
down_read(&mm->mmap_lock);
|
||||
#endif
|
||||
if (mmz_vma_check((unsigned long)(uintptr_t)kvirt, (unsigned long)(uintptr_t)kvirt+length)) {
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||
up_read(&mm->mmap_sem);
|
||||
#else
|
||||
up_read(&mm->mmap_lock);
|
||||
#endif
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ret = mmz_mmb_flush_dcache_byaddr(kvirt, phys_addr, length);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||
up_read(&mm->mmap_sem);
|
||||
#else
|
||||
up_read(&mm->mmap_lock);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mmz_mmb_flush_dcache_byaddr_safe);
|
||||
|
||||
#define MEDIA_MEM_NAME "media-mem"
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static void mmz_proc_version(struct osal_proc_dir_entry *sfile)
|
||||
{
|
||||
unsigned char mmz_version[128] = {0};
|
||||
VERSION_FORMAT(mmz_version, "MMZ", "V1.0", "");
|
||||
osal_seq_printf(sfile, "\n%s\n\n", mmz_version);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int mmz_seq_show(struct osal_proc_dir_entry *sfile)
|
||||
{
|
||||
mmz_mmz_t *p = NULL;
|
||||
int len = 0;
|
||||
unsigned int zone_number = 0;
|
||||
unsigned int block_number = 0;
|
||||
unsigned int used_size = 0;
|
||||
unsigned int free_size = 0;
|
||||
unsigned int mmz_total_size = 0;
|
||||
|
||||
mmz_trace_func();
|
||||
|
||||
mmz_proc_version(sfile);
|
||||
|
||||
down(&mmz_lock);
|
||||
list_for_each_entry(p, &mmz_list, list) {
|
||||
mmz_mmb_t *mmb = NULL;
|
||||
osal_seq_printf(sfile, "+---ZONE: " MMZ_MMZ_FMT_S "\n", mmz_mmz_fmt_arg(p));
|
||||
mmz_total_size += p->nbytes / 1024;
|
||||
++zone_number;
|
||||
|
||||
list_for_each_entry(mmb, &p->mmb_list, list) {
|
||||
osal_seq_printf(sfile, " |-MMB: " MMZ_MMB_FMT_S "\n", mmz_mmb_fmt_arg(mmb));
|
||||
used_size += mmb->length / 1024;
|
||||
++block_number;
|
||||
}
|
||||
}
|
||||
|
||||
if (mmz_total_size != 0) {
|
||||
free_size = mmz_total_size - used_size;
|
||||
osal_seq_printf(sfile, "\n---MMZ_USE_INFO:\n total size=%dKB(%dMB),"
|
||||
"used=%dKB(%dMB + %dKB),free=%dKB(%dMB + %dKB),"
|
||||
"zone_number=%d,block_number=%d\n",
|
||||
mmz_total_size, mmz_total_size / 1024,
|
||||
used_size, used_size / 1024, used_size % 1024,
|
||||
free_size, free_size / 1024, free_size % 1024,
|
||||
zone_number, block_number);
|
||||
}
|
||||
up(&mmz_lock);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int __init media_mem_proc_init(void)
|
||||
{
|
||||
osal_proc_entry_t *proc = NULL;
|
||||
|
||||
proc = osal_create_proc_entry(MEDIA_MEM_NAME, NULL);
|
||||
if (proc == NULL) {
|
||||
printk(KERN_ERR "Create mmz proc fail!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
proc->read = mmz_seq_show;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit media_mem_proc_exit(void)
|
||||
{
|
||||
osal_remove_proc_entry(MEDIA_MEM_NAME, NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
static int __init media_mem_proc_init(void) { return 0; }
|
||||
static void __exit media_mem_proc_exit(void) { }
|
||||
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
static void mmz_exit_check(void)
|
||||
{
|
||||
mmz_mmz_t* pmmz = NULL;
|
||||
struct osal_list_head* p = NULL, *n = NULL;
|
||||
|
||||
mmz_trace_func();
|
||||
|
||||
list_for_each_safe(p, n, &mmz_list) {
|
||||
pmmz = list_entry(p,mmz_mmz_t,list);
|
||||
printk(KERN_WARNING "MMZ force removed: " MMZ_MMZ_FMT_S "\n",
|
||||
mmz_mmz_fmt_arg(pmmz));
|
||||
mmz_mmz_unregister(pmmz);
|
||||
mmz_mmz_destroy(pmmz);
|
||||
}
|
||||
}
|
||||
|
||||
int __init media_mem_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
printk(KERN_INFO "Media Memory Zone Manager\n");
|
||||
|
||||
if (setup_zones[0] == '\0') {
|
||||
char *boot_mmz_para_start = NULL;
|
||||
char *boot_mmz_para_end = NULL;
|
||||
int mmz_para_len = 0;
|
||||
|
||||
/* get parameter from bootargs*/
|
||||
boot_mmz_para_start = lotus_get_cmd_line();
|
||||
|
||||
if (boot_mmz_para_start != NULL)
|
||||
boot_mmz_para_start = strstr(boot_mmz_para_start, "mmz_allocator=");
|
||||
|
||||
printk("mmz allocator from bootargs:%s\n", boot_mmz_para_start == NULL ? "none" : boot_mmz_para_start);
|
||||
if (boot_mmz_para_start != NULL) {
|
||||
|
||||
boot_mmz_para_start += strlen("mmz_allocator=");
|
||||
|
||||
/*find mmz parameter end*/
|
||||
boot_mmz_para_end = strchr(boot_mmz_para_start, ' ');
|
||||
|
||||
/*if this is the last bootargs, bootargs end is mmz parameter end*/
|
||||
if (boot_mmz_para_end == NULL) {
|
||||
mmz_para_len = strlen(boot_mmz_para_start);
|
||||
} else {
|
||||
mmz_para_len = boot_mmz_para_end - boot_mmz_para_start;
|
||||
}
|
||||
|
||||
mmz_para_len = ((mmz_para_len > MMZ_ALLOCATOR_NAME_LEN) ? MMZ_ALLOCATOR_NAME_LEN : mmz_para_len);
|
||||
memcpy(setup_allocator, boot_mmz_para_start, mmz_para_len);
|
||||
|
||||
boot_mmz_para_start = lotus_get_cmd_line();
|
||||
/*no need judge here*/
|
||||
boot_mmz_para_start = strstr(boot_mmz_para_start, "mmz=") + strlen("mmz=");
|
||||
|
||||
printk("mmz zone setting from bootargs:%s\n", boot_mmz_para_start);
|
||||
if (boot_mmz_para_start != NULL) {
|
||||
|
||||
/*find mmz parameter end*/
|
||||
boot_mmz_para_end = strchr(boot_mmz_para_start, ' ');
|
||||
|
||||
/*if this is the last bootargs, bootargs end is mmz parameter end*/
|
||||
if (boot_mmz_para_end == NULL) {
|
||||
mmz_para_len = strlen(boot_mmz_para_start);
|
||||
} else {
|
||||
mmz_para_len = boot_mmz_para_end - boot_mmz_para_start;
|
||||
}
|
||||
|
||||
mmz_para_len = ((mmz_para_len > MMZ_SETUP_CMDLINE_LEN) ? MMZ_SETUP_CMDLINE_LEN : mmz_para_len);
|
||||
memcpy(setup_zones, boot_mmz_para_start, mmz_para_len);
|
||||
printk("mmz cfg from bootargs allocator:%s zones:%s\n", setup_allocator, setup_zones);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(setup_allocator, "cma") == 0) {
|
||||
#ifdef CONFIG_CMA
|
||||
ret = cma_allocator_setopt(&the_allocator);
|
||||
#else
|
||||
pr_err("cma is not enabled in kernel, please check!\n");
|
||||
return -EINVAL;
|
||||
#endif
|
||||
} else if (strcmp(setup_allocator, "xmedia") == 0) {
|
||||
ret = allocator_setopt(&the_allocator);
|
||||
} else {
|
||||
printk("The module param \"setup_allocator\" should be \"cma\" or \"xmedia\", which is \"%s\"\n",
|
||||
setup_allocator);
|
||||
mmz_exit_check();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = the_allocator.init(setup_zones);
|
||||
if (ret != 0) {
|
||||
mmz_exit_check();
|
||||
return ret;
|
||||
}
|
||||
|
||||
media_mem_proc_init();
|
||||
mmz_userdev_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit media_mem_exit(void)
|
||||
{
|
||||
mmz_userdev_exit();
|
||||
mmz_exit_check();
|
||||
media_mem_proc_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
module_init(media_mem_init);
|
||||
module_exit(media_mem_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
*/
|
||||
/*
|
||||
#ifndef MODULE
|
||||
subsys_initcall(media_mem_init);
|
||||
#endif
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user