/*
* Copyright (C) 2011 Texas Instruments, Inc
*
* This program 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 program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see .
*/
#include
#include
#include
#include "gc_bvmapping.h"
#include "services_headers.h"
void gc_bvmap_meminfo(PVRSRV_KERNEL_MEM_INFO *psMemInfo)
{
int i;
IMG_CPU_PHYADDR phy_addr;
unsigned long *page_addrs;
struct bvbuffdesc *buffdesc;
struct bvphysdesc *physdesc;
int num_pages;
struct bventry bv_entry;
enum bverror bv_error;
gcbv_init(&bv_entry);
if (!bv_entry.bv_map) {
psMemInfo->bvmap_handle = NULL;
return;
}
num_pages = (psMemInfo->uAllocSize +
PAGE_SIZE - 1) >> PAGE_SHIFT;
page_addrs = kzalloc(sizeof(*page_addrs) * num_pages, GFP_KERNEL);
if (!page_addrs) {
printk(KERN_ERR "%s: Out of memory\n", __func__);
return;
}
physdesc = kzalloc(sizeof(*physdesc), GFP_KERNEL);
buffdesc = kzalloc(sizeof(*buffdesc), GFP_KERNEL);
if (!buffdesc || !physdesc) {
printk(KERN_ERR "%s: Out of memory\n", __func__);
kfree(page_addrs);
kfree(physdesc);
kfree(buffdesc);
return;
}
for (i = 0; i < num_pages; i++) {
phy_addr = OSMemHandleToCpuPAddr(
psMemInfo->sMemBlk.hOSMemHandle, i << PAGE_SHIFT);
page_addrs[i] = (u32)phy_addr.uiAddr;
}
buffdesc->structsize = sizeof(*buffdesc);
buffdesc->map = NULL;
buffdesc->length = psMemInfo->uAllocSize;
buffdesc->auxtype = BVAT_PHYSDESC;
buffdesc->auxptr = physdesc;
physdesc->structsize = sizeof(*physdesc);
physdesc->pagesize = PAGE_SIZE;
physdesc->pagearray = page_addrs;
physdesc->pagecount = num_pages;
/*
* For ion allocated buffers let's verify how many planes this
* meminfo consist of
*/
if(psMemInfo->ui32Flags & PVRSRV_MEM_ION) {
IMG_UINT32 num_addr_offsets = 0;
OSGetMemMultiPlaneInfo(psMemInfo->sMemBlk.hOSMemHandle,
NULL, &num_addr_offsets);
/*
* Account for this meminfo plane offset (relative to the base
* address) if necessary
*/
if(num_addr_offsets > 0)
physdesc->pageoffset = psMemInfo->planeOffsets[0];
/*
* In BV there is no way to specify multiple offsets, check
* all planes have the same offset and report any discrepancy
*/
for (i = 1; i < num_addr_offsets; i++) {
IMG_UINT32 plane_offset =
psMemInfo->planeOffsets[i] % PAGE_SIZE;
if (psMemInfo->planeOffsets[0] != plane_offset) {
printk(KERN_WARNING "%s: meminfo %p offset 0 %d"
" != offset %d %d, coalignment is "
"missing\n", __func__, psMemInfo,
psMemInfo->planeOffsets[0],
i, plane_offset);
}
}
}
bv_error = bv_entry.bv_map(buffdesc);
if (bv_error) {
printk(KERN_ERR "%s: Failed to map meminfo %p, bverror %d\n",
__func__, psMemInfo, bv_error);
psMemInfo->bvmap_handle = NULL;
} else
psMemInfo->bvmap_handle = buffdesc;
}
void gc_bvunmap_meminfo(PVRSRV_KERNEL_MEM_INFO *psMemInfo)
{
struct bvbuffdesc *buffdesc;
struct bvphysdesc *physdesc;
struct bventry bv_entry;
enum bverror bv_error;
gcbv_init(&bv_entry);
if (!bv_entry.bv_map || !psMemInfo || !psMemInfo->bvmap_handle)
return;
buffdesc = psMemInfo->bvmap_handle;
physdesc = (struct bvphysdesc*) buffdesc->auxptr;
bv_error = bv_entry.bv_unmap(buffdesc);
if (bv_error) {
printk(KERN_ERR "%s: Failed to unmap bvhandle %p from meminfo "
"%p, bverror %d\n", __func__, buffdesc, psMemInfo,
bv_error);
}
kfree(physdesc->pagearray);
kfree(physdesc);
kfree(psMemInfo->bvmap_handle);
psMemInfo->bvmap_handle = NULL;
}
IMG_VOID *gc_meminfo_to_hndl(PVRSRV_KERNEL_MEM_INFO *psMemInfo)
{
return psMemInfo->bvmap_handle;
}