/* * 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; }