[PATCH 09/17] powerpc: make __ioremap_caller() common to PPC32 and PPC64

Christophe LEROY christophe.leroy at c-s.fr
Wed May 16 19:58:05 AEST 2018



Le 08/05/2018 à 11:56, Aneesh Kumar K.V a écrit :
> Christophe Leroy <christophe.leroy at c-s.fr> writes:
> 
>> Signed-off-by: Christophe Leroy <christophe.leroy at c-s.fr>
>> ---
>>   arch/powerpc/include/asm/book3s/64/pgtable.h |   1 +
>>   arch/powerpc/mm/ioremap.c                    | 126 +++++++--------------------
>>   2 files changed, 34 insertions(+), 93 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
>> index c5c6ead06bfb..2bebdd8302cb 100644
>> --- a/arch/powerpc/include/asm/book3s/64/pgtable.h
>> +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
>> @@ -18,6 +18,7 @@
>>   #define _PAGE_RO		0
>>   #define _PAGE_USER		0
>>   #define _PAGE_HWWRITE		0
>> +#define _PAGE_COHERENT		0
> 
> This is something I was trying to avoid when I split the headers. We do
> support _PAGE_USER it is !_PAGE_PRIVILEGED. It gets really confusing
> when we have these conflicting names because we are trying to make code
> common across platforms.

Euh ... Here patch adds _PAGE_COHERENT

_PAGE_USER was added some time ago.

Well, we have three cases:

BOOK3S64 and NOHASH32/8xx has _PAGE_PRIVILEGED and no _PAGE_USER
BOOKE has both _PAGE_PRIVILEGED and _PAGE_USER
Others have _PAGE_USER and no _PAGE_PRIVILEGED

So when giving user rights to a page, some will set _PAGE_USER, some 
will unset _PAGE_PRIVILEGED and some will do both.

_PAGE_USER and _PAGE_PRIVILEGED being used outside of the subarch headers,
- either we have to add uggly ifdefs
- or we can just make sure unused flags are set as 0, then  (x | 0) and 
(x & ~0) will do nothing and will be eliminated by the compiler.

Today, this is done in asm/pte-common.h. Unfortunately, all headers 
except book3s64 do include pte-common.

Another solution would be to make sure _PAGE_xxx flags are not used 
outside of subarch specific headers. That would mean having specific 
helpers defined in each subarch header, but is it really worth it ?




Lets take the exemple of an even more tricky one :
- Some subarchs have _PAGE_RW, others have _PAGE_RO instead. In 
addition, the 8xx has _PAGE_NA
- Book3s64 has _PAGE_READ and _PAGE_WRITE.
- In some places, _PAGE_RW has been redefined has _PAGE_READ | _PAGE_WRITE

It has really become pretty complex. Why having defined new flags 
instead of using _PAGE_RO for _PAGE_READ and _PAGE_RW for _PAGE_READ | 
_PAGE_WRITE ? Does it make any sense to have the possibility to set 
_PAGE_WRITE without _PAGE_READ ?


I feel like having simple generic code like:

	flags = (flags & ~_PAGE_PRIVILEGED) | _PAGE_USER;

is better than having almost same code duplicated in several places or 
ugly ifdefs like:

#if defined(CONFIG_BOOK3S64) || defined(CONFIG_PPC_8xx) || defined 
(CONFIG_BOOKE)
	flags &= ~_PAGE_PRIVILEGED;
#endif
#if !defined(CONFIG_BOOK3S64) && !defined(CONFIG_PPC_8xx)
	flags |= _PAGE_USER;
#endif


It looks to me that patch 
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=812fadcb941a81d1f3948b10a95a4dce663da3e4 
allowed a nice code simplification, don't you feel the same ?

Christophe

