aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/x86/pat.txt9
-rw-r--r--arch/x86/include/asm/cacheflush.h6
-rw-r--r--arch/x86/mm/ioremap.c3
-rw-r--r--arch/x86/mm/pageattr.c62
4 files changed, 63 insertions, 17 deletions
diff --git a/Documentation/x86/pat.txt b/Documentation/x86/pat.txt
index db0de6cfc351..54944c71b819 100644
--- a/Documentation/x86/pat.txt
+++ b/Documentation/x86/pat.txt
@@ -48,6 +48,9 @@ set_memory_uc | UC- | -- | -- |
48set_memory_wc | WC | -- | -- | 48set_memory_wc | WC | -- | -- |
49 set_memory_wb | | | | 49 set_memory_wb | | | |
50 | | | | 50 | | | |
51set_memory_wt | WT | -- | -- |
52 set_memory_wb | | | |
53 | | | |
51pci sysfs resource | -- | -- | UC- | 54pci sysfs resource | -- | -- | UC- |
52 | | | | 55 | | | |
53pci sysfs resource_wc | -- | -- | WC | 56pci sysfs resource_wc | -- | -- | WC |
@@ -150,8 +153,8 @@ can be more restrictive, in case of any existing aliasing for that address.
150For example: If there is an existing uncached mapping, a new ioremap_wc can 153For example: If there is an existing uncached mapping, a new ioremap_wc can
151return uncached mapping in place of write-combine requested. 154return uncached mapping in place of write-combine requested.
152 155
153set_memory_[uc|wc] and set_memory_wb should be used in pairs, where driver will 156set_memory_[uc|wc|wt] and set_memory_wb should be used in pairs, where driver
154first make a region uc or wc and switch it back to wb after use. 157will first make a region uc, wc or wt and switch it back to wb after use.
155 158
156Over time writes to /proc/mtrr will be deprecated in favor of using PAT based 159Over time writes to /proc/mtrr will be deprecated in favor of using PAT based
157interfaces. Users writing to /proc/mtrr are suggested to use above interfaces. 160interfaces. 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.
159Drivers should use ioremap_[uc|wc] to access PCI BARs with [uc|wc] access 162Drivers should use ioremap_[uc|wc] to access PCI BARs with [uc|wc] access
160types. 163types.
161 164
162Drivers should use set_memory_[uc|wc] to set access type for RAM ranges. 165Drivers should use set_memory_[uc|wc|wt] to set access type for RAM ranges.
163 166
164 167
165PAT debugging 168PAT debugging
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h
index 47c8e32f621a..b6f7457d12e4 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -8,7 +8,7 @@
8/* 8/*
9 * The set_memory_* API can be used to change various attributes of a virtual 9 * The set_memory_* API can be used to change various attributes of a virtual
10 * address range. The attributes include: 10 * address range. The attributes include:
11 * Cachability : UnCached, WriteCombining, WriteBack 11 * Cachability : UnCached, WriteCombining, WriteThrough, WriteBack
12 * Executability : eXeutable, NoteXecutable 12 * Executability : eXeutable, NoteXecutable
13 * Read/Write : ReadOnly, ReadWrite 13 * Read/Write : ReadOnly, ReadWrite
14 * Presence : NotPresent 14 * Presence : NotPresent
@@ -35,9 +35,11 @@
35 35
36int _set_memory_uc(unsigned long addr, int numpages); 36int _set_memory_uc(unsigned long addr, int numpages);
37int _set_memory_wc(unsigned long addr, int numpages); 37int _set_memory_wc(unsigned long addr, int numpages);
38int _set_memory_wt(unsigned long addr, int numpages);
38int _set_memory_wb(unsigned long addr, int numpages); 39int _set_memory_wb(unsigned long addr, int numpages);
39int set_memory_uc(unsigned long addr, int numpages); 40int set_memory_uc(unsigned long addr, int numpages);
40int set_memory_wc(unsigned long addr, int numpages); 41int set_memory_wc(unsigned long addr, int numpages);
42int set_memory_wt(unsigned long addr, int numpages);
41int set_memory_wb(unsigned long addr, int numpages); 43int set_memory_wb(unsigned long addr, int numpages);
42int set_memory_x(unsigned long addr, int numpages); 44int set_memory_x(unsigned long addr, int numpages);
43int set_memory_nx(unsigned long addr, int numpages); 45int set_memory_nx(unsigned long addr, int numpages);
@@ -48,10 +50,12 @@ int set_memory_4k(unsigned long addr, int numpages);
48 50
49int set_memory_array_uc(unsigned long *addr, int addrinarray); 51int set_memory_array_uc(unsigned long *addr, int addrinarray);
50int set_memory_array_wc(unsigned long *addr, int addrinarray); 52int set_memory_array_wc(unsigned long *addr, int addrinarray);
53int set_memory_array_wt(unsigned long *addr, int addrinarray);
51int set_memory_array_wb(unsigned long *addr, int addrinarray); 54int set_memory_array_wb(unsigned long *addr, int addrinarray);
52 55
53int set_pages_array_uc(struct page **pages, int addrinarray); 56int set_pages_array_uc(struct page **pages, int addrinarray);
54int set_pages_array_wc(struct page **pages, int addrinarray); 57int set_pages_array_wc(struct page **pages, int addrinarray);
58int set_pages_array_wt(struct page **pages, int addrinarray);
55int set_pages_array_wb(struct page **pages, int addrinarray); 59int set_pages_array_wb(struct page **pages, int addrinarray);
56 60
57/* 61/*
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 07cd46a8f30a..8405c0c6a535 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -42,6 +42,9 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size,
42 case _PAGE_CACHE_MODE_WC: 42 case _PAGE_CACHE_MODE_WC:
43 err = _set_memory_wc(vaddr, nrpages); 43 err = _set_memory_wc(vaddr, nrpages);
44 break; 44 break;
45 case _PAGE_CACHE_MODE_WT:
46 err = _set_memory_wt(vaddr, nrpages);
47 break;
45 case _PAGE_CACHE_MODE_WB: 48 case _PAGE_CACHE_MODE_WB:
46 err = _set_memory_wb(vaddr, nrpages); 49 err = _set_memory_wb(vaddr, nrpages);
47 break; 50 break;
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 31b4f3fd1207..727158cb3b3c 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -1503,12 +1503,10 @@ EXPORT_SYMBOL(set_memory_uc);
1503static int _set_memory_array(unsigned long *addr, int addrinarray, 1503static int _set_memory_array(unsigned long *addr, int addrinarray,
1504 enum page_cache_mode new_type) 1504 enum page_cache_mode new_type)
1505{ 1505{
1506 enum page_cache_mode set_type;
1506 int i, j; 1507 int i, j;
1507 int ret; 1508 int ret;
1508 1509
1509 /*
1510 * for now UC MINUS. see comments in ioremap_nocache()
1511 */
1512 for (i = 0; i < addrinarray; i++) { 1510 for (i = 0; i < addrinarray; i++) {
1513 ret = reserve_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE, 1511 ret = reserve_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE,
1514 new_type, NULL); 1512 new_type, NULL);
@@ -1516,9 +1514,12 @@ static int _set_memory_array(unsigned long *addr, int addrinarray,
1516 goto out_free; 1514 goto out_free;
1517 } 1515 }
1518 1516
1517 /* If WC, set to UC- first and then WC */
1518 set_type = (new_type == _PAGE_CACHE_MODE_WC) ?
1519 _PAGE_CACHE_MODE_UC_MINUS : new_type;
1520
1519 ret = change_page_attr_set(addr, addrinarray, 1521 ret = change_page_attr_set(addr, addrinarray,
1520 cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS), 1522 cachemode2pgprot(set_type), 1);
1521 1);
1522 1523
1523 if (!ret && new_type == _PAGE_CACHE_MODE_WC) 1524 if (!ret && new_type == _PAGE_CACHE_MODE_WC)
1524 ret = change_page_attr_set_clr(addr, addrinarray, 1525 ret = change_page_attr_set_clr(addr, addrinarray,
@@ -1550,6 +1551,12 @@ int set_memory_array_wc(unsigned long *addr, int addrinarray)
1550} 1551}
1551EXPORT_SYMBOL(set_memory_array_wc); 1552EXPORT_SYMBOL(set_memory_array_wc);
1552 1553
1554int set_memory_array_wt(unsigned long *addr, int addrinarray)
1555{
1556 return _set_memory_array(addr, addrinarray, _PAGE_CACHE_MODE_WT);
1557}
1558EXPORT_SYMBOL_GPL(set_memory_array_wt);
1559
1553int _set_memory_wc(unsigned long addr, int numpages) 1560int _set_memory_wc(unsigned long addr, int numpages)
1554{ 1561{
1555 int ret; 1562 int ret;
@@ -1575,21 +1582,39 @@ int set_memory_wc(unsigned long addr, int numpages)
1575 ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE, 1582 ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
1576 _PAGE_CACHE_MODE_WC, NULL); 1583 _PAGE_CACHE_MODE_WC, NULL);
1577 if (ret) 1584 if (ret)
1578 goto out_err; 1585 return ret;
1579 1586
1580 ret = _set_memory_wc(addr, numpages); 1587 ret = _set_memory_wc(addr, numpages);
1581 if (ret) 1588 if (ret)
1582 goto out_free; 1589 free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE);
1583 1590
1584 return 0;
1585
1586out_free:
1587 free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE);
1588out_err:
1589 return ret; 1591 return ret;
1590} 1592}
1591EXPORT_SYMBOL(set_memory_wc); 1593EXPORT_SYMBOL(set_memory_wc);
1592 1594
1595int _set_memory_wt(unsigned long addr, int numpages)
1596{
1597 return change_page_attr_set(&addr, numpages,
1598 cachemode2pgprot(_PAGE_CACHE_MODE_WT), 0);
1599}
1600
1601int set_memory_wt(unsigned long addr, int numpages)
1602{
1603 int ret;
1604
1605 ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
1606 _PAGE_CACHE_MODE_WT, NULL);
1607 if (ret)
1608 return ret;
1609
1610 ret = _set_memory_wt(addr, numpages);
1611 if (ret)
1612 free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE);
1613
1614 return ret;
1615}
1616EXPORT_SYMBOL_GPL(set_memory_wt);
1617
1593int _set_memory_wb(unsigned long addr, int numpages) 1618int _set_memory_wb(unsigned long addr, int numpages)
1594{ 1619{
1595 /* WB cache mode is hard wired to all cache attribute bits being 0 */ 1620 /* 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{ 1705{
1681 unsigned long start; 1706 unsigned long start;
1682 unsigned long end; 1707 unsigned long end;
1708 enum page_cache_mode set_type;
1683 int i; 1709 int i;
1684 int free_idx; 1710 int free_idx;
1685 int ret; 1711 int ret;
@@ -1693,8 +1719,12 @@ static int _set_pages_array(struct page **pages, int addrinarray,
1693 goto err_out; 1719 goto err_out;
1694 } 1720 }
1695 1721
1722 /* If WC, set to UC- first and then WC */
1723 set_type = (new_type == _PAGE_CACHE_MODE_WC) ?
1724 _PAGE_CACHE_MODE_UC_MINUS : new_type;
1725
1696 ret = cpa_set_pages_array(pages, addrinarray, 1726 ret = cpa_set_pages_array(pages, addrinarray,
1697 cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS)); 1727 cachemode2pgprot(set_type));
1698 if (!ret && new_type == _PAGE_CACHE_MODE_WC) 1728 if (!ret && new_type == _PAGE_CACHE_MODE_WC)
1699 ret = change_page_attr_set_clr(NULL, addrinarray, 1729 ret = change_page_attr_set_clr(NULL, addrinarray,
1700 cachemode2pgprot( 1730 cachemode2pgprot(
@@ -1728,6 +1758,12 @@ int set_pages_array_wc(struct page **pages, int addrinarray)
1728} 1758}
1729EXPORT_SYMBOL(set_pages_array_wc); 1759EXPORT_SYMBOL(set_pages_array_wc);
1730 1760
1761int set_pages_array_wt(struct page **pages, int addrinarray)
1762{
1763 return _set_pages_array(pages, addrinarray, _PAGE_CACHE_MODE_WT);
1764}
1765EXPORT_SYMBOL_GPL(set_pages_array_wt);
1766
1731int set_pages_wb(struct page *page, int numpages) 1767int set_pages_wb(struct page *page, int numpages)
1732{ 1768{
1733 unsigned long addr = (unsigned long)page_address(page); 1769 unsigned long addr = (unsigned long)page_address(page);