aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/pageattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/pageattr.c')
-rw-r--r--arch/x86/mm/pageattr.c84
1 files changed, 59 insertions, 25 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 89af288ec674..727158cb3b3c 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -14,6 +14,7 @@
14#include <linux/percpu.h> 14#include <linux/percpu.h>
15#include <linux/gfp.h> 15#include <linux/gfp.h>
16#include <linux/pci.h> 16#include <linux/pci.h>
17#include <linux/vmalloc.h>
17 18
18#include <asm/e820.h> 19#include <asm/e820.h>
19#include <asm/processor.h> 20#include <asm/processor.h>
@@ -129,16 +130,15 @@ within(unsigned long addr, unsigned long start, unsigned long end)
129 */ 130 */
130void clflush_cache_range(void *vaddr, unsigned int size) 131void clflush_cache_range(void *vaddr, unsigned int size)
131{ 132{
132 void *vend = vaddr + size - 1; 133 unsigned long clflush_mask = boot_cpu_data.x86_clflush_size - 1;
134 void *vend = vaddr + size;
135 void *p;
133 136
134 mb(); 137 mb();
135 138
136 for (; vaddr < vend; vaddr += boot_cpu_data.x86_clflush_size) 139 for (p = (void *)((unsigned long)vaddr & ~clflush_mask);
137 clflushopt(vaddr); 140 p < vend; p += boot_cpu_data.x86_clflush_size)
138 /* 141 clflushopt(p);
139 * Flush any possible final partial cacheline:
140 */
141 clflushopt(vend);
142 142
143 mb(); 143 mb();
144} 144}
@@ -418,13 +418,11 @@ phys_addr_t slow_virt_to_phys(void *__virt_addr)
418 phys_addr_t phys_addr; 418 phys_addr_t phys_addr;
419 unsigned long offset; 419 unsigned long offset;
420 enum pg_level level; 420 enum pg_level level;
421 unsigned long psize;
422 unsigned long pmask; 421 unsigned long pmask;
423 pte_t *pte; 422 pte_t *pte;
424 423
425 pte = lookup_address(virt_addr, &level); 424 pte = lookup_address(virt_addr, &level);
426 BUG_ON(!pte); 425 BUG_ON(!pte);
427 psize = page_level_size(level);
428 pmask = page_level_mask(level); 426 pmask = page_level_mask(level);
429 offset = virt_addr & ~pmask; 427 offset = virt_addr & ~pmask;
430 phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT; 428 phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT;
@@ -1468,6 +1466,9 @@ int _set_memory_uc(unsigned long addr, int numpages)
1468{ 1466{
1469 /* 1467 /*
1470 * for now UC MINUS. see comments in ioremap_nocache() 1468 * for now UC MINUS. see comments in ioremap_nocache()
1469 * If you really need strong UC use ioremap_uc(), but note
1470 * that you cannot override IO areas with set_memory_*() as
1471 * these helpers cannot work with IO memory.
1471 */ 1472 */
1472 return change_page_attr_set(&addr, numpages, 1473 return change_page_attr_set(&addr, numpages,
1473 cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS), 1474 cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS),
@@ -1502,12 +1503,10 @@ EXPORT_SYMBOL(set_memory_uc);
1502static int _set_memory_array(unsigned long *addr, int addrinarray, 1503static int _set_memory_array(unsigned long *addr, int addrinarray,
1503 enum page_cache_mode new_type) 1504 enum page_cache_mode new_type)
1504{ 1505{
1506 enum page_cache_mode set_type;
1505 int i, j; 1507 int i, j;
1506 int ret; 1508 int ret;
1507 1509
1508 /*
1509 * for now UC MINUS. see comments in ioremap_nocache()
1510 */
1511 for (i = 0; i < addrinarray; i++) { 1510 for (i = 0; i < addrinarray; i++) {
1512 ret = reserve_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE, 1511 ret = reserve_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE,
1513 new_type, NULL); 1512 new_type, NULL);
@@ -1515,9 +1514,12 @@ static int _set_memory_array(unsigned long *addr, int addrinarray,
1515 goto out_free; 1514 goto out_free;
1516 } 1515 }
1517 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
1518 ret = change_page_attr_set(addr, addrinarray, 1521 ret = change_page_attr_set(addr, addrinarray,
1519 cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS), 1522 cachemode2pgprot(set_type), 1);
1520 1);
1521 1523
1522 if (!ret && new_type == _PAGE_CACHE_MODE_WC) 1524 if (!ret && new_type == _PAGE_CACHE_MODE_WC)
1523 ret = change_page_attr_set_clr(addr, addrinarray, 1525 ret = change_page_attr_set_clr(addr, addrinarray,
@@ -1549,6 +1551,12 @@ int set_memory_array_wc(unsigned long *addr, int addrinarray)
1549} 1551}
1550EXPORT_SYMBOL(set_memory_array_wc); 1552EXPORT_SYMBOL(set_memory_array_wc);
1551 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
1552int _set_memory_wc(unsigned long addr, int numpages) 1560int _set_memory_wc(unsigned long addr, int numpages)
1553{ 1561{
1554 int ret; 1562 int ret;
@@ -1571,27 +1579,42 @@ int set_memory_wc(unsigned long addr, int numpages)
1571{ 1579{
1572 int ret; 1580 int ret;
1573 1581
1574 if (!pat_enabled)
1575 return set_memory_uc(addr, numpages);
1576
1577 ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE, 1582 ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
1578 _PAGE_CACHE_MODE_WC, NULL); 1583 _PAGE_CACHE_MODE_WC, NULL);
1579 if (ret) 1584 if (ret)
1580 goto out_err; 1585 return ret;
1581 1586
1582 ret = _set_memory_wc(addr, numpages); 1587 ret = _set_memory_wc(addr, numpages);
1583 if (ret) 1588 if (ret)
1584 goto out_free; 1589 free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE);
1585
1586 return 0;
1587 1590
1588out_free:
1589 free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE);
1590out_err:
1591 return ret; 1591 return ret;
1592} 1592}
1593EXPORT_SYMBOL(set_memory_wc); 1593EXPORT_SYMBOL(set_memory_wc);
1594 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
1595int _set_memory_wb(unsigned long addr, int numpages) 1618int _set_memory_wb(unsigned long addr, int numpages)
1596{ 1619{
1597 /* 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 */
@@ -1682,6 +1705,7 @@ static int _set_pages_array(struct page **pages, int addrinarray,
1682{ 1705{
1683 unsigned long start; 1706 unsigned long start;
1684 unsigned long end; 1707 unsigned long end;
1708 enum page_cache_mode set_type;
1685 int i; 1709 int i;
1686 int free_idx; 1710 int free_idx;
1687 int ret; 1711 int ret;
@@ -1695,8 +1719,12 @@ static int _set_pages_array(struct page **pages, int addrinarray,
1695 goto err_out; 1719 goto err_out;
1696 } 1720 }
1697 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
1698 ret = cpa_set_pages_array(pages, addrinarray, 1726 ret = cpa_set_pages_array(pages, addrinarray,
1699 cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS)); 1727 cachemode2pgprot(set_type));
1700 if (!ret && new_type == _PAGE_CACHE_MODE_WC) 1728 if (!ret && new_type == _PAGE_CACHE_MODE_WC)
1701 ret = change_page_attr_set_clr(NULL, addrinarray, 1729 ret = change_page_attr_set_clr(NULL, addrinarray,
1702 cachemode2pgprot( 1730 cachemode2pgprot(
@@ -1730,6 +1758,12 @@ int set_pages_array_wc(struct page **pages, int addrinarray)
1730} 1758}
1731EXPORT_SYMBOL(set_pages_array_wc); 1759EXPORT_SYMBOL(set_pages_array_wc);
1732 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
1733int set_pages_wb(struct page *page, int numpages) 1767int set_pages_wb(struct page *page, int numpages)
1734{ 1768{
1735 unsigned long addr = (unsigned long)page_address(page); 1769 unsigned long addr = (unsigned long)page_address(page);