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 @@  #include <linux/percpu.h>  #include <linux/gfp.h>  #include <linux/pci.h> +#include <linux/vmalloc.h>  #include <asm/e820.h>  #include <asm/processor.h> @@ -129,16 +130,15 @@ within(unsigned long addr, unsigned long start, unsigned long end)   */  void clflush_cache_range(void *vaddr, unsigned int size)  { -	void *vend = vaddr + size - 1; +	unsigned long clflush_mask = boot_cpu_data.x86_clflush_size - 1; +	void *vend = vaddr + size; +	void *p;  	mb(); -	for (; vaddr < vend; vaddr += boot_cpu_data.x86_clflush_size) -		clflushopt(vaddr); -	/* -	 * Flush any possible final partial cacheline: -	 */ -	clflushopt(vend); +	for (p = (void *)((unsigned long)vaddr & ~clflush_mask); +	     p < vend; p += boot_cpu_data.x86_clflush_size) +		clflushopt(p);  	mb();  } @@ -418,13 +418,11 @@ phys_addr_t slow_virt_to_phys(void *__virt_addr)  	phys_addr_t phys_addr;  	unsigned long offset;  	enum pg_level level; -	unsigned long psize;  	unsigned long pmask;  	pte_t *pte;  	pte = lookup_address(virt_addr, &level);  	BUG_ON(!pte); -	psize = page_level_size(level);  	pmask = page_level_mask(level);  	offset = virt_addr & ~pmask;  	phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT; @@ -1468,6 +1466,9 @@ int _set_memory_uc(unsigned long addr, int numpages)  {  	/*  	 * for now UC MINUS. see comments in ioremap_nocache() +	 * If you really need strong UC use ioremap_uc(), but note +	 * that you cannot override IO areas with set_memory_*() as +	 * these helpers cannot work with IO memory.  	 */  	return change_page_attr_set(&addr, numpages,  				    cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS), @@ -1502,12 +1503,10 @@ EXPORT_SYMBOL(set_memory_uc);  static int _set_memory_array(unsigned long *addr, int addrinarray,  		enum page_cache_mode new_type)  { +	enum page_cache_mode set_type;  	int i, j;  	int ret; -	/* -	 * for now UC MINUS. see comments in ioremap_nocache() -	 */  	for (i = 0; i < addrinarray; i++) {  		ret = reserve_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE,  					new_type, NULL); @@ -1515,9 +1514,12 @@ static int _set_memory_array(unsigned long *addr, int addrinarray,  			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, -				   cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS), -				   1); +				   cachemode2pgprot(set_type), 1);  	if (!ret && new_type == _PAGE_CACHE_MODE_WC)  		ret = change_page_attr_set_clr(addr, addrinarray, @@ -1549,6 +1551,12 @@ int set_memory_array_wc(unsigned long *addr, int addrinarray)  }  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 ret; @@ -1571,27 +1579,42 @@ int set_memory_wc(unsigned long addr, int numpages)  {  	int ret; -	if (!pat_enabled) -		return set_memory_uc(addr, numpages); -  	ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,  		_PAGE_CACHE_MODE_WC, NULL);  	if (ret) -		goto out_err; +		return ret;  	ret = _set_memory_wc(addr, numpages);  	if (ret) -		goto out_free; - -	return 0; +		free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE); -out_free: -	free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE); -out_err:  	return ret;  }  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)  {  	/* 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,  {  	unsigned long start;  	unsigned long end; +	enum page_cache_mode set_type;  	int i;  	int free_idx;  	int ret; @@ -1695,8 +1719,12 @@ static int _set_pages_array(struct page **pages, int addrinarray,  			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, -			cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS)); +				  cachemode2pgprot(set_type));  	if (!ret && new_type == _PAGE_CACHE_MODE_WC)  		ret = change_page_attr_set_clr(NULL, addrinarray,  					       cachemode2pgprot( @@ -1730,6 +1758,12 @@ int set_pages_array_wc(struct page **pages, int addrinarray)  }  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)  {  	unsigned long addr = (unsigned long)page_address(page);  |