Commit 8f2112f8 authored by Roger He's avatar Roger He Committed by Alex Deucher

drm/ttm: add VADDR_FLAG_UPDATED_COUNT to correctly update dma_page global count

add this for correctly updating global mem count in ttm_mem_zone.
before that when ttm_mem_global_alloc_page fails, we would update all
dma_page's global mem count in ttm_dma->pages_list. but actually here
we should not update for the last dma_page.

v2: only the update of last dma_page is not right
v3: use lower bits of dma_page vaddr
Signed-off-by: default avatarRoger He <Hongbo.He@amd.com>
Reviewed-by: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 8159e509
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#define SMALL_ALLOCATION 4 #define SMALL_ALLOCATION 4
#define FREE_ALL_PAGES (~0U) #define FREE_ALL_PAGES (~0U)
#define VADDR_FLAG_HUGE_POOL 1UL #define VADDR_FLAG_HUGE_POOL 1UL
#define VADDR_FLAG_UPDATED_COUNT 2UL
enum pool_type { enum pool_type {
IS_UNDEFINED = 0, IS_UNDEFINED = 0,
...@@ -874,18 +875,18 @@ static int ttm_dma_page_pool_fill_locked(struct dma_pool *pool, ...@@ -874,18 +875,18 @@ static int ttm_dma_page_pool_fill_locked(struct dma_pool *pool,
} }
/* /*
* @return count of pages still required to fulfill the request.
* The populate list is actually a stack (not that is matters as TTM * The populate list is actually a stack (not that is matters as TTM
* allocates one page at a time. * allocates one page at a time.
* return dma_page pointer if success, otherwise NULL.
*/ */
static int ttm_dma_pool_get_pages(struct dma_pool *pool, static struct dma_page *ttm_dma_pool_get_pages(struct dma_pool *pool,
struct ttm_dma_tt *ttm_dma, struct ttm_dma_tt *ttm_dma,
unsigned index) unsigned index)
{ {
struct dma_page *d_page; struct dma_page *d_page = NULL;
struct ttm_tt *ttm = &ttm_dma->ttm; struct ttm_tt *ttm = &ttm_dma->ttm;
unsigned long irq_flags; unsigned long irq_flags;
int count, r = -ENOMEM; int count;
spin_lock_irqsave(&pool->lock, irq_flags); spin_lock_irqsave(&pool->lock, irq_flags);
count = ttm_dma_page_pool_fill_locked(pool, &irq_flags); count = ttm_dma_page_pool_fill_locked(pool, &irq_flags);
...@@ -894,12 +895,11 @@ static int ttm_dma_pool_get_pages(struct dma_pool *pool, ...@@ -894,12 +895,11 @@ static int ttm_dma_pool_get_pages(struct dma_pool *pool,
ttm->pages[index] = d_page->p; ttm->pages[index] = d_page->p;
ttm_dma->dma_address[index] = d_page->dma; ttm_dma->dma_address[index] = d_page->dma;
list_move_tail(&d_page->page_list, &ttm_dma->pages_list); list_move_tail(&d_page->page_list, &ttm_dma->pages_list);
r = 0;
pool->npages_in_use += 1; pool->npages_in_use += 1;
pool->npages_free -= 1; pool->npages_free -= 1;
} }
spin_unlock_irqrestore(&pool->lock, irq_flags); spin_unlock_irqrestore(&pool->lock, irq_flags);
return r; return d_page;
} }
static gfp_t ttm_dma_pool_gfp_flags(struct ttm_dma_tt *ttm_dma, bool huge) static gfp_t ttm_dma_pool_gfp_flags(struct ttm_dma_tt *ttm_dma, bool huge)
...@@ -934,6 +934,7 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev, ...@@ -934,6 +934,7 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev,
struct ttm_mem_global *mem_glob = ttm->glob->mem_glob; struct ttm_mem_global *mem_glob = ttm->glob->mem_glob;
unsigned long num_pages = ttm->num_pages; unsigned long num_pages = ttm->num_pages;
struct dma_pool *pool; struct dma_pool *pool;
struct dma_page *d_page;
enum pool_type type; enum pool_type type;
unsigned i; unsigned i;
int ret; int ret;
...@@ -962,8 +963,8 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev, ...@@ -962,8 +963,8 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev,
while (num_pages >= HPAGE_PMD_NR) { while (num_pages >= HPAGE_PMD_NR) {
unsigned j; unsigned j;
ret = ttm_dma_pool_get_pages(pool, ttm_dma, i); d_page = ttm_dma_pool_get_pages(pool, ttm_dma, i);
if (ret != 0) if (!d_page)
break; break;
ret = ttm_mem_global_alloc_page(mem_glob, ttm->pages[i], ret = ttm_mem_global_alloc_page(mem_glob, ttm->pages[i],
...@@ -973,6 +974,7 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev, ...@@ -973,6 +974,7 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev,
return -ENOMEM; return -ENOMEM;
} }
d_page->vaddr |= VADDR_FLAG_UPDATED_COUNT;
for (j = i + 1; j < (i + HPAGE_PMD_NR); ++j) { for (j = i + 1; j < (i + HPAGE_PMD_NR); ++j) {
ttm->pages[j] = ttm->pages[j - 1] + 1; ttm->pages[j] = ttm->pages[j - 1] + 1;
ttm_dma->dma_address[j] = ttm_dma->dma_address[j - 1] + ttm_dma->dma_address[j] = ttm_dma->dma_address[j - 1] +
...@@ -996,8 +998,8 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev, ...@@ -996,8 +998,8 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev,
} }
while (num_pages) { while (num_pages) {
ret = ttm_dma_pool_get_pages(pool, ttm_dma, i); d_page = ttm_dma_pool_get_pages(pool, ttm_dma, i);
if (ret != 0) { if (!d_page) {
ttm_dma_unpopulate(ttm_dma, dev); ttm_dma_unpopulate(ttm_dma, dev);
return -ENOMEM; return -ENOMEM;
} }
...@@ -1009,6 +1011,7 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev, ...@@ -1009,6 +1011,7 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev,
return -ENOMEM; return -ENOMEM;
} }
d_page->vaddr |= VADDR_FLAG_UPDATED_COUNT;
++i; ++i;
--num_pages; --num_pages;
} }
...@@ -1049,8 +1052,11 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev) ...@@ -1049,8 +1052,11 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev)
continue; continue;
count++; count++;
ttm_mem_global_free_page(ttm->glob->mem_glob, if (d_page->vaddr & VADDR_FLAG_UPDATED_COUNT) {
d_page->p, pool->size); ttm_mem_global_free_page(ttm->glob->mem_glob,
d_page->p, pool->size);
d_page->vaddr &= ~VADDR_FLAG_UPDATED_COUNT;
}
ttm_dma_page_put(pool, d_page); ttm_dma_page_put(pool, d_page);
} }
...@@ -1070,9 +1076,19 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev) ...@@ -1070,9 +1076,19 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev)
/* make sure pages array match list and count number of pages */ /* make sure pages array match list and count number of pages */
count = 0; count = 0;
list_for_each_entry(d_page, &ttm_dma->pages_list, page_list) { list_for_each_entry_safe(d_page, next, &ttm_dma->pages_list,
page_list) {
ttm->pages[count] = d_page->p; ttm->pages[count] = d_page->p;
count++; count++;
if (d_page->vaddr & VADDR_FLAG_UPDATED_COUNT) {
ttm_mem_global_free_page(ttm->glob->mem_glob,
d_page->p, pool->size);
d_page->vaddr &= ~VADDR_FLAG_UPDATED_COUNT;
}
if (is_cached)
ttm_dma_page_put(pool, d_page);
} }
spin_lock_irqsave(&pool->lock, irq_flags); spin_lock_irqsave(&pool->lock, irq_flags);
...@@ -1092,19 +1108,6 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev) ...@@ -1092,19 +1108,6 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev)
} }
spin_unlock_irqrestore(&pool->lock, irq_flags); spin_unlock_irqrestore(&pool->lock, irq_flags);
if (is_cached) {
list_for_each_entry_safe(d_page, next, &ttm_dma->pages_list, page_list) {
ttm_mem_global_free_page(ttm->glob->mem_glob,
d_page->p, pool->size);
ttm_dma_page_put(pool, d_page);
}
} else {
for (i = 0; i < count; i++) {
ttm_mem_global_free_page(ttm->glob->mem_glob,
ttm->pages[i], pool->size);
}
}
INIT_LIST_HEAD(&ttm_dma->pages_list); INIT_LIST_HEAD(&ttm_dma->pages_list);
for (i = 0; i < ttm->num_pages; i++) { for (i = 0; i < ttm->num_pages; i++) {
ttm->pages[i] = NULL; ttm->pages[i] = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment