goto out_err;
}
- DRM_DEBUG("%s: vram kernel virtual address %p\n", pg->vram_addr);
-
tt_pages = (pg->gatt_pages < PSB_TT_PRIV0_PLIMIT) ?
(pg->gatt_pages) : PSB_TT_PRIV0_PLIMIT;
return 0;
}
-
int psb_gtt_insert_phys_addresses(struct psb_gtt *pg, IMG_CPU_PHYADDR *pPhysFrames,
unsigned offset_pages, unsigned num_pages, int type)
{
ret = drm_ht_find_item(&mm->hash, tgid, &entry);
if (ret) {
- DRM_DEBUG("Cannot find entry pid=%ld\n", tgid);
+ DRM_DEBUG("Cannot find entry pid=%d\n", tgid);
return ret;
}
spin_lock(&mm->lock);
ret = psb_gtt_mm_get_ht_by_pid_locked(mm, tgid, &hentry);
if (!ret) {
- DRM_DEBUG("Entry for tgid %ld exist, hentry %p\n",
+ DRM_DEBUG("Entry for tgid %d exist, hentry %p\n",
tgid, hentry);
*entry = hentry;
spin_unlock(&mm->lock);
}
spin_unlock(&mm->lock);
- DRM_DEBUG("Entry for tgid %ld doesn't exist, will create it\n", tgid);
+ DRM_DEBUG("Entry for tgid %d doesn't exist, will create it\n", tgid);
hentry = kzalloc(sizeof(struct psb_gtt_hash_entry), GFP_KERNEL);
if (!hentry) {
ret = psb_gtt_mm_get_ht_by_pid_locked(mm, tgid, &tmp);
if (ret) {
- DRM_DEBUG("Cannot find entry pid %ld\n", tgid);
+ DRM_DEBUG("Cannot find entry pid %d\n", tgid);
return NULL;
}
ret = drm_ht_find_item(ht, key, &entry);
if (ret) {
- DRM_DEBUG("Cannot find key %ld\n", key);
+ DRM_DEBUG("Cannot find key %d\n", key);
return ret;
}
spin_lock(&mm->lock);
ret = psb_gtt_mm_get_mem_mapping_locked(ht, key, &mapping);
if (!ret) {
- DRM_DEBUG("mapping entry for key %ld exists, entry %p\n",
+ DRM_DEBUG("mapping entry for key %d exists, entry %p\n",
key, mapping);
*entry = mapping;
spin_unlock(&mm->lock);
}
spin_unlock(&mm->lock);
- DRM_DEBUG("Mapping entry for key %ld doesn't exist, will create it\n",
+ DRM_DEBUG("Mapping entry for key %d doesn't exist, will create it\n",
key);
mapping = kzalloc(sizeof(struct psb_gtt_mem_mapping), GFP_KERNEL);
ret = psb_gtt_mm_get_mem_mapping_locked(ht, key, &tmp);
if (ret) {
- DRM_DEBUG("Cannot find key %ld\n", key);
+ DRM_DEBUG("Cannot find key %d\n", key);
return NULL;
}
spin_lock(&mm->lock);
ret = psb_gtt_mm_get_ht_by_pid_locked(mm, tgid, &hentry);
if (ret) {
- DRM_DEBUG("Cannot find entry for pid %ld\n", tgid);
+ DRM_DEBUG("Cannot find entry for pid %d\n", tgid);
spin_unlock(&mm->lock);
return ret;
}
/*check the count of mapping entry*/
if (!hentry->count) {
- DRM_DEBUG("count of mapping entry is zero, tgid=%ld\n", tgid);
+ DRM_DEBUG("count of mapping entry is zero, tgid=%d\n", tgid);
psb_gtt_mm_remove_free_ht_locked(mm, tgid);
}
uint32_t size, pages, offset_pages;
void *kmem;
struct drm_mm_node *node;
- struct page **page_list;
+ u32 *pfn_list = 0;
struct psb_gtt_mem_mapping *mapping = NULL;
int ret;
ret = psb_get_meminfo_by_handle(hKernelMemInfo, &psKernelMemInfo);
if (ret) {
- DRM_DEBUG("Cannot find kernelMemInfo handle %ld\n",
- hKernelMemInfo);
+ DRM_DEBUG("Cannot find kernelMemInfo handle %d\n",
+ (int)hKernelMemInfo);
return -EINVAL;
}
- DRM_DEBUG("Got psKernelMemInfo %p for handle %lx\n",
+ DRM_DEBUG("Got psKernelMemInfo %p for handle %x\n",
psKernelMemInfo, (u32)hKernelMemInfo);
size = psKernelMemInfo->uAllocSize;
kmem = psKernelMemInfo->pvLinAddrKM;
pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
- DRM_DEBUG("KerMemInfo size %ld, cpuVadr %lx, pages %ld, osMemHdl %lx\n",
- size, kmem, pages, psKernelMemInfo->sMemBlk.hOSMemHandle);
+ DRM_DEBUG("KerMemInfo size %d, cpuVadr %x, pages %d, osMemHdl %x\n",
+ size, kmem, pages,
+ (int)psKernelMemInfo->sMemBlk.hOSMemHandle);
if (!kmem)
DRM_DEBUG("kmem is NULL");
/*get pages*/
ret = psb_get_pages_by_mem_handle(psKernelMemInfo->sMemBlk.hOSMemHandle,
- &page_list);
+ &pfn_list, pages);
if (ret) {
DRM_DEBUG("get pages error\n");
return ret;
}
- DRM_DEBUG("get %ld pages\n", pages);
+ DRM_DEBUG("get %d pages\n", pages);
/*alloc memory in TT apeture*/
ret = psb_gtt_mm_alloc_mem(mm, pages, page_align, &node);
node = mapping->node;
offset_pages = node->start;
- DRM_DEBUG("get free node for %ld pages, offset %ld pages",
+ DRM_DEBUG("get free node for %d pages, offset %d pages",
pages, offset_pages);
/*update gtt*/
- psb_gtt_insert_pages(pg, page_list,
+ psb_gtt_insert_pfn_list(pg, pfn_list,
(unsigned)offset_pages,
(unsigned)pages,
0,
0,
0);
+ /*free pfn_list if allocated*/
+ kfree(pfn_list);
+
*offset = offset_pages;
return 0;
failed_add_node:
psb_gtt_mm_free_mem(mm, node);
failed_pages_alloc:
- kfree(page_list);
+ kfree(pfn_list);
return ret;
}
return 0;
}
+static int psb_gtt_map_bcd(struct drm_device *dev,
+ uint32_t device_id,
+ uint32_t buffer_id,
+ uint32_t page_align,
+ uint32_t *offset)
+{
+ struct drm_psb_private *dev_priv
+ = (struct drm_psb_private *)dev->dev_private;
+ struct psb_gtt_mm *mm = dev_priv->gtt_mm;
+ struct psb_gtt *pg = dev_priv->pg;
+ uint32_t pages, offset_pages;
+ struct drm_mm_node *node;
+ u32 *pfn_list = 0;
+ struct psb_gtt_mem_mapping *mapping = NULL;
+ int ret;
+
+ /*get pages*/
+ ret = psb_get_bcd_pages(device_id, buffer_id, &pfn_list, &pages);
+ if (ret) {
+ DRM_DEBUG("get pages error\n");
+ return ret;
+ }
+
+ DRM_DEBUG("get %d pages\n", pages);
+
+ /*alloc memory in TT apeture*/
+ ret = psb_gtt_mm_alloc_mem(mm, pages, page_align, &node);
+ if (ret) {
+ DRM_DEBUG("alloc TT memory error\n");
+ goto failed_pages_alloc;
+ }
+
+ /*update psb_gtt_mm*/
+ ret = psb_gtt_add_node(mm,
+ (u32)psb_get_tgid(),
+ ((device_id << 16) | (buffer_id)),
+ node,
+ &mapping);
+ if (ret) {
+ DRM_DEBUG("add_node failed");
+ goto failed_add_node;
+ }
+
+ node = mapping->node;
+ offset_pages = node->start;
+
+ DRM_DEBUG("get free node for %d pages, offset %d pages",
+ pages, offset_pages);
+
+ /*update gtt*/
+ psb_gtt_insert_pfn_list(pg, pfn_list,
+ (unsigned)offset_pages,
+ (unsigned)pages,
+ 0,
+ 0,
+ 0);
+
+ /*free pfn_list if allocated*/
+ kfree(pfn_list);
+
+ *offset = offset_pages;
+ return 0;
+
+failed_add_node:
+ psb_gtt_mm_free_mem(mm, node);
+failed_pages_alloc:
+ kfree(pfn_list);
+ return ret;
+}
+
+static int psb_gtt_unmap_bcd(struct drm_device *dev,
+ uint32_t device_id,
+ uint32_t buffer_id)
+{
+ struct drm_psb_private *dev_priv
+ = (struct drm_psb_private *)dev->dev_private;
+ struct psb_gtt_mm *mm = dev_priv->gtt_mm;
+ struct psb_gtt *pg = dev_priv->pg;
+ uint32_t pages, offset_pages;
+ struct drm_mm_node *node;
+ int ret;
+
+ ret = psb_gtt_remove_node(mm,
+ (u32)psb_get_tgid(),
+ ((device_id << 16) | buffer_id),
+ &node);
+ if (ret) {
+ DRM_DEBUG("remove node failed\n");
+ return ret;
+ }
+
+ /*remove gtt entries*/
+ offset_pages = node->start;
+ pages = node->size;
+
+ psb_gtt_remove_pages(pg, offset_pages, pages, 0, 0, 1);
+
+
+ /*free tt node*/
+ psb_gtt_mm_free_mem(mm, node);
+ return 0;
+}
+
+static int psb_gtt_get_bcd_device_info(struct drm_device *dev,
+ uint32_t bcd_id,
+ uint32_t *buf_count,
+ uint32_t *buf_stride)
+{
+ int count;
+ int stride;
+
+ if (!buf_count || !buf_stride) {
+ DRM_ERROR("invalid parameters\n");
+ return -EINVAL;
+ }
+
+ count = psb_get_bcd_buffer_count(bcd_id);
+ if (count <= 0) {
+ DRM_ERROR("failed to get bcd %d buffer count\n", bcd_id);
+ return -EINVAL;
+ }
+
+ stride = psb_get_bcd_buffer_stride(bcd_id);
+ if (stride <= 0) {
+ DRM_ERROR("failed to get bcd %d buffer stride\n", bcd_id);
+ return -EINVAL;
+ }
+
+ *buf_count = count;
+ *buf_stride = stride;
+
+ return 0;
+}
+
+static int psb_gtt_map_vaddr(struct drm_device *dev,
+ uint32_t vaddr,
+ uint32_t size,
+ uint32_t page_align,
+ uint32_t *offset)
+{
+ struct drm_psb_private *dev_priv
+ = (struct drm_psb_private *)dev->dev_private;
+ struct psb_gtt_mm *mm = dev_priv->gtt_mm;
+ struct psb_gtt *pg = dev_priv->pg;
+ uint32_t pages, offset_pages;
+ struct drm_mm_node *node;
+ u32 *pfn_list = 0;
+ struct psb_gtt_mem_mapping *mapping = NULL;
+ int ret;
+
+ /*get pages*/
+ ret = psb_get_vaddr_pages(vaddr, size, &pfn_list, &pages);
+ if (ret) {
+ DRM_DEBUG("get pages error\n");
+ return ret;
+ }
+
+ DRM_DEBUG("get %d pages\n", pages);
+
+ /*alloc memory in TT apeture*/
+ ret = psb_gtt_mm_alloc_mem(mm, pages, page_align, &node);
+ if (ret) {
+ DRM_DEBUG("alloc TT memory error\n");
+ goto failed_pages_alloc;
+ }
+
+ /*update psb_gtt_mm*/
+ ret = psb_gtt_add_node(mm,
+ (u32)psb_get_tgid(),
+ vaddr,
+ node,
+ &mapping);
+ if (ret) {
+ DRM_DEBUG("add_node failed");
+ goto failed_add_node;
+ }
+
+ node = mapping->node;
+ offset_pages = node->start;
+
+ DRM_DEBUG("get free node for %d pages, offset %d pages",
+ pages, offset_pages);
+
+ /*update gtt*/
+ psb_gtt_insert_pfn_list(pg, pfn_list,
+ (unsigned)offset_pages,
+ (unsigned)pages,
+ 0,
+ 0,
+ 0);
+
+ /*free pfn_list if allocated*/
+ kfree(pfn_list);
+
+ *offset = offset_pages;
+ return 0;
+
+failed_add_node:
+ psb_gtt_mm_free_mem(mm, node);
+failed_pages_alloc:
+ kfree(pfn_list);
+ return ret;
+}
+
+static int psb_gtt_unmap_vaddr(struct drm_device *dev,
+ uint32_t vaddr,
+ uint32_t size)
+{
+ struct drm_psb_private *dev_priv
+ = (struct drm_psb_private *)dev->dev_private;
+ struct psb_gtt_mm *mm = dev_priv->gtt_mm;
+ struct psb_gtt *pg = dev_priv->pg;
+ uint32_t pages, offset_pages;
+ struct drm_mm_node *node;
+ int ret;
+
+ ret = psb_gtt_remove_node(mm,
+ (u32)psb_get_tgid(),
+ vaddr,
+ &node);
+ if (ret) {
+ DRM_DEBUG("remove node failed\n");
+ return ret;
+ }
+
+ /*remove gtt entries*/
+ offset_pages = node->start;
+ pages = node->size;
+
+ psb_gtt_remove_pages(pg, offset_pages, pages, 0, 0, 1);
+
+
+ /*free tt node*/
+ psb_gtt_mm_free_mem(mm, node);
+ return 0;
+}
+
int psb_gtt_map_meminfo_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
= (struct psb_gtt_mapping_arg *)data;
uint32_t *offset_pages = &arg->offset_pages;
uint32_t page_align = arg->page_align;
+ uint32_t device_id = arg->bcd_device_id;
+ uint32_t buffer_id = arg->bcd_buffer_id;
+ uint32_t *buffer_count = &arg->bcd_buffer_count;
+ uint32_t *buffer_stride = &arg->bcd_buffer_stride;
+ uint32_t vaddr = arg->vaddr;
+ uint32_t size = arg->size;
+ uint32_t type = arg->type;
DRM_DEBUG("\n");
- return psb_gtt_map_meminfo(dev,
+ switch (type) {
+ case PSB_GTT_MAP_TYPE_MEMINFO:
+ return psb_gtt_map_meminfo(dev,
arg->hKernelMemInfo,
page_align,
offset_pages);
+ case PSB_GTT_MAP_TYPE_BCD:
+ return psb_gtt_map_bcd(dev,
+ device_id, buffer_id,
+ page_align,
+ offset_pages);
+ case PSB_GTT_MAP_TYPE_VIRTUAL:
+ return psb_gtt_map_vaddr(dev,
+ vaddr,
+ size,
+ page_align,
+ offset_pages);
+ case PSB_GTT_MAP_TYPE_BCD_INFO:
+ return psb_gtt_get_bcd_device_info(dev,
+ device_id,
+ buffer_count,
+ buffer_stride);
+ default:
+ DRM_ERROR("unsupported buffer type %d\n", type);
+ return -EINVAL;
+ }
}
int psb_gtt_unmap_meminfo_ioctl(struct drm_device *dev, void *data,
{
struct psb_gtt_mapping_arg *arg
- = (struct psb_gtt_mapping_arg *)data;
+ = (struct psb_gtt_mapping_arg *)data;
+ uint32_t device_id = arg->bcd_device_id;
+ uint32_t buffer_id = arg->bcd_buffer_id;
+ uint32_t vaddr = arg->vaddr;
+ uint32_t size = arg->size;
+ uint32_t type = arg->type;
DRM_DEBUG("\n");
- return psb_gtt_unmap_meminfo(dev, arg->hKernelMemInfo);
+ switch (type) {
+ case PSB_GTT_MAP_TYPE_MEMINFO:
+ return psb_gtt_unmap_meminfo(dev, arg->hKernelMemInfo);
+ case PSB_GTT_MAP_TYPE_BCD:
+ return psb_gtt_unmap_bcd(dev, device_id, buffer_id);
+ case PSB_GTT_MAP_TYPE_VIRTUAL:
+ return psb_gtt_unmap_vaddr(dev, vaddr, size);
+ default:
+ DRM_ERROR("unsupported buffer type %d\n", type);
+ return -EINVAL;
+ }
}
int psb_gtt_map_pvr_memory(struct drm_device *dev,
node = mapping->node;
offset_pages = node->start;
- DRM_DEBUG("get free node for %ld pages, offset %ld pages", pages, offset_pages);
+ DRM_DEBUG("get free node for %d pages, offset %d pages",
+ pages, offset_pages);
/*update gtt*/
psb_gtt_insert_phys_addresses(pg, pPages, (unsigned)offset_pages, (unsigned)ui32PagesNum, 0);
*/
#include "psb_pvr_glue.h"
+#include <asm/page.h>
/**
* FIXME: should NOT use these file under env/linux directly
*ppsKernelMemInfo = psKernelMemInfo;
- DRM_DEBUG("Got Kernel MemInfo for handle %lx\n",
+ DRM_DEBUG("Got Kernel MemInfo for handle %x\n",
(IMG_UINT32)hKernelMemInfo);
return 0;
}
return OSGetCurrentProcessIDKM();
}
-int psb_get_pages_by_mem_handle(IMG_HANDLE hOSMemHandle, struct page ***pages)
+int psb_get_pages_by_mem_handle(IMG_HANDLE hOSMemHandle,
+ u32 **pfn_list,
+ int page_count)
{
LinuxMemArea *psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
- struct page **page_list;
+ u32 *pfns = 0;
+ IMG_CPU_PHYADDR phys_addr;
+ int i;
- if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_ALLOC_PAGES) {
- DRM_ERROR("MemArea type is not LINUX_MEM_AREA_ALLOC_PAGES\n");
+ if (!pfn_list)
return -EINVAL;
+
+ /*allocate page list*/
+ pfns = kzalloc(page_count * sizeof(u32), GFP_KERNEL);
+ if (!pfns) {
+ DRM_ERROR("No memory\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < page_count; i++) {
+ phys_addr.uiAddr = 0;
+
+ phys_addr =
+ LinuxMemAreaToCpuPAddr(psLinuxMemArea, i * PAGE_SIZE);
+ pfns[i] = ((u32)phys_addr.uiAddr) >> PAGE_SHIFT;
}
- page_list = psLinuxMemArea->uData.sPageList.pvPageList;
- if (!page_list) {
- DRM_DEBUG("Page List is NULL\n");
+ *pfn_list = pfns;
+ return 0;
+}
+
+int psb_get_bcd_pages(u32 device_id, u32 buffer_id, u32 **pfn_list, int *pages)
+{
+ BC_VIDEO_BUFFER *buffer;
+ u32 size;
+ u32 num_pages;
+ int is_contig;
+ int err;
+ u32 phys_addr;
+ u32 *pfns = 0;
+ int i;
+
+ if (!pfn_list || !pages)
+ return -EINVAL;
+
+ err = BCGetBuffer(device_id, buffer_id, &buffer);
+ if (err)
+ return err;
+
+ size = buffer->ulSize;
+ num_pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+ is_contig = buffer->is_conti_addr;
+
+ /*allocate page list*/
+ pfns = kzalloc(num_pages * sizeof(u32), GFP_KERNEL);
+ if (!pfns) {
+ DRM_ERROR("No memory\n");
return -ENOMEM;
}
- *pages = page_list;
+ if (is_contig) {
+ phys_addr = (u32)buffer->psSysAddr[0].uiAddr;
+ for (i = 0; i < num_pages; i++)
+ pfns[i] = (phys_addr + i * PAGE_SIZE) >> PAGE_SHIFT;
+ } else {
+ for (i = 0; i < num_pages; i++) {
+ phys_addr = (u32)buffer->psSysAddr[i].uiAddr;
+ pfns[i] = phys_addr >> PAGE_SHIFT;
+ }
+ }
+
+ *pfn_list = pfns;
+ *pages = num_pages;
+
return 0;
}
+
+int psb_get_vaddr_pages(u32 vaddr, u32 size, u32 **pfn_list, int *page_count)
+{
+ u32 num_pages;
+ struct page **pages = 0;
+ struct task_struct *task = current;
+ struct mm_struct *mm = task->mm;
+ struct vm_area_struct *vma;
+ u32 *pfns = 0;
+ int ret;
+ int i;
+
+ if (unlikely(!pfn_list || !page_count || !vaddr || !size))
+ return -EINVAL;
+
+ num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ pages = kzalloc(num_pages * sizeof(struct page *), GFP_KERNEL);
+ if (unlikely(!pages)) {
+ DRM_ERROR("Failed to allocate page list\n");
+ return -ENOMEM;
+ }
+
+ down_read(&mm->mmap_sem);
+ ret = get_user_pages(task, mm, vaddr, num_pages, 0, 0, pages, NULL);
+ up_read(&mm->mmap_sem);
+
+ if (ret <= 0) {
+ DRM_DEBUG("failed to get user pages\n");
+ kfree(pages);
+ pages = 0;
+ } else {
+ DRM_DEBUG("num_pages %d, ret %d\n", num_pages, ret);
+ num_pages = ret;
+ }
+
+ /*allocate page list*/
+ pfns = kzalloc(num_pages * sizeof(u32), GFP_KERNEL);
+ if (!pfns) {
+ DRM_ERROR("No memory\n");
+ goto get_page_err;
+ }
+
+ if (!pages) {
+ DRM_ERROR("No pages found, trying to follow pfn\n");
+ for (i = 0; i < num_pages; i++) {
+ vma = find_vma(mm, vaddr + i * PAGE_SIZE);
+ if (!vma) {
+ DRM_ERROR("failed to find vma\n");
+ goto find_vma_err;
+ }
+
+ ret = follow_pfn(vma,
+ (unsigned long)(vaddr + i * PAGE_SIZE),
+ (unsigned long *)&pfns[i]);
+ if (ret) {
+ DRM_ERROR("failed to follow pfn\n");
+ goto follow_pfn_err;
+ }
+ }
+ } else {
+ DRM_ERROR("Found pages\n");
+ for (i = 0; i < num_pages; i++)
+ pfns[i] = page_to_pfn(pages[i]);
+ }
+
+ *pfn_list = pfns;
+ *page_count = num_pages;
+
+ kfree(pages);
+
+ return 0;
+find_vma_err:
+follow_pfn_err:
+ kfree(pfns);
+get_page_err:
+ if (pages) {
+ for (i = 0; i < num_pages; i++)
+ put_page(pages[i]);
+ kfree(pages);
+ }
+ return -EINVAL;
+}
+
+int psb_get_bcd_buffer_count(uint32_t bcd_id)
+{
+ return BCGetDeviceBufferCount(bcd_id);
+}
+
+int psb_get_bcd_buffer_stride(uint32_t bcd_id)
+{
+ return BCGetDeviceStride(bcd_id);
+}