Commit 4f646254 authored by Pauli Nieminen's avatar Pauli Nieminen Committed by Dave Airlie

arch/x86: Add array variants for setting memory to wc caching.

Setting single memory pages at a time to wc takes a lot time in cache flush. To
reduce number of cache flush set_pages_array_wc and set_memory_array_wc can be
used to set multiple pages to WC with single cache flush.

This improves allocation performance for wc cached pages in drm/ttm.

CC: Suresh Siddha <suresh.b.siddha@intel.com>
CC: Venkatesh Pallipadi <venkatesh.pallipadi@gmail.com>
Signed-off-by: default avatarPauli Nieminen <suokkos@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent bf62acde
...@@ -139,9 +139,11 @@ int set_memory_np(unsigned long addr, int numpages); ...@@ -139,9 +139,11 @@ int set_memory_np(unsigned long addr, int numpages);
int set_memory_4k(unsigned long addr, int numpages); int set_memory_4k(unsigned long addr, int numpages);
int set_memory_array_uc(unsigned long *addr, int addrinarray); int set_memory_array_uc(unsigned long *addr, int addrinarray);
int set_memory_array_wc(unsigned long *addr, int addrinarray);
int set_memory_array_wb(unsigned long *addr, int addrinarray); int set_memory_array_wb(unsigned long *addr, int addrinarray);
int set_pages_array_uc(struct page **pages, int addrinarray); int set_pages_array_uc(struct page **pages, int addrinarray);
int set_pages_array_wc(struct page **pages, int addrinarray);
int set_pages_array_wb(struct page **pages, int addrinarray); int set_pages_array_wb(struct page **pages, int addrinarray);
/* /*
......
...@@ -997,7 +997,8 @@ int set_memory_uc(unsigned long addr, int numpages) ...@@ -997,7 +997,8 @@ int set_memory_uc(unsigned long addr, int numpages)
} }
EXPORT_SYMBOL(set_memory_uc); EXPORT_SYMBOL(set_memory_uc);
int set_memory_array_uc(unsigned long *addr, int addrinarray) int _set_memory_array(unsigned long *addr, int addrinarray,
unsigned long new_type)
{ {
int i, j; int i, j;
int ret; int ret;
...@@ -1007,13 +1008,19 @@ int set_memory_array_uc(unsigned long *addr, int addrinarray) ...@@ -1007,13 +1008,19 @@ int set_memory_array_uc(unsigned long *addr, int addrinarray)
*/ */
for (i = 0; i < addrinarray; i++) { for (i = 0; i < addrinarray; i++) {
ret = reserve_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE, ret = reserve_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE,
_PAGE_CACHE_UC_MINUS, NULL); new_type, NULL);
if (ret) if (ret)
goto out_free; goto out_free;
} }
ret = change_page_attr_set(addr, addrinarray, ret = change_page_attr_set(addr, addrinarray,
__pgprot(_PAGE_CACHE_UC_MINUS), 1); __pgprot(_PAGE_CACHE_UC_MINUS), 1);
if (!ret && new_type == _PAGE_CACHE_WC)
ret = change_page_attr_set_clr(addr, addrinarray,
__pgprot(_PAGE_CACHE_WC),
__pgprot(_PAGE_CACHE_MASK),
0, CPA_ARRAY, NULL);
if (ret) if (ret)
goto out_free; goto out_free;
...@@ -1025,8 +1032,19 @@ int set_memory_array_uc(unsigned long *addr, int addrinarray) ...@@ -1025,8 +1032,19 @@ int set_memory_array_uc(unsigned long *addr, int addrinarray)
return ret; return ret;
} }
int set_memory_array_uc(unsigned long *addr, int addrinarray)
{
return _set_memory_array(addr, addrinarray, _PAGE_CACHE_UC_MINUS);
}
EXPORT_SYMBOL(set_memory_array_uc); EXPORT_SYMBOL(set_memory_array_uc);
int set_memory_array_wc(unsigned long *addr, int addrinarray)
{
return _set_memory_array(addr, addrinarray, _PAGE_CACHE_WC);
}
EXPORT_SYMBOL(set_memory_array_wc);
int _set_memory_wc(unsigned long addr, int numpages) int _set_memory_wc(unsigned long addr, int numpages)
{ {
int ret; int ret;
...@@ -1153,26 +1171,34 @@ int set_pages_uc(struct page *page, int numpages) ...@@ -1153,26 +1171,34 @@ int set_pages_uc(struct page *page, int numpages)
} }
EXPORT_SYMBOL(set_pages_uc); EXPORT_SYMBOL(set_pages_uc);
int set_pages_array_uc(struct page **pages, int addrinarray) static int _set_pages_array(struct page **pages, int addrinarray,
unsigned long new_type)
{ {
unsigned long start; unsigned long start;
unsigned long end; unsigned long end;
int i; int i;
int free_idx; int free_idx;
int ret;
for (i = 0; i < addrinarray; i++) { for (i = 0; i < addrinarray; i++) {
if (PageHighMem(pages[i])) if (PageHighMem(pages[i]))
continue; continue;
start = page_to_pfn(pages[i]) << PAGE_SHIFT; start = page_to_pfn(pages[i]) << PAGE_SHIFT;
end = start + PAGE_SIZE; end = start + PAGE_SIZE;
if (reserve_memtype(start, end, _PAGE_CACHE_UC_MINUS, NULL)) if (reserve_memtype(start, end, new_type, NULL))
goto err_out; goto err_out;
} }
if (cpa_set_pages_array(pages, addrinarray, ret = cpa_set_pages_array(pages, addrinarray,
__pgprot(_PAGE_CACHE_UC_MINUS)) == 0) { __pgprot(_PAGE_CACHE_UC_MINUS));
return 0; /* Success */ if (!ret && new_type == _PAGE_CACHE_WC)
} ret = change_page_attr_set_clr(NULL, addrinarray,
__pgprot(_PAGE_CACHE_WC),
__pgprot(_PAGE_CACHE_MASK),
0, CPA_PAGES_ARRAY, pages);
if (ret)
goto err_out;
return 0; /* Success */
err_out: err_out:
free_idx = i; free_idx = i;
for (i = 0; i < free_idx; i++) { for (i = 0; i < free_idx; i++) {
...@@ -1184,8 +1210,19 @@ int set_pages_array_uc(struct page **pages, int addrinarray) ...@@ -1184,8 +1210,19 @@ int set_pages_array_uc(struct page **pages, int addrinarray)
} }
return -EINVAL; return -EINVAL;
} }
int set_pages_array_uc(struct page **pages, int addrinarray)
{
return _set_pages_array(pages, addrinarray, _PAGE_CACHE_UC_MINUS);
}
EXPORT_SYMBOL(set_pages_array_uc); EXPORT_SYMBOL(set_pages_array_uc);
int set_pages_array_wc(struct page **pages, int addrinarray)
{
return _set_pages_array(pages, addrinarray, _PAGE_CACHE_WC);
}
EXPORT_SYMBOL(set_pages_array_wc);
int set_pages_wb(struct page *page, int numpages) int set_pages_wb(struct page *page, int numpages)
{ {
unsigned long addr = (unsigned long)page_address(page); unsigned long addr = (unsigned long)page_address(page);
......
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