> 
> 
>>   
>>   #define _PAGE_EXEC		0x00001 /* execute permission */
>>   #define _PAGE_WRITE		0x00002 /* write access allowed */
>> diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
>> index 65d611d44d38..59be5dfcb3e9 100644
>> --- a/arch/powerpc/mm/ioremap.c
>> +++ b/arch/powerpc/mm/ioremap.c
>> @@ -33,95 +33,6 @@ unsigned long ioremap_bot;
>>   unsigned long ioremap_bot = IOREMAP_BASE;
>>   #endif
>>   
>> -#ifdef CONFIG_PPC32
>> -
>> -void __iomem *
>> -__ioremap_caller(phys_addr_t addr, unsigned long size, unsigned long flags,
>> -		 void *caller)
>> -{
>> -	unsigned long v, i;
>> -	phys_addr_t p;
>> -	int err;
>> -
>> -	/* Make sure we have the base flags */
>> -	if ((flags & _PAGE_PRESENT) == 0)
>> -		flags |= pgprot_val(PAGE_KERNEL);
>> -
>> -	/* Non-cacheable page cannot be coherent */
>> -	if (flags & _PAGE_NO_CACHE)
>> -		flags &= ~_PAGE_COHERENT;
>> -
>> -	/*
>> -	 * Choose an address to map it to.
>> -	 * Once the vmalloc system is running, we use it.
>> -	 * Before then, we use space going up from IOREMAP_BASE
>> -	 * (ioremap_bot records where we're up to).
>> -	 */
>> -	p = addr & PAGE_MASK;
>> -	size = PAGE_ALIGN(addr + size) - p;
>> -
>> -	/*
>> -	 * If the address lies within the first 16 MB, assume it's in ISA
>> -	 * memory space
>> -	 */
>> -	if (p < 16*1024*1024)
>> -		p += _ISA_MEM_BASE;
>> -
>> -#ifndef CONFIG_CRASH_DUMP
>> -	/*
>> -	 * Don't allow anybody to remap normal RAM that we're using.
>> -	 * mem_init() sets high_memory so only do the check after that.
>> -	 */
>> -	if (slab_is_available() && (p < virt_to_phys(high_memory)) &&
>> -	    page_is_ram(__phys_to_pfn(p))) {
>> -		printk("__ioremap(): phys addr 0x%llx is RAM lr %ps\n",
>> -		       (unsigned long long)p, __builtin_return_address(0));
>> -		return NULL;
>> -	}
>> -#endif
>> -
>> -	if (size == 0)
>> -		return NULL;
>> -
>> -	/*
>> -	 * Is it already mapped?  Perhaps overlapped by a previous
>> -	 * mapping.
>> -	 */
>> -	v = p_block_mapped(p);
>> -	if (v)
>> -		goto out;
>> -
>> -	if (slab_is_available()) {
>> -		struct vm_struct *area;
>> -		area = get_vm_area_caller(size, VM_IOREMAP, caller);
>> -		if (area == 0)
>> -			return NULL;
>> -		area->phys_addr = p;
>> -		v = (unsigned long) area->addr;
>> -	} else {
>> -		v = ioremap_bot;
>> -		ioremap_bot += size;
>> -	}
>> -
>> -	/*
>> -	 * Should check if it is a candidate for a BAT mapping
>> -	 */
>> -
>> -	err = 0;
>> -	for (i = 0; i < size && err == 0; i += PAGE_SIZE)
>> -		err = map_kernel_page(v+i, p+i, flags);
>> -	if (err) {
>> -		if (slab_is_available())
>> -			vunmap((void *)v);
>> -		return NULL;
>> -	}
>> -
>> -out:
>> -	return (void __iomem *) (v + ((unsigned long)addr & ~PAGE_MASK));
>> -}
>> -
>> -#else
>> -
>>   /**
>>    * __ioremap_at - Low level function to establish the page tables
>>    *                for an IO mapping
>> @@ -135,6 +46,10 @@ void __iomem * __ioremap_at(phys_addr_t pa, void *ea, unsigned long size,
>>   	if ((flags & _PAGE_PRESENT) == 0)
>>   		flags |= pgprot_val(PAGE_KERNEL);
>>   
>> +	/* Non-cacheable page cannot be coherent */
>> +	if (flags & _PAGE_NO_CACHE)
>> +		flags &= ~_PAGE_COHERENT;
>> +
>>   	/* We don't support the 4K PFN hack with ioremap */
>>   	if (flags & H_PAGE_4K_PFN)
>>   		return NULL;
>> @@ -187,6 +102,33 @@ void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,
>>   	if ((size == 0) || (paligned == 0))
>>   		return NULL;
>>   
>> +	/*
>> +	 * If the address lies within the first 16 MB, assume it's in ISA
>> +	 * memory space
>> +	 */
>> +	if (IS_ENABLED(CONFIG_PPC32) && paligned < 16*1024*1024)
>> +		paligned += _ISA_MEM_BASE;
>> +
>> +	/*
>> +	 * Don't allow anybody to remap normal RAM that we're using.
>> +	 * mem_init() sets high_memory so only do the check after that.
>> +	 */
>> +	if (!IS_ENABLED(CONFIG_CRASH_DUMP) &&
>> +	    slab_is_available() && (paligned < virt_to_phys(high_memory)) &&
>> +	    page_is_ram(__phys_to_pfn(paligned))) {
>> +		printk("__ioremap(): phys addr 0x%llx is RAM lr %ps\n",
>> +		       (u64)paligned, __builtin_return_address(0));
>> +		return NULL;
>> +	}
>> +
>> +	/*
>> +	 * Is it already mapped?  Perhaps overlapped by a previous
>> +	 * mapping.
>> +	 */
>> +	ret = (void __iomem *)p_block_mapped(paligned);
>> +	if (ret)
>> +		goto out;
>> +
>>   	if (slab_is_available()) {
>>   		struct vm_struct *area;
>>   
>> @@ -205,14 +147,12 @@ void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,
>>   		if (ret)
>>   			ioremap_bot += size;
>>   	}
>> -
>> +out:
>>   	if (ret)
>> -		ret += addr & ~PAGE_MASK;
>> +		ret += (unsigned long)addr & ~PAGE_MASK;
>>   	return ret;
>>   }
>>   
>> -#endif
>> -
>>   /*
>>    * Unmap an IO region and remove it from imalloc'd list.
>>    * Access to IO memory should be serialized by driver.
>> -- 
>> 2.13.3


More information about the Linuxppc-dev mailing list