diff options
Diffstat (limited to 'arch/x86/mm/pageattr.c')
-rw-r--r-- | arch/x86/mm/pageattr.c | 84 |
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 | */ |
130 | void clflush_cache_range(void *vaddr, unsigned int size) | 131 | void 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); | |||
1502 | static int _set_memory_array(unsigned long *addr, int addrinarray, | 1503 | static 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 | } |
1550 | EXPORT_SYMBOL(set_memory_array_wc); | 1552 | EXPORT_SYMBOL(set_memory_array_wc); |
1551 | 1553 | ||
1554 | int set_memory_array_wt(unsigned long *addr, int addrinarray) | ||
1555 | { | ||
1556 | return _set_memory_array(addr, addrinarray, _PAGE_CACHE_MODE_WT); | ||
1557 | } | ||
1558 | EXPORT_SYMBOL_GPL(set_memory_array_wt); | ||
1559 | |||
1552 | int _set_memory_wc(unsigned long addr, int numpages) | 1560 | int _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 | ||
1588 | out_free: | ||
1589 | free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE); | ||
1590 | out_err: | ||
1591 | return ret; | 1591 | return ret; |
1592 | } | 1592 | } |
1593 | EXPORT_SYMBOL(set_memory_wc); | 1593 | EXPORT_SYMBOL(set_memory_wc); |
1594 | 1594 | ||
1595 | int _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 | |||
1601 | int 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 | } | ||
1616 | EXPORT_SYMBOL_GPL(set_memory_wt); | ||
1617 | |||
1595 | int _set_memory_wb(unsigned long addr, int numpages) | 1618 | int _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 | } |
1731 | EXPORT_SYMBOL(set_pages_array_wc); | 1759 | EXPORT_SYMBOL(set_pages_array_wc); |
1732 | 1760 | ||
1761 | int set_pages_array_wt(struct page **pages, int addrinarray) | ||
1762 | { | ||
1763 | return _set_pages_array(pages, addrinarray, _PAGE_CACHE_MODE_WT); | ||
1764 | } | ||
1765 | EXPORT_SYMBOL_GPL(set_pages_array_wt); | ||
1766 | |||
1733 | int set_pages_wb(struct page *page, int numpages) | 1767 | int 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); |