From: Jackie Li Date: Wed, 23 Nov 2011 15:00:06 +0000 (+0800) Subject: gfx-gtt: enhanced GTT memory manager to support different buffer types. X-Git-Tag: 2.1b_release~1858 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=787bdba308f8606b4646da2527e40e3f61e9b456;p=kernel%2Fkernel-mfld-blackbay.git gfx-gtt: enhanced GTT memory manager to support different buffer types. This is patch 2/5 of HWC enabling. Added three interfaces to GTT memory manager to support follow buffers: 1) all kinds of PVR meminfo 2) BCD buffer 3) user mode allocated buffer. Change-Id: I9bdcd4f18cf01ab58976c495d51b0aa0a3d27583 Signed-off-by: Jackie Li Reviewed-on: http://android.intel.com:8080/25090 Reviewed-by: buildbot Reviewed-by: Gross, Mark Tested-by: Gross, Mark --- diff --git a/drivers/staging/mrst/bc_video/bufferclass_video_linux.c b/drivers/staging/mrst/bc_video/bufferclass_video_linux.c index 8b42692..a67c2eb 100755 --- a/drivers/staging/mrst/bc_video/bufferclass_video_linux.c +++ b/drivers/staging/mrst/bc_video/bufferclass_video_linux.c @@ -898,3 +898,54 @@ BC_Camera_Bridge(BC_Video_ioctl_package * psBridge, unsigned long pAddr) return 0; } EXPORT_SYMBOL_GPL(BC_Camera_Bridge); + +int BCGetBuffer(int devId, int bufferId, BC_VIDEO_BUFFER **bc_buffer) +{ + BC_VIDEO_DEVINFO *devInfo; + unsigned long bufferCount; + BC_VIDEO_BUFFER *buffer; + + if (devId < 0 || devId > BC_CAMERA_DEVICEID || !bc_buffer) + return -EINVAL; + + devInfo = GetAnchorPtr(devId); + if (!devInfo) + return -ENODEV; + + bufferCount = devInfo->ulNumBuffers; + if (bufferId >= bufferCount) + return -EINVAL; + + buffer = &devInfo->psSystemBuffer[bufferId]; + *bc_buffer = buffer; + return 0; +} +EXPORT_SYMBOL_GPL(BCGetBuffer); + +int BCGetDeviceBufferCount(int devId) +{ + BC_VIDEO_DEVINFO *devInfo; + + if (devId < 0 || devId > BC_CAMERA_DEVICEID) + return -EINVAL; + + devInfo = GetAnchorPtr(devId); + if (!devInfo) + return -ENODEV; + return devInfo->ulNumBuffers; +} +EXPORT_SYMBOL_GPL(BCGetDeviceBufferCount); + +int BCGetDeviceStride(int devId) +{ + BC_VIDEO_DEVINFO *devInfo; + + if (devId < 0 || devId > BC_CAMERA_DEVICEID) + return -EINVAL; + + devInfo = GetAnchorPtr(devId); + if (!devInfo) + return -ENODEV; + + return devInfo->sBufferInfo.ui32ByteStride; +} diff --git a/drivers/staging/mrst/bc_video/bufferclass_video_linux.h b/drivers/staging/mrst/bc_video/bufferclass_video_linux.h index 292e788..10d9f67 100755 --- a/drivers/staging/mrst/bc_video/bufferclass_video_linux.h +++ b/drivers/staging/mrst/bc_video/bufferclass_video_linux.h @@ -66,4 +66,5 @@ typedef struct bc_buf_ptr { int BC_Camera_Bridge(BC_Video_ioctl_package *spBridge, unsigned long pAddr); int BC_DestroyBuffers(int id); + #endif diff --git a/drivers/staging/mrst/drv/psb_drm.h b/drivers/staging/mrst/drv/psb_drm.h index 7ee2a5a..b13f774 100644 --- a/drivers/staging/mrst/drv/psb_drm.h +++ b/drivers/staging/mrst/drv/psb_drm.h @@ -566,15 +566,15 @@ struct drm_psb_stolen_memory_arg { #define REGRWBITS_PIPEBSRC (1 << 4) #define REGRWBITS_VTOTAL_A (1 << 5) #define REGRWBITS_VTOTAL_B (1 << 6) -#define REGRWBITS_DSPACNTR (1 << 8) -#define REGRWBITS_DSPBCNTR (1 << 9) -#define REGRWBITS_DSPCCNTR (1 << 10) +#define REGRWBITS_DSPACNTR (1 << 8) +#define REGRWBITS_DSPBCNTR (1 << 9) +#define REGRWBITS_DSPCCNTR (1 << 10) #define REGRWBITS_SPRITE_UPDATE (1 << 11) /*Overlay Register Bits*/ #define OV_REGRWBITS_OVADD (1 << 0) #define OV_REGRWBITS_OGAM_ALL (1 << 1) -#define OVC_REGRWBITS_OVADD (1 << 2) +#define OVC_REGRWBITS_OVADD (1 << 2) #define OVC_REGRWBITS_OGAM_ALL (1 << 3) /*sprite update fields*/ #define SPRITE_UPDATE_SURFACE (0x00000001UL) @@ -606,8 +606,6 @@ struct drm_psb_register_rw_arg { uint32_t display_read_mask; uint32_t display_write_mask; - uint32_t sprite_context_mask; - struct intel_sprite_context sprite_context; struct { uint32_t pfit_controls; uint32_t pfit_autoscale_ratios; @@ -620,6 +618,9 @@ struct drm_psb_register_rw_arg { uint32_t dspcntr_b; } display; + uint32_t sprite_context_mask; + struct intel_sprite_context sprite_context; + uint32_t overlay_read_mask; uint32_t overlay_write_mask; @@ -657,10 +658,24 @@ struct drm_psb_register_rw_arg { uint32_t subpicture_disable_mask; }; +enum { + PSB_GTT_MAP_TYPE_MEMINFO = 0, + PSB_GTT_MAP_TYPE_BCD, + PSB_GTT_MAP_TYPE_BCD_INFO, + PSB_GTT_MAP_TYPE_VIRTUAL, +}; + struct psb_gtt_mapping_arg { + uint32_t type; void *hKernelMemInfo; uint32_t offset_pages; uint32_t page_align; + uint32_t bcd_device_id; + uint32_t bcd_buffer_id; + uint32_t bcd_buffer_count; + uint32_t bcd_buffer_stride; + uint32_t vaddr; + uint32_t size; }; struct drm_psb_getpageaddrs_arg { diff --git a/drivers/staging/mrst/drv/psb_drv.c b/drivers/staging/mrst/drv/psb_drv.c index 97ea257..6195895 100755 --- a/drivers/staging/mrst/drv/psb_drv.c +++ b/drivers/staging/mrst/drv/psb_drv.c @@ -2719,6 +2719,7 @@ static int psb_register_rw_ioctl(struct drm_device *dev, void *data, UHBUsage usage = arg->b_force_hw_on ? OSPM_UHB_FORCE_POWER_ON : OSPM_UHB_ONLY_IF_ON; uint32_t ovadd; + if (arg->sprite_context_mask & REGRWBITS_SPRITE_UPDATE) { if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, usage)) return -EAGAIN; @@ -2733,21 +2734,28 @@ static int psb_register_rw_ioctl(struct drm_device *dev, void *data, return -EINVAL; if ((arg->sprite_context.update_mask & SPRITE_UPDATE_POSITION)) - PSB_WVDC32(arg->sprite_context.pos, DSPAPOS + reg_offset); + PSB_WVDC32(arg->sprite_context.pos, + DSPAPOS + reg_offset); if ((arg->sprite_context.update_mask & SPRITE_UPDATE_SIZE)) { - PSB_WVDC32(arg->sprite_context.size, DSPASIZE + reg_offset); - PSB_WVDC32(arg->sprite_context.stride, DSPASTRIDE + reg_offset); + PSB_WVDC32(arg->sprite_context.size, + DSPASIZE + reg_offset); + PSB_WVDC32(arg->sprite_context.stride, + DSPASTRIDE + reg_offset); } if ((arg->sprite_context.update_mask & SPRITE_UPDATE_SURFACE)) { - PSB_WVDC32(arg->sprite_context.linoff, DSPALINOFF + reg_offset); - PSB_WVDC32(arg->sprite_context.surf, DSPASURF + reg_offset); + PSB_WVDC32(arg->sprite_context.linoff, + DSPALINOFF + reg_offset); + PSB_WVDC32(arg->sprite_context.surf, + DSPASURF + reg_offset); } if ((arg->sprite_context.update_mask & SPRITE_UPDATE_CONTROL)) { - PSB_WVDC32(arg->sprite_context.cntr, DSPACNTR + reg_offset); - PSB_WVDC32(PSB_RVDC32(DSPASURF + reg_offset), DSPASURF + reg_offset); + PSB_WVDC32(arg->sprite_context.cntr, + DSPACNTR + reg_offset); + PSB_WVDC32(PSB_RVDC32(DSPASURF + reg_offset), + DSPASURF + reg_offset); } ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); } diff --git a/drivers/staging/mrst/drv/psb_gtt.c b/drivers/staging/mrst/drv/psb_gtt.c index 8b0f435..53d2ecf 100644 --- a/drivers/staging/mrst/drv/psb_gtt.c +++ b/drivers/staging/mrst/drv/psb_gtt.c @@ -167,8 +167,6 @@ int psb_gtt_init(struct psb_gtt *pg, int resume) 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; @@ -318,7 +316,6 @@ static int psb_gtt_insert_pfn_list(struct psb_gtt *pg, u32 *pfn_list, return 0; } - int psb_gtt_insert_phys_addresses(struct psb_gtt *pg, IMG_CPU_PHYADDR *pPhysFrames, unsigned offset_pages, unsigned num_pages, int type) { @@ -456,7 +453,7 @@ static int psb_gtt_mm_get_ht_by_pid_locked(struct psb_gtt_mm *mm, 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; } @@ -518,7 +515,7 @@ static int psb_gtt_mm_alloc_insert_ht(struct psb_gtt_mm *mm, 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); @@ -526,7 +523,7 @@ static int psb_gtt_mm_alloc_insert_ht(struct psb_gtt_mm *mm, } 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) { @@ -557,7 +554,7 @@ psb_gtt_mm_remove_ht_locked(struct psb_gtt_mm *mm, u32 tgid) { 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; } @@ -599,7 +596,7 @@ psb_gtt_mm_get_mem_mapping_locked(struct drm_open_hash *ht, 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; } @@ -662,7 +659,7 @@ psb_gtt_mm_alloc_insert_mem_mapping(struct psb_gtt_mm *mm, 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); @@ -670,7 +667,7 @@ psb_gtt_mm_alloc_insert_mem_mapping(struct psb_gtt_mm *mm, } 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); @@ -699,7 +696,7 @@ psb_gtt_mm_remove_mem_mapping_locked(struct drm_open_hash *ht, u32 key) { 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; } @@ -773,7 +770,7 @@ static int psb_gtt_remove_node(struct psb_gtt_mm *mm, 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; } @@ -794,7 +791,7 @@ static int psb_gtt_remove_node(struct psb_gtt_mm *mm, /*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); } @@ -859,39 +856,40 @@ int psb_gtt_map_meminfo(struct drm_device *dev, 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); @@ -914,24 +912,27 @@ int psb_gtt_map_meminfo(struct drm_device *dev, 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; } @@ -967,6 +968,243 @@ int psb_gtt_unmap_meminfo(struct drm_device *dev, IMG_HANDLE hKernelMemInfo) 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) { @@ -974,13 +1212,42 @@ int psb_gtt_map_meminfo_ioctl(struct drm_device *dev, void *data, = (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, @@ -988,11 +1255,26 @@ 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, @@ -1035,7 +1317,8 @@ 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); diff --git a/drivers/staging/mrst/drv/psb_pvr_glue.c b/drivers/staging/mrst/drv/psb_pvr_glue.c index 88641c1..92bbe1f 100644 --- a/drivers/staging/mrst/drv/psb_pvr_glue.c +++ b/drivers/staging/mrst/drv/psb_pvr_glue.c @@ -17,6 +17,7 @@ */ #include "psb_pvr_glue.h" +#include /** * FIXME: should NOT use these file under env/linux directly @@ -43,7 +44,7 @@ int psb_get_meminfo_by_handle(IMG_HANDLE hKernelMemInfo, *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; } @@ -53,22 +54,172 @@ IMG_UINT32 psb_get_tgid(void) 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); +} diff --git a/drivers/staging/mrst/drv/psb_pvr_glue.h b/drivers/staging/mrst/drv/psb_pvr_glue.h index 3c2ae45..9b16356 100644 --- a/drivers/staging/mrst/drv/psb_pvr_glue.h +++ b/drivers/staging/mrst/drv/psb_pvr_glue.h @@ -18,9 +18,20 @@ #include "psb_drv.h" #include "services_headers.h" +#include "bufferclass_video.h" + +int BCGetBuffer(int devId, int bufferId, BC_VIDEO_BUFFER **bc_buffer); +int BCGetDeviceBufferCount(int devId); +int BCGetDeviceStride(int devId); extern int psb_get_meminfo_by_handle(IMG_HANDLE hKernelMemInfo, PVRSRV_KERNEL_MEM_INFO **ppsKernelMemInfo); extern IMG_UINT32 psb_get_tgid(void); extern int psb_get_pages_by_mem_handle(IMG_HANDLE hOSMemHandle, - struct page ***pages); + u32 **pfn_list, + int page_count); +extern int psb_get_bcd_pages(u32 device_id, u32 buffer_id, u32 **pfn_list, + int *pages); +extern int psb_get_vaddr_pages(u32 vaddr, u32 size, u32 **pfn_list, int *pages); +extern int psb_get_bcd_buffer_count(uint32_t bcd_id); +extern int psb_get_bcd_buffer_stride(uint32_t bcd_id);