mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 14:42:37 +02:00
drm/rockchip: gem: reorder pages if page chunk less than 8
Change-Id: I03a91d2f9c017086b3cb35edeaf6b7913b147b9b Signed-off-by: Simon Xue <xxm@rock-chips.com>
This commit is contained in:
parent
e381404955
commit
773a33a1cc
|
|
@ -16,6 +16,13 @@
|
||||||
#include "rockchip_drm_drv.h"
|
#include "rockchip_drm_drv.h"
|
||||||
#include "rockchip_drm_gem.h"
|
#include "rockchip_drm_gem.h"
|
||||||
|
|
||||||
|
struct page_info {
|
||||||
|
struct page *page;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PG_ROUND 8
|
||||||
|
|
||||||
static int rockchip_gem_iommu_map(struct rockchip_gem_object *rk_obj)
|
static int rockchip_gem_iommu_map(struct rockchip_gem_object *rk_obj)
|
||||||
{
|
{
|
||||||
struct drm_device *drm = rk_obj->base.dev;
|
struct drm_device *drm = rk_obj->base.dev;
|
||||||
|
|
@ -73,23 +80,119 @@ static int rockchip_gem_iommu_unmap(struct rockchip_gem_object *rk_obj)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rockchip_gem_free_list(struct list_head lists[])
|
||||||
|
{
|
||||||
|
struct page_info *info, *tmp_info;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < PG_ROUND; i++) {
|
||||||
|
list_for_each_entry_safe(info, tmp_info, &lists[i], list) {
|
||||||
|
list_del(&info->list);
|
||||||
|
kfree(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int rockchip_gem_get_pages(struct rockchip_gem_object *rk_obj)
|
static int rockchip_gem_get_pages(struct rockchip_gem_object *rk_obj)
|
||||||
{
|
{
|
||||||
struct drm_device *drm = rk_obj->base.dev;
|
struct drm_device *drm = rk_obj->base.dev;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
struct scatterlist *s;
|
struct scatterlist *s;
|
||||||
|
unsigned int cur_page;
|
||||||
|
struct page **pages, **dst_pages;
|
||||||
|
int j;
|
||||||
|
int n_pages;
|
||||||
|
unsigned long chunk_pages;
|
||||||
|
unsigned long remain;
|
||||||
|
struct list_head lists[PG_ROUND];
|
||||||
|
dma_addr_t phys;
|
||||||
|
int end = 0;
|
||||||
|
unsigned int bit12_14;
|
||||||
|
unsigned int block_index[PG_ROUND] = {0};
|
||||||
|
struct page_info *info;
|
||||||
|
unsigned int maximum;
|
||||||
|
|
||||||
rk_obj->pages = drm_gem_get_pages(&rk_obj->base);
|
for (i = 0; i < PG_ROUND; i++)
|
||||||
if (IS_ERR(rk_obj->pages))
|
INIT_LIST_HEAD(&lists[i]);
|
||||||
return PTR_ERR(rk_obj->pages);
|
|
||||||
|
pages = drm_gem_get_pages(&rk_obj->base);
|
||||||
|
if (IS_ERR(pages))
|
||||||
|
return PTR_ERR(pages);
|
||||||
|
|
||||||
|
rk_obj->pages = pages;
|
||||||
|
|
||||||
rk_obj->num_pages = rk_obj->base.size >> PAGE_SHIFT;
|
rk_obj->num_pages = rk_obj->base.size >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
n_pages = rk_obj->num_pages;
|
||||||
|
|
||||||
|
dst_pages = __vmalloc(sizeof(struct page *) * n_pages,
|
||||||
|
GFP_KERNEL | __GFP_HIGHMEM);
|
||||||
|
if (!dst_pages) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err_put_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_page = 0;
|
||||||
|
remain = n_pages;
|
||||||
|
/* look for the end of the current chunk */
|
||||||
|
while (remain) {
|
||||||
|
for (j = cur_page + 1; j < n_pages; ++j) {
|
||||||
|
if (page_to_pfn(pages[j]) !=
|
||||||
|
page_to_pfn(pages[j - 1]) + 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk_pages = j - cur_page;
|
||||||
|
if (chunk_pages > 7) {
|
||||||
|
for (i = 0; i < chunk_pages; i++)
|
||||||
|
dst_pages[end + i] = pages[cur_page + i];
|
||||||
|
end += chunk_pages;
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < chunk_pages; i++) {
|
||||||
|
info = kmalloc(sizeof(*info), GFP_KERNEL);
|
||||||
|
if (!info) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err_put_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&info->list);
|
||||||
|
info->page = pages[cur_page + i];
|
||||||
|
phys = page_to_phys(info->page);
|
||||||
|
bit12_14 = (phys >> 12) & 0x7;
|
||||||
|
list_add_tail(&info->list, &lists[bit12_14]);
|
||||||
|
block_index[bit12_14]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_page = j;
|
||||||
|
remain -= chunk_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
maximum = block_index[0];
|
||||||
|
for (i = 1; i < PG_ROUND; i++)
|
||||||
|
maximum = max(maximum, block_index[i]);
|
||||||
|
|
||||||
|
for (i = 0; i < maximum; i++) {
|
||||||
|
for (j = 0; j < PG_ROUND; j++) {
|
||||||
|
if (!list_empty(&lists[j])) {
|
||||||
|
struct page_info *info;
|
||||||
|
|
||||||
|
info = list_first_entry(&lists[j],
|
||||||
|
struct page_info, list);
|
||||||
|
dst_pages[end++] = info->page;
|
||||||
|
list_del(&info->list);
|
||||||
|
kfree(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s, %d, end = %d, n_pages = %d\n", __func__, __LINE__,
|
||||||
|
end, n_pages);
|
||||||
rk_obj->sgt = drm_prime_pages_to_sg(rk_obj->base.dev,
|
rk_obj->sgt = drm_prime_pages_to_sg(rk_obj->base.dev,
|
||||||
rk_obj->pages, rk_obj->num_pages);
|
dst_pages, rk_obj->num_pages);
|
||||||
if (IS_ERR(rk_obj->sgt)) {
|
if (IS_ERR(rk_obj->sgt)) {
|
||||||
ret = PTR_ERR(rk_obj->sgt);
|
ret = PTR_ERR(rk_obj->sgt);
|
||||||
goto err_put_pages;
|
goto err_put_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -104,8 +207,13 @@ static int rockchip_gem_get_pages(struct rockchip_gem_object *rk_obj)
|
||||||
|
|
||||||
dma_sync_sgtable_for_device(drm->dev, rk_obj->sgt, DMA_TO_DEVICE);
|
dma_sync_sgtable_for_device(drm->dev, rk_obj->sgt, DMA_TO_DEVICE);
|
||||||
|
|
||||||
|
kvfree(pages);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_put_list:
|
||||||
|
rockchip_gem_free_list(lists);
|
||||||
|
kvfree(dst_pages);
|
||||||
err_put_pages:
|
err_put_pages:
|
||||||
drm_gem_put_pages(&rk_obj->base, rk_obj->pages, false, false);
|
drm_gem_put_pages(&rk_obj->base, rk_obj->pages, false, false);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user