diff options
| -rw-r--r-- | Documentation/x86/pat.txt | 9 | ||||
| -rw-r--r-- | arch/x86/include/asm/cacheflush.h | 6 | ||||
| -rw-r--r-- | arch/x86/mm/ioremap.c | 3 | ||||
| -rw-r--r-- | arch/x86/mm/pageattr.c | 62 |
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- | -- | -- | | |||
| 48 | set_memory_wc | WC | -- | -- | | 48 | set_memory_wc | WC | -- | -- | |
| 49 | set_memory_wb | | | | | 49 | set_memory_wb | | | | |
| 50 | | | | | | 50 | | | | | |
| 51 | set_memory_wt | WT | -- | -- | | ||
| 52 | set_memory_wb | | | | | ||
| 53 | | | | | | ||
| 51 | pci sysfs resource | -- | -- | UC- | | 54 | pci sysfs resource | -- | -- | UC- | |
| 52 | | | | | | 55 | | | | | |
| 53 | pci sysfs resource_wc | -- | -- | WC | | 56 | pci sysfs resource_wc | -- | -- | WC | |
| @@ -150,8 +153,8 @@ can be more restrictive, in case of any existing aliasing for that address. | |||
| 150 | For example: If there is an existing uncached mapping, a new ioremap_wc can | 153 | For example: If there is an existing uncached mapping, a new ioremap_wc can |
| 151 | return uncached mapping in place of write-combine requested. | 154 | return uncached mapping in place of write-combine requested. |
| 152 | 155 | ||
| 153 | set_memory_[uc|wc] and set_memory_wb should be used in pairs, where driver will | 156 | set_memory_[uc|wc|wt] and set_memory_wb should be used in pairs, where driver |
| 154 | first make a region uc or wc and switch it back to wb after use. | 157 | will first make a region uc, wc or wt and switch it back to wb after use. |
| 155 | 158 | ||
| 156 | Over time writes to /proc/mtrr will be deprecated in favor of using PAT based | 159 | Over time writes to /proc/mtrr will be deprecated in favor of using PAT based |
| 157 | interfaces. Users writing to /proc/mtrr are suggested to use above interfaces. | 160 | 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 | Drivers should use ioremap_[uc|wc] to access PCI BARs with [uc|wc] access | 162 | Drivers should use ioremap_[uc|wc] to access PCI BARs with [uc|wc] access |
| 160 | types. | 163 | types. |
| 161 | 164 | ||
| 162 | Drivers should use set_memory_[uc|wc] to set access type for RAM ranges. | 165 | Drivers should use set_memory_[uc|wc|wt] to set access type for RAM ranges. |
| 163 | 166 | ||
| 164 | 167 | ||
| 165 | PAT debugging | 168 | PAT 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 | ||
| 36 | int _set_memory_uc(unsigned long addr, int numpages); | 36 | int _set_memory_uc(unsigned long addr, int numpages); |
| 37 | int _set_memory_wc(unsigned long addr, int numpages); | 37 | int _set_memory_wc(unsigned long addr, int numpages); |
| 38 | int _set_memory_wt(unsigned long addr, int numpages); | ||
| 38 | int _set_memory_wb(unsigned long addr, int numpages); | 39 | int _set_memory_wb(unsigned long addr, int numpages); |
| 39 | int set_memory_uc(unsigned long addr, int numpages); | 40 | int set_memory_uc(unsigned long addr, int numpages); |
| 40 | int set_memory_wc(unsigned long addr, int numpages); | 41 | int set_memory_wc(unsigned long addr, int numpages); |
| 42 | int set_memory_wt(unsigned long addr, int numpages); | ||
| 41 | int set_memory_wb(unsigned long addr, int numpages); | 43 | int set_memory_wb(unsigned long addr, int numpages); |
| 42 | int set_memory_x(unsigned long addr, int numpages); | 44 | int set_memory_x(unsigned long addr, int numpages); |
| 43 | int set_memory_nx(unsigned long addr, int numpages); | 45 | int set_memory_nx(unsigned long addr, int numpages); |
| @@ -48,10 +50,12 @@ int set_memory_4k(unsigned long addr, int numpages); | |||
| 48 | 50 | ||
| 49 | int set_memory_array_uc(unsigned long *addr, int addrinarray); | 51 | int set_memory_array_uc(unsigned long *addr, int addrinarray); |
| 50 | int set_memory_array_wc(unsigned long *addr, int addrinarray); | 52 | int set_memory_array_wc(unsigned long *addr, int addrinarray); |
| 53 | int set_memory_array_wt(unsigned long *addr, int addrinarray); | ||
| 51 | int set_memory_array_wb(unsigned long *addr, int addrinarray); | 54 | int set_memory_array_wb(unsigned long *addr, int addrinarray); |
| 52 | 55 | ||
| 53 | int set_pages_array_uc(struct page **pages, int addrinarray); | 56 | int set_pages_array_uc(struct page **pages, int addrinarray); |
| 54 | int set_pages_array_wc(struct page **pages, int addrinarray); | 57 | int set_pages_array_wc(struct page **pages, int addrinarray); |
| 58 | int set_pages_array_wt(struct page **pages, int addrinarray); | ||
| 55 | int set_pages_array_wb(struct page **pages, int addrinarray); | 59 | int 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); | |||
| 1503 | static int _set_memory_array(unsigned long *addr, int addrinarray, | 1503 | static 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 | } |
| 1551 | EXPORT_SYMBOL(set_memory_array_wc); | 1552 | EXPORT_SYMBOL(set_memory_array_wc); |
| 1552 | 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 | |||
| 1553 | int _set_memory_wc(unsigned long addr, int numpages) | 1560 | int _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 | |||
| 1586 | out_free: | ||
| 1587 | free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE); | ||
| 1588 | out_err: | ||
| 1589 | return ret; | 1591 | return ret; |
| 1590 | } | 1592 | } |
| 1591 | EXPORT_SYMBOL(set_memory_wc); | 1593 | EXPORT_SYMBOL(set_memory_wc); |
| 1592 | 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 | |||
| 1593 | int _set_memory_wb(unsigned long addr, int numpages) | 1618 | int _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 | } |
| 1729 | EXPORT_SYMBOL(set_pages_array_wc); | 1759 | EXPORT_SYMBOL(set_pages_array_wc); |
| 1730 | 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 | |||
| 1731 | int set_pages_wb(struct page *page, int numpages) | 1767 | int 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); |
