Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72e458df authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Ingo Molnar
Browse files

x86: introduce struct cpa_data



The number of arguments which need to be transported is increasing
and we want to add flush optimizations and large page preserving.

Create struct cpa data and pass a pointer instead of increasing the
number of arguments further.

Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 6bb8383b
Loading
Loading
Loading
Loading
+38 −37
Original line number Original line Diff line number Diff line
@@ -16,6 +16,13 @@
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/pgalloc.h>


struct cpa_data {
	unsigned long	vaddr;
	int		numpages;
	pgprot_t	mask_set;
	pgprot_t	mask_clr;
};

static inline int
static inline int
within(unsigned long addr, unsigned long start, unsigned long end)
within(unsigned long addr, unsigned long start, unsigned long end)
{
{
@@ -284,8 +291,7 @@ static int split_large_page(pte_t *kpte, unsigned long address)
	return 0;
	return 0;
}
}


static int
static int __change_page_attr(unsigned long address, struct cpa_data *cpa)
__change_page_attr(unsigned long address, pgprot_t mask_set, pgprot_t mask_clr)
{
{
	struct page *kpte_page;
	struct page *kpte_page;
	int level, err = 0;
	int level, err = 0;
@@ -305,12 +311,15 @@ __change_page_attr(unsigned long address, pgprot_t mask_set, pgprot_t mask_clr)
		pgprot_t new_prot = pte_pgprot(old_pte);
		pgprot_t new_prot = pte_pgprot(old_pte);


		if(!pte_val(old_pte)) {
		if(!pte_val(old_pte)) {
			WARN_ON_ONCE(1);
			printk(KERN_WARNING "CPA: called for zero pte. "
			       "vaddr = %lx cpa->vaddr = %lx\n", address,
				cpa->vaddr);
			WARN_ON(1);
			return -EINVAL;
			return -EINVAL;
		}
		}


		pgprot_val(new_prot) &= ~pgprot_val(mask_clr);
		pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
		pgprot_val(new_prot) |= pgprot_val(mask_set);
		pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);


		new_prot = static_protections(new_prot, address);
		new_prot = static_protections(new_prot, address);


@@ -343,12 +352,10 @@ __change_page_attr(unsigned long address, pgprot_t mask_set, pgprot_t mask_clr)
 * Modules and drivers should use the set_memory_* APIs instead.
 * Modules and drivers should use the set_memory_* APIs instead.
 */
 */



static int change_page_attr_addr(struct cpa_data *cpa)
static int
change_page_attr_addr(unsigned long address, pgprot_t mask_set,
		      pgprot_t mask_clr)
{
{
	int err;
	int err;
	unsigned long address = cpa->vaddr;


#ifdef CONFIG_X86_64
#ifdef CONFIG_X86_64
	unsigned long phys_addr = __pa(address);
	unsigned long phys_addr = __pa(address);
@@ -362,7 +369,7 @@ change_page_attr_addr(unsigned long address, pgprot_t mask_set,
		address = (unsigned long) __va(phys_addr);
		address = (unsigned long) __va(phys_addr);
#endif
#endif


	err = __change_page_attr(address, mask_set, mask_clr);
	err = __change_page_attr(address, cpa);
	if (err)
	if (err)
		return err;
		return err;


@@ -386,20 +393,19 @@ change_page_attr_addr(unsigned long address, pgprot_t mask_set,
		 * everything between 0 and KERNEL_TEXT_SIZE, so do
		 * everything between 0 and KERNEL_TEXT_SIZE, so do
		 * not propagate lookup failures back to users:
		 * not propagate lookup failures back to users:
		 */
		 */
		__change_page_attr(address, mask_set, mask_clr);
		__change_page_attr(address, cpa);
	}
	}
#endif
#endif
	return err;
	return err;
}
}


static int __change_page_attr_set_clr(unsigned long addr, int numpages,
static int __change_page_attr_set_clr(struct cpa_data *cpa)
				      pgprot_t mask_set, pgprot_t mask_clr)
{
{
	unsigned int i;
	unsigned int i;
	int ret;
	int ret;


	for (i = 0; i < numpages ; i++, addr += PAGE_SIZE) {
	for (i = 0; i < cpa->numpages ; i++, cpa->vaddr += PAGE_SIZE) {
		ret = change_page_attr_addr(addr, mask_set, mask_clr);
		ret = change_page_attr_addr(cpa);
		if (ret)
		if (ret)
			return ret;
			return ret;
	}
	}
@@ -416,6 +422,7 @@ static inline int cache_attr(pgprot_t attr)
static int change_page_attr_set_clr(unsigned long addr, int numpages,
static int change_page_attr_set_clr(unsigned long addr, int numpages,
				    pgprot_t mask_set, pgprot_t mask_clr)
				    pgprot_t mask_set, pgprot_t mask_clr)
{
{
	struct cpa_data cpa;
	int ret, cache;
	int ret, cache;


	/*
	/*
@@ -427,7 +434,12 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages,
	if (!pgprot_val(mask_set) && !pgprot_val(mask_clr))
	if (!pgprot_val(mask_set) && !pgprot_val(mask_clr))
		return 0;
		return 0;


	ret = __change_page_attr_set_clr(addr, numpages, mask_set, mask_clr);
	cpa.vaddr = addr;
	cpa.numpages = numpages;
	cpa.mask_set = mask_set;
	cpa.mask_clr = mask_clr;

	ret = __change_page_attr_set_clr(&cpa);


	/*
	/*
	 * No need to flush, when we did not set any of the caching
	 * No need to flush, when we did not set any of the caching
@@ -548,37 +560,26 @@ int set_pages_rw(struct page *page, int numpages)
	return set_memory_rw(addr, numpages);
	return set_memory_rw(addr, numpages);
}
}



#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_CPA_DEBUG)
static inline int __change_page_attr_set(unsigned long addr, int numpages,
					 pgprot_t mask)
{
	return __change_page_attr_set_clr(addr, numpages, mask, __pgprot(0));
}

static inline int __change_page_attr_clear(unsigned long addr, int numpages,
					   pgprot_t mask)
{
	return __change_page_attr_set_clr(addr, numpages, __pgprot(0), mask);
}
#endif

#ifdef CONFIG_DEBUG_PAGEALLOC
#ifdef CONFIG_DEBUG_PAGEALLOC


static int __set_pages_p(struct page *page, int numpages)
static int __set_pages_p(struct page *page, int numpages)
{
{
	unsigned long addr = (unsigned long)page_address(page);
	struct cpa_data cpa = { .vaddr = (unsigned long) page_address(page),
				.numpages = numpages,
				.mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW),
				.mask_clr = __pgprot(0)};


	return __change_page_attr_set(addr, numpages,
	return __change_page_attr_set_clr(&cpa);
				      __pgprot(_PAGE_PRESENT | _PAGE_RW));
}
}


static int __set_pages_np(struct page *page, int numpages)
static int __set_pages_np(struct page *page, int numpages)
{
{
	unsigned long addr = (unsigned long)page_address(page);
	struct cpa_data cpa = { .vaddr = (unsigned long) page_address(page),
				.numpages = numpages,
				.mask_set = __pgprot(0),
				.mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW)};


	return __change_page_attr_clear(addr, numpages,
	return __change_page_attr_set_clr(&cpa);
					__pgprot(_PAGE_PRESENT));
}
}


void kernel_map_pages(struct page *page, int numpages, int enable)
void kernel_map_pages(struct page *page, int numpages, int enable)