Commit 623dffb2 authored by Toshi Kani's avatar Toshi Kani Committed by Ingo Molnar

x86/mm/pat: Add set_memory_wt() for Write-Through type

Now that reserve_ram_pages_type() accepts the WT type, add
set_memory_wt(), set_memory_array_wt() and set_pages_array_wt()
in order to be able to set memory to Write-Through page cache
mode.

Also, extend ioremap_change_attr() to accept the WT type.
Signed-off-by: default avatarToshi Kani <toshi.kani@hp.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Elliott@hp.com
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Luis R. Rodriguez <mcgrof@suse.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: arnd@arndb.de
Cc: hch@lst.de
Cc: hmh@hmh.eng.br
Cc: jgross@suse.com
Cc: konrad.wilk@oracle.com
Cc: linux-mm <linux-mm@kvack.org>
Cc: linux-nvdimm@lists.01.org
Cc: stefan.bader@canonical.com
Cc: yigal@plexistor.com
Link: http://lkml.kernel.org/r/1433436928-31903-13-git-send-email-bp@alien8.deSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 35a5a104
...@@ -48,6 +48,9 @@ set_memory_uc | UC- | -- | -- | ...@@ -48,6 +48,9 @@ set_memory_uc | UC- | -- | -- |
set_memory_wc | WC | -- | -- | set_memory_wc | WC | -- | -- |
set_memory_wb | | | | set_memory_wb | | | |
| | | | | | | |
set_memory_wt | WT | -- | -- |
set_memory_wb | | | |
| | | |
pci sysfs resource | -- | -- | UC- | pci sysfs resource | -- | -- | UC- |
| | | | | | | |
pci sysfs resource_wc | -- | -- | WC | pci sysfs resource_wc | -- | -- | WC |
...@@ -150,8 +153,8 @@ can be more restrictive, in case of any existing aliasing for that address. ...@@ -150,8 +153,8 @@ can be more restrictive, in case of any existing aliasing for that address.
For example: If there is an existing uncached mapping, a new ioremap_wc can For example: If there is an existing uncached mapping, a new ioremap_wc can
return uncached mapping in place of write-combine requested. return uncached mapping in place of write-combine requested.
set_memory_[uc|wc] and set_memory_wb should be used in pairs, where driver will set_memory_[uc|wc|wt] and set_memory_wb should be used in pairs, where driver
first make a region uc or wc and switch it back to wb after use. will first make a region uc, wc or wt and switch it back to wb after use.
Over time writes to /proc/mtrr will be deprecated in favor of using PAT based Over time writes to /proc/mtrr will be deprecated in favor of using PAT based
interfaces. Users writing to /proc/mtrr are suggested to use above interfaces. interfaces. Users writing to /proc/mtrr are suggested to use above interfaces.
...@@ -159,7 +162,7 @@ interfaces. Users writing to /proc/mtrr are suggested to use above interfaces. ...@@ -159,7 +162,7 @@ interfaces. Users writing to /proc/mtrr are suggested to use above interfaces.
Drivers should use ioremap_[uc|wc] to access PCI BARs with [uc|wc] access Drivers should use ioremap_[uc|wc] to access PCI BARs with [uc|wc] access
types. types.
Drivers should use set_memory_[uc|wc] to set access type for RAM ranges. Drivers should use set_memory_[uc|wc|wt] to set access type for RAM ranges.
PAT debugging PAT debugging
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
/* /*
* The set_memory_* API can be used to change various attributes of a virtual * The set_memory_* API can be used to change various attributes of a virtual
* address range. The attributes include: * address range. The attributes include:
* Cachability : UnCached, WriteCombining, WriteBack * Cachability : UnCached, WriteCombining, WriteThrough, WriteBack
* Executability : eXeutable, NoteXecutable * Executability : eXeutable, NoteXecutable
* Read/Write : ReadOnly, ReadWrite * Read/Write : ReadOnly, ReadWrite
* Presence : NotPresent * Presence : NotPresent
...@@ -35,9 +35,11 @@ ...@@ -35,9 +35,11 @@
int _set_memory_uc(unsigned long addr, int numpages); int _set_memory_uc(unsigned long addr, int numpages);
int _set_memory_wc(unsigned long addr, int numpages); int _set_memory_wc(unsigned long addr, int numpages);
int _set_memory_wt(unsigned long addr, int numpages);
int _set_memory_wb(unsigned long addr, int numpages); int _set_memory_wb(unsigned long addr, int numpages);
int set_memory_uc(unsigned long addr, int numpages); int set_memory_uc(unsigned long addr, int numpages);
int set_memory_wc(unsigned long addr, int numpages); int set_memory_wc(unsigned long addr, int numpages);
int set_memory_wt(unsigned long addr, int numpages);
int set_memory_wb(unsigned long addr, int numpages); int set_memory_wb(unsigned long addr, int numpages);
int set_memory_x(unsigned long addr, int numpages); int set_memory_x(unsigned long addr, int numpages);
int set_memory_nx(unsigned long addr, int numpages); int set_memory_nx(unsigned long addr, int numpages);
...@@ -48,10 +50,12 @@ int set_memory_4k(unsigned long addr, int numpages); ...@@ -48,10 +50,12 @@ 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_wc(unsigned long *addr, int addrinarray);
int set_memory_array_wt(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_wc(struct page **pages, int addrinarray);
int set_pages_array_wt(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);
/* /*
......
...@@ -42,6 +42,9 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size, ...@@ -42,6 +42,9 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size,
case _PAGE_CACHE_MODE_WC: case _PAGE_CACHE_MODE_WC:
err = _set_memory_wc(vaddr, nrpages); err = _set_memory_wc(vaddr, nrpages);
break; break;
case _PAGE_CACHE_MODE_WT:
err = _set_memory_wt(vaddr, nrpages);
break;
case _PAGE_CACHE_MODE_WB: case _PAGE_CACHE_MODE_WB:
err = _set_memory_wb(vaddr, nrpages); err = _set_memory_wb(vaddr, nrpages);
break; break;
......
...@@ -1503,12 +1503,10 @@ EXPORT_SYMBOL(set_memory_uc); ...@@ -1503,12 +1503,10 @@ EXPORT_SYMBOL(set_memory_uc);
static int _set_memory_array(unsigned long *addr, int addrinarray, static int _set_memory_array(unsigned long *addr, int addrinarray,
enum page_cache_mode new_type) enum page_cache_mode new_type)
{ {
enum page_cache_mode set_type;
int i, j; int i, j;
int ret; int ret;
/*
* for now UC MINUS. see comments in ioremap_nocache()
*/
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,
new_type, NULL); new_type, NULL);
...@@ -1516,9 +1514,12 @@ static int _set_memory_array(unsigned long *addr, int addrinarray, ...@@ -1516,9 +1514,12 @@ static int _set_memory_array(unsigned long *addr, int addrinarray,
goto out_free; goto out_free;
} }
/* If WC, set to UC- first and then WC */
set_type = (new_type == _PAGE_CACHE_MODE_WC) ?
_PAGE_CACHE_MODE_UC_MINUS : new_type;
ret = change_page_attr_set(addr, addrinarray, ret = change_page_attr_set(addr, addrinarray,
cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS), cachemode2pgprot(set_type), 1);
1);
if (!ret && new_type == _PAGE_CACHE_MODE_WC) if (!ret && new_type == _PAGE_CACHE_MODE_WC)
ret = change_page_attr_set_clr(addr, addrinarray, ret = change_page_attr_set_clr(addr, addrinarray,
...@@ -1550,6 +1551,12 @@ int set_memory_array_wc(unsigned long *addr, int addrinarray) ...@@ -1550,6 +1551,12 @@ int set_memory_array_wc(unsigned long *addr, int addrinarray)
} }
EXPORT_SYMBOL(set_memory_array_wc); EXPORT_SYMBOL(set_memory_array_wc);
int set_memory_array_wt(unsigned long *addr, int addrinarray)
{
return _set_memory_array(addr, addrinarray, _PAGE_CACHE_MODE_WT);
}
EXPORT_SYMBOL_GPL(set_memory_array_wt);
int _set_memory_wc(unsigned long addr, int numpages) int _set_memory_wc(unsigned long addr, int numpages)
{ {
int ret; int ret;
...@@ -1575,21 +1582,39 @@ int set_memory_wc(unsigned long addr, int numpages) ...@@ -1575,21 +1582,39 @@ int set_memory_wc(unsigned long addr, int numpages)
ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE, ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
_PAGE_CACHE_MODE_WC, NULL); _PAGE_CACHE_MODE_WC, NULL);
if (ret) if (ret)
goto out_err; return ret;
ret = _set_memory_wc(addr, numpages); ret = _set_memory_wc(addr, numpages);
if (ret) if (ret)
goto out_free; free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE);
return 0;
out_free:
free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE);
out_err:
return ret; return ret;
} }
EXPORT_SYMBOL(set_memory_wc); EXPORT_SYMBOL(set_memory_wc);
int _set_memory_wt(unsigned long addr, int numpages)
{
return change_page_attr_set(&addr, numpages,
cachemode2pgprot(_PAGE_CACHE_MODE_WT), 0);
}
int set_memory_wt(unsigned long addr, int numpages)
{
int ret;
ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
_PAGE_CACHE_MODE_WT, NULL);
if (ret)
return ret;
ret = _set_memory_wt(addr, numpages);
if (ret)
free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE);
return ret;
}
EXPORT_SYMBOL_GPL(set_memory_wt);
int _set_memory_wb(unsigned long addr, int numpages) int _set_memory_wb(unsigned long addr, int numpages)
{ {
/* WB cache mode is hard wired to all cache attribute bits being 0 */ /* WB cache mode is hard wired to all cache attribute bits being 0 */
...@@ -1680,6 +1705,7 @@ static int _set_pages_array(struct page **pages, int addrinarray, ...@@ -1680,6 +1705,7 @@ static int _set_pages_array(struct page **pages, int addrinarray,
{ {
unsigned long start; unsigned long start;
unsigned long end; unsigned long end;
enum page_cache_mode set_type;
int i; int i;
int free_idx; int free_idx;
int ret; int ret;
...@@ -1693,8 +1719,12 @@ static int _set_pages_array(struct page **pages, int addrinarray, ...@@ -1693,8 +1719,12 @@ static int _set_pages_array(struct page **pages, int addrinarray,
goto err_out; goto err_out;
} }
/* If WC, set to UC- first and then WC */
set_type = (new_type == _PAGE_CACHE_MODE_WC) ?
_PAGE_CACHE_MODE_UC_MINUS : new_type;
ret = cpa_set_pages_array(pages, addrinarray, ret = cpa_set_pages_array(pages, addrinarray,
cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS)); cachemode2pgprot(set_type));
if (!ret && new_type == _PAGE_CACHE_MODE_WC) if (!ret && new_type == _PAGE_CACHE_MODE_WC)
ret = change_page_attr_set_clr(NULL, addrinarray, ret = change_page_attr_set_clr(NULL, addrinarray,
cachemode2pgprot( cachemode2pgprot(
...@@ -1728,6 +1758,12 @@ int set_pages_array_wc(struct page **pages, int addrinarray) ...@@ -1728,6 +1758,12 @@ int set_pages_array_wc(struct page **pages, int addrinarray)
} }
EXPORT_SYMBOL(set_pages_array_wc); EXPORT_SYMBOL(set_pages_array_wc);
int set_pages_array_wt(struct page **pages, int addrinarray)
{
return _set_pages_array(pages, addrinarray, _PAGE_CACHE_MODE_WT);
}
EXPORT_SYMBOL_GPL(set_pages_array_wt);
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