Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 08/10] mm: replace __access_remote_vm() write parameter with gup_flags
From: Jan Kara @ 2016-10-19  7:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161013002020.3062-9-lstoakes@gmail.com>

On Thu 13-10-16 01:20:18, Lorenzo Stoakes wrote:
> This patch removes the write parameter from __access_remote_vm() and replaces it
> with a gup_flags parameter as use of this function previously _implied_
> FOLL_FORCE, whereas after this patch callers explicitly pass this flag.
> 
> We make this explicit as use of FOLL_FORCE can result in surprising behaviour
> (and hence bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>

So I'm not convinced this (and the following two patches) is actually
helping much. By grepping for FOLL_FORCE we will easily see that any caller
of access_remote_vm() gets that semantics and can thus continue search
accordingly (it is much simpler than searching for all get_user_pages()
users and extracting from parameter lists what they actually pass as
'force' argument). Sure it makes somewhat more visible to callers of
access_remote_vm() that they get FOLL_FORCE semantics but OTOH it also
opens a space for issues where a caller of access_remote_vm() actually
wants FOLL_FORCE (and currently all of them want it) and just mistakenly
does not set it. All in all I'd prefer to keep access_remote_vm() and
friends as is...

								Honza

> ---
>  mm/memory.c | 23 +++++++++++++++--------
>  mm/nommu.c  |  9 ++++++---
>  2 files changed, 21 insertions(+), 11 deletions(-)
> 
> diff --git a/mm/memory.c b/mm/memory.c
> index 20a9adb..79ebed3 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3869,14 +3869,11 @@ EXPORT_SYMBOL_GPL(generic_access_phys);
>   * given task for page fault accounting.
>   */
>  static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
> -		unsigned long addr, void *buf, int len, int write)
> +		unsigned long addr, void *buf, int len, unsigned int gup_flags)
>  {
>  	struct vm_area_struct *vma;
>  	void *old_buf = buf;
> -	unsigned int flags = FOLL_FORCE;
> -
> -	if (write)
> -		flags |= FOLL_WRITE;
> +	int write = gup_flags & FOLL_WRITE;
>  
>  	down_read(&mm->mmap_sem);
>  	/* ignore errors, just check how much was successfully transferred */
> @@ -3886,7 +3883,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
>  		struct page *page = NULL;
>  
>  		ret = get_user_pages_remote(tsk, mm, addr, 1,
> -				flags, &page, &vma);
> +				gup_flags, &page, &vma);
>  		if (ret <= 0) {
>  #ifndef CONFIG_HAVE_IOREMAP_PROT
>  			break;
> @@ -3945,7 +3942,12 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
>  int access_remote_vm(struct mm_struct *mm, unsigned long addr,
>  		void *buf, int len, int write)
>  {
> -	return __access_remote_vm(NULL, mm, addr, buf, len, write);
> +	unsigned int flags = FOLL_FORCE;
> +
> +	if (write)
> +		flags |= FOLL_WRITE;
> +
> +	return __access_remote_vm(NULL, mm, addr, buf, len, flags);
>  }
>  
>  /*
> @@ -3958,12 +3960,17 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr,
>  {
>  	struct mm_struct *mm;
>  	int ret;
> +	unsigned int flags = FOLL_FORCE;
>  
>  	mm = get_task_mm(tsk);
>  	if (!mm)
>  		return 0;
>  
> -	ret = __access_remote_vm(tsk, mm, addr, buf, len, write);
> +	if (write)
> +		flags |= FOLL_WRITE;
> +
> +	ret = __access_remote_vm(tsk, mm, addr, buf, len, flags);
> +
>  	mmput(mm);
>  
>  	return ret;
> diff --git a/mm/nommu.c b/mm/nommu.c
> index 70cb844..bde7df3 100644
> --- a/mm/nommu.c
> +++ b/mm/nommu.c
> @@ -1809,9 +1809,10 @@ void filemap_map_pages(struct fault_env *fe,
>  EXPORT_SYMBOL(filemap_map_pages);
>  
>  static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
> -		unsigned long addr, void *buf, int len, int write)
> +		unsigned long addr, void *buf, int len, unsigned int gup_flags)
>  {
>  	struct vm_area_struct *vma;
> +	int write = gup_flags & FOLL_WRITE;
>  
>  	down_read(&mm->mmap_sem);
>  
> @@ -1853,7 +1854,8 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
>  int access_remote_vm(struct mm_struct *mm, unsigned long addr,
>  		void *buf, int len, int write)
>  {
> -	return __access_remote_vm(NULL, mm, addr, buf, len, write);
> +	return __access_remote_vm(NULL, mm, addr, buf, len,
> +			write ? FOLL_WRITE : 0);
>  }
>  
>  /*
> @@ -1871,7 +1873,8 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in
>  	if (!mm)
>  		return 0;
>  
> -	len = __access_remote_vm(tsk, mm, addr, buf, len, write);
> +	len = __access_remote_vm(tsk, mm, addr, buf, len,
> +			write ? FOLL_WRITE : 0);
>  
>  	mmput(mm);
>  	return len;
> -- 
> 2.10.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply

* [PATCH/RESEND] clocksource/arm_arch_timer: Map frame with of_io_request_and_map()
From: Marc Zyngier @ 2016-10-19  7:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018234514.6175-1-sboyd@codeaurora.org>

On 19/10/16 00:45, Stephen Boyd wrote:
> Let's use the of_io_request_and_map() API so that the frame
> region is protected and shows up in /proc/iomem.
> 
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> ---
>  drivers/clocksource/arm_arch_timer.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
> index 73c487da6d2a..cbfa3bc5be75 100644
> --- a/drivers/clocksource/arm_arch_timer.c
> +++ b/drivers/clocksource/arm_arch_timer.c
> @@ -964,7 +964,8 @@ static int __init arch_timer_mem_init(struct device_node *np)
>  	}
>  
>  	ret= -ENXIO;
> -	base = arch_counter_base = of_iomap(best_frame, 0);
> +	base = arch_counter_base = of_io_request_and_map(best_frame, 0,
> +							 "arch_mem_timer");
>  	if (!base) {
>  		pr_err("arch_timer: Can't map frame's registers\n");
>  		goto out;
> 

Careful here: of_io_request_and_map() returns an ERR_PTR() on failure,
while of_iomap just returns NULL. You want to change the error handling
if you're going down that road.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply

* [PATCH 07/10] mm: replace get_user_pages_remote() write/force parameters with gup_flags
From: Jan Kara @ 2016-10-19  7:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161013002020.3062-8-lstoakes@gmail.com>

On Thu 13-10-16 01:20:17, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_user_pages_remote()
> and replaces them with a gup_flags parameter to make the use of FOLL_FORCE
> explicit in callers as use of this flag can result in surprising behaviour (and
> hence bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  drivers/gpu/drm/etnaviv/etnaviv_gem.c   |  7 +++++--
>  drivers/gpu/drm/i915/i915_gem_userptr.c |  6 +++++-
>  drivers/infiniband/core/umem_odp.c      |  7 +++++--
>  fs/exec.c                               |  9 +++++++--
>  include/linux/mm.h                      |  2 +-
>  kernel/events/uprobes.c                 |  6 ++++--
>  mm/gup.c                                | 22 +++++++---------------
>  mm/memory.c                             |  6 +++++-
>  security/tomoyo/domain.c                |  2 +-
>  9 files changed, 40 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> index 5ce3603..0370b84 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> @@ -748,19 +748,22 @@ static struct page **etnaviv_gem_userptr_do_get_pages(
>  	int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
>  	struct page **pvec;
>  	uintptr_t ptr;
> +	unsigned int flags = 0;
>  
>  	pvec = drm_malloc_ab(npages, sizeof(struct page *));
>  	if (!pvec)
>  		return ERR_PTR(-ENOMEM);
>  
> +	if (!etnaviv_obj->userptr.ro)
> +		flags |= FOLL_WRITE;
> +
>  	pinned = 0;
>  	ptr = etnaviv_obj->userptr.ptr;
>  
>  	down_read(&mm->mmap_sem);
>  	while (pinned < npages) {
>  		ret = get_user_pages_remote(task, mm, ptr, npages - pinned,
> -					    !etnaviv_obj->userptr.ro, 0,
> -					    pvec + pinned, NULL);
> +					    flags, pvec + pinned, NULL);
>  		if (ret < 0)
>  			break;
>  
> diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c
> index e537930..c6f780f 100644
> --- a/drivers/gpu/drm/i915/i915_gem_userptr.c
> +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
> @@ -508,6 +508,10 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
>  	pvec = drm_malloc_gfp(npages, sizeof(struct page *), GFP_TEMPORARY);
>  	if (pvec != NULL) {
>  		struct mm_struct *mm = obj->userptr.mm->mm;
> +		unsigned int flags = 0;
> +
> +		if (!obj->userptr.read_only)
> +			flags |= FOLL_WRITE;
>  
>  		ret = -EFAULT;
>  		if (atomic_inc_not_zero(&mm->mm_users)) {
> @@ -517,7 +521,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
>  					(work->task, mm,
>  					 obj->userptr.ptr + pinned * PAGE_SIZE,
>  					 npages - pinned,
> -					 !obj->userptr.read_only, 0,
> +					 flags,
>  					 pvec + pinned, NULL);
>  				if (ret < 0)
>  					break;
> diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
> index 75077a0..1f0fe32 100644
> --- a/drivers/infiniband/core/umem_odp.c
> +++ b/drivers/infiniband/core/umem_odp.c
> @@ -527,6 +527,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
>  	u64 off;
>  	int j, k, ret = 0, start_idx, npages = 0;
>  	u64 base_virt_addr;
> +	unsigned int flags = 0;
>  
>  	if (access_mask == 0)
>  		return -EINVAL;
> @@ -556,6 +557,9 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
>  		goto out_put_task;
>  	}
>  
> +	if (access_mask & ODP_WRITE_ALLOWED_BIT)
> +		flags |= FOLL_WRITE;
> +
>  	start_idx = (user_virt - ib_umem_start(umem)) >> PAGE_SHIFT;
>  	k = start_idx;
>  
> @@ -574,8 +578,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
>  		 */
>  		npages = get_user_pages_remote(owning_process, owning_mm,
>  				user_virt, gup_num_pages,
> -				access_mask & ODP_WRITE_ALLOWED_BIT,
> -				0, local_page_list, NULL);
> +				flags, local_page_list, NULL);
>  		up_read(&owning_mm->mmap_sem);
>  
>  		if (npages < 0)
> diff --git a/fs/exec.c b/fs/exec.c
> index 6fcfb3f..4e497b9 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -191,6 +191,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  {
>  	struct page *page;
>  	int ret;
> +	unsigned int gup_flags = FOLL_FORCE;
>  
>  #ifdef CONFIG_STACK_GROWSUP
>  	if (write) {
> @@ -199,12 +200,16 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  			return NULL;
>  	}
>  #endif
> +
> +	if (write)
> +		gup_flags |= FOLL_WRITE;
> +
>  	/*
>  	 * We are doing an exec().  'current' is the process
>  	 * doing the exec and bprm->mm is the new process's mm.
>  	 */
> -	ret = get_user_pages_remote(current, bprm->mm, pos, 1, write,
> -			1, &page, NULL);
> +	ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags,
> +			&page, NULL);
>  	if (ret <= 0)
>  		return NULL;
>  
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 686a477..2a481d3 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1276,7 +1276,7 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
>  		      struct vm_area_struct **vmas, int *nonblocking);
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  			    unsigned long start, unsigned long nr_pages,
> -			    int write, int force, struct page **pages,
> +			    unsigned int gup_flags, struct page **pages,
>  			    struct vm_area_struct **vmas);
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
>  			    unsigned int gup_flags, struct page **pages,
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index d4129bb..f9ec9ad 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -300,7 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr,
>  
>  retry:
>  	/* Read the page with vaddr into memory */
> -	ret = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
> +	ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page,
> +			&vma);
>  	if (ret <= 0)
>  		return ret;
>  
> @@ -1710,7 +1711,8 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
>  	 * but we treat this as a 'remote' access since it is
>  	 * essentially a kernel access to the memory.
>  	 */
> -	result = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
> +	result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page,
> +			NULL);
>  	if (result < 0)
>  		return result;
>  
> diff --git a/mm/gup.c b/mm/gup.c
> index dc91303..0deecf3 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -905,9 +905,7 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * @mm:		mm_struct of target mm
>   * @start:	starting user address
>   * @nr_pages:	number of pages from start to pin
> - * @write:	whether pages will be written to by the caller
> - * @force:	whether to force access even when user mapping is currently
> - *		protected (but never forces write access to shared mapping).
> + * @gup_flags:	flags modifying lookup behaviour
>   * @pages:	array that receives pointers to the pages pinned.
>   *		Should be at least nr_pages long. Or NULL, if caller
>   *		only intends to ensure the pages are faulted in.
> @@ -936,9 +934,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * or similar operation cannot guarantee anything stronger anyway because
>   * locks can't be held over the syscall boundary.
>   *
> - * If write=0, the page must not be written to. If the page is written to,
> - * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called
> - * after the page is finished with, and before put_page is called.
> + * If gup_flags & FOLL_WRITE == 0, the page must not be written to. If the page
> + * is written to, set_page_dirty (or set_page_dirty_lock, as appropriate) must
> + * be called after the page is finished with, and before put_page is called.
>   *
>   * get_user_pages is typically used for fewer-copy IO operations, to get a
>   * handle on the memory by some means other than accesses via the user virtual
> @@ -955,18 +953,12 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   */
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  		unsigned long start, unsigned long nr_pages,
> -		int write, int force, struct page **pages,
> +		unsigned int gup_flags, struct page **pages,
>  		struct vm_area_struct **vmas)
>  {
> -	unsigned int flags = FOLL_TOUCH | FOLL_REMOTE;
> -
> -	if (write)
> -		flags |= FOLL_WRITE;
> -	if (force)
> -		flags |= FOLL_FORCE;
> -
>  	return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
> -				       NULL, false, flags);
> +				       NULL, false,
> +				       gup_flags | FOLL_TOUCH | FOLL_REMOTE);
>  }
>  EXPORT_SYMBOL(get_user_pages_remote);
>  
> diff --git a/mm/memory.c b/mm/memory.c
> index fc1987d..20a9adb 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3873,6 +3873,10 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
>  {
>  	struct vm_area_struct *vma;
>  	void *old_buf = buf;
> +	unsigned int flags = FOLL_FORCE;
> +
> +	if (write)
> +		flags |= FOLL_WRITE;
>  
>  	down_read(&mm->mmap_sem);
>  	/* ignore errors, just check how much was successfully transferred */
> @@ -3882,7 +3886,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
>  		struct page *page = NULL;
>  
>  		ret = get_user_pages_remote(tsk, mm, addr, 1,
> -				write, 1, &page, &vma);
> +				flags, &page, &vma);
>  		if (ret <= 0) {
>  #ifndef CONFIG_HAVE_IOREMAP_PROT
>  			break;
> diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
> index ade7c6c..682b73a 100644
> --- a/security/tomoyo/domain.c
> +++ b/security/tomoyo/domain.c
> @@ -881,7 +881,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
>  	 * the execve().
>  	 */
>  	if (get_user_pages_remote(current, bprm->mm, pos, 1,
> -				0, 1, &page, NULL) <= 0)
> +				FOLL_FORCE, &page, NULL) <= 0)
>  		return false;
>  #else
>  	page = bprm->page[pos / PAGE_SIZE];
> -- 
> 2.10.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply

* [PATCH 06/10] mm: replace get_user_pages() write/force parameters with gup_flags
From: Jan Kara @ 2016-10-19  7:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161013002020.3062-7-lstoakes@gmail.com>

On Thu 13-10-16 01:20:16, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_user_pages() and
> replaces them with a gup_flags parameter to make the use of FOLL_FORCE explicit
> in callers as use of this flag can result in surprising behaviour (and hence
> bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>

The patch looks good. You can add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  arch/cris/arch-v32/drivers/cryptocop.c                 |  4 +---
>  arch/ia64/kernel/err_inject.c                          |  2 +-
>  arch/x86/mm/mpx.c                                      |  5 ++---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c                |  7 +++++--
>  drivers/gpu/drm/radeon/radeon_ttm.c                    |  3 ++-
>  drivers/gpu/drm/via/via_dmablit.c                      |  4 ++--
>  drivers/infiniband/core/umem.c                         |  6 +++++-
>  drivers/infiniband/hw/mthca/mthca_memfree.c            |  2 +-
>  drivers/infiniband/hw/qib/qib_user_pages.c             |  3 ++-
>  drivers/infiniband/hw/usnic/usnic_uiom.c               |  5 ++++-
>  drivers/media/v4l2-core/videobuf-dma-sg.c              |  7 +++++--
>  drivers/misc/mic/scif/scif_rma.c                       |  3 +--
>  drivers/misc/sgi-gru/grufault.c                        |  2 +-
>  drivers/platform/goldfish/goldfish_pipe.c              |  3 ++-
>  drivers/rapidio/devices/rio_mport_cdev.c               |  3 ++-
>  .../vc04_services/interface/vchiq_arm/vchiq_2835_arm.c |  3 +--
>  .../vc04_services/interface/vchiq_arm/vchiq_arm.c      |  3 +--
>  drivers/virt/fsl_hypervisor.c                          |  4 ++--
>  include/linux/mm.h                                     |  2 +-
>  mm/gup.c                                               | 12 +++---------
>  mm/mempolicy.c                                         |  2 +-
>  mm/nommu.c                                             | 18 ++++--------------
>  22 files changed, 49 insertions(+), 54 deletions(-)
> 
> diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c
> index b5698c8..099e170 100644
> --- a/arch/cris/arch-v32/drivers/cryptocop.c
> +++ b/arch/cris/arch-v32/drivers/cryptocop.c
> @@ -2722,7 +2722,6 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig
>  	err = get_user_pages((unsigned long int)(oper.indata + prev_ix),
>  			     noinpages,
>  			     0,  /* read access only for in data */
> -			     0, /* no force */
>  			     inpages,
>  			     NULL);
>  
> @@ -2736,8 +2735,7 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig
>  	if (oper.do_cipher){
>  		err = get_user_pages((unsigned long int)oper.cipher_outdata,
>  				     nooutpages,
> -				     1, /* write access for out data */
> -				     0, /* no force */
> +				     FOLL_WRITE, /* write access for out data */
>  				     outpages,
>  				     NULL);
>  		up_read(&current->mm->mmap_sem);
> diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c
> index 09f8457..5ed0ea9 100644
> --- a/arch/ia64/kernel/err_inject.c
> +++ b/arch/ia64/kernel/err_inject.c
> @@ -142,7 +142,7 @@ store_virtual_to_phys(struct device *dev, struct device_attribute *attr,
>  	u64 virt_addr=simple_strtoull(buf, NULL, 16);
>  	int ret;
>  
> -	ret = get_user_pages(virt_addr, 1, VM_READ, 0, NULL, NULL);
> +	ret = get_user_pages(virt_addr, 1, FOLL_WRITE, NULL, NULL);
>  	if (ret<=0) {
>  #ifdef ERR_INJ_DEBUG
>  		printk("Virtual address %lx is not existing.\n",virt_addr);
> diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c
> index 8047687..e4f8009 100644
> --- a/arch/x86/mm/mpx.c
> +++ b/arch/x86/mm/mpx.c
> @@ -544,10 +544,9 @@ static int mpx_resolve_fault(long __user *addr, int write)
>  {
>  	long gup_ret;
>  	int nr_pages = 1;
> -	int force = 0;
>  
> -	gup_ret = get_user_pages((unsigned long)addr, nr_pages, write,
> -			force, NULL, NULL);
> +	gup_ret = get_user_pages((unsigned long)addr, nr_pages,
> +			write ? FOLL_WRITE : 0,	NULL, NULL);
>  	/*
>  	 * get_user_pages() returns number of pages gotten.
>  	 * 0 means we failed to fault in and get anything,
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
> index 887483b..dcaf691 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
> @@ -555,10 +555,13 @@ struct amdgpu_ttm_tt {
>  int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
>  {
>  	struct amdgpu_ttm_tt *gtt = (void *)ttm;
> -	int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
> +	unsigned int flags = 0;
>  	unsigned pinned = 0;
>  	int r;
>  
> +	if (!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY))
> +		flags |= FOLL_WRITE;
> +
>  	if (gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) {
>  		/* check that we only use anonymous memory
>  		   to prevent problems with writeback */
> @@ -581,7 +584,7 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
>  		list_add(&guptask.list, &gtt->guptasks);
>  		spin_unlock(&gtt->guptasklock);
>  
> -		r = get_user_pages(userptr, num_pages, write, 0, p, NULL);
> +		r = get_user_pages(userptr, num_pages, flags, p, NULL);
>  
>  		spin_lock(&gtt->guptasklock);
>  		list_del(&guptask.list);
> diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
> index 4552682..3de5e6e 100644
> --- a/drivers/gpu/drm/radeon/radeon_ttm.c
> +++ b/drivers/gpu/drm/radeon/radeon_ttm.c
> @@ -566,7 +566,8 @@ static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
>  		uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
>  		struct page **pages = ttm->pages + pinned;
>  
> -		r = get_user_pages(userptr, num_pages, write, 0, pages, NULL);
> +		r = get_user_pages(userptr, num_pages, write ? FOLL_WRITE : 0,
> +				   pages, NULL);
>  		if (r < 0)
>  			goto release_pages;
>  
> diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c
> index 7e2a12c..1a3ad76 100644
> --- a/drivers/gpu/drm/via/via_dmablit.c
> +++ b/drivers/gpu/drm/via/via_dmablit.c
> @@ -241,8 +241,8 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg,  drm_via_dmablit_t *xfer)
>  	down_read(&current->mm->mmap_sem);
>  	ret = get_user_pages((unsigned long)xfer->mem_addr,
>  			     vsg->num_pages,
> -			     (vsg->direction == DMA_FROM_DEVICE),
> -			     0, vsg->pages, NULL);
> +			     (vsg->direction == DMA_FROM_DEVICE) ? FOLL_WRITE : 0,
> +			     vsg->pages, NULL);
>  
>  	up_read(&current->mm->mmap_sem);
>  	if (ret != vsg->num_pages) {
> diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
> index c68746c..224ad27 100644
> --- a/drivers/infiniband/core/umem.c
> +++ b/drivers/infiniband/core/umem.c
> @@ -94,6 +94,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
>  	unsigned long dma_attrs = 0;
>  	struct scatterlist *sg, *sg_list_start;
>  	int need_release = 0;
> +	unsigned int gup_flags = FOLL_WRITE;
>  
>  	if (dmasync)
>  		dma_attrs |= DMA_ATTR_WRITE_BARRIER;
> @@ -183,6 +184,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
>  	if (ret)
>  		goto out;
>  
> +	if (!umem->writable)
> +		gup_flags |= FOLL_FORCE;
> +
>  	need_release = 1;
>  	sg_list_start = umem->sg_head.sgl;
>  
> @@ -190,7 +194,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
>  		ret = get_user_pages(cur_base,
>  				     min_t(unsigned long, npages,
>  					   PAGE_SIZE / sizeof (struct page *)),
> -				     1, !umem->writable, page_list, vma_list);
> +				     gup_flags, page_list, vma_list);
>  
>  		if (ret < 0)
>  			goto out;
> diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
> index 6c00d04..c6fe89d 100644
> --- a/drivers/infiniband/hw/mthca/mthca_memfree.c
> +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
> @@ -472,7 +472,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
>  		goto out;
>  	}
>  
> -	ret = get_user_pages(uaddr & PAGE_MASK, 1, 1, 0, pages, NULL);
> +	ret = get_user_pages(uaddr & PAGE_MASK, 1, FOLL_WRITE, pages, NULL);
>  	if (ret < 0)
>  		goto out;
>  
> diff --git a/drivers/infiniband/hw/qib/qib_user_pages.c b/drivers/infiniband/hw/qib/qib_user_pages.c
> index 2d2b94f..75f0862 100644
> --- a/drivers/infiniband/hw/qib/qib_user_pages.c
> +++ b/drivers/infiniband/hw/qib/qib_user_pages.c
> @@ -67,7 +67,8 @@ static int __qib_get_user_pages(unsigned long start_page, size_t num_pages,
>  
>  	for (got = 0; got < num_pages; got += ret) {
>  		ret = get_user_pages(start_page + got * PAGE_SIZE,
> -				     num_pages - got, 1, 1,
> +				     num_pages - got,
> +				     FOLL_WRITE | FOLL_FORCE,
>  				     p + got, NULL);
>  		if (ret < 0)
>  			goto bail_release;
> diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c
> index a0b6ebe..1ccee6e 100644
> --- a/drivers/infiniband/hw/usnic/usnic_uiom.c
> +++ b/drivers/infiniband/hw/usnic/usnic_uiom.c
> @@ -111,6 +111,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
>  	int i;
>  	int flags;
>  	dma_addr_t pa;
> +	unsigned int gup_flags;
>  
>  	if (!can_do_mlock())
>  		return -EPERM;
> @@ -135,6 +136,8 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
>  
>  	flags = IOMMU_READ | IOMMU_CACHE;
>  	flags |= (writable) ? IOMMU_WRITE : 0;
> +	gup_flags = FOLL_WRITE;
> +	gup_flags |= (writable) ? 0 : FOLL_FORCE;
>  	cur_base = addr & PAGE_MASK;
>  	ret = 0;
>  
> @@ -142,7 +145,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
>  		ret = get_user_pages(cur_base,
>  					min_t(unsigned long, npages,
>  					PAGE_SIZE / sizeof(struct page *)),
> -					1, !writable, page_list, NULL);
> +					gup_flags, page_list, NULL);
>  
>  		if (ret < 0)
>  			goto out;
> diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
> index f300f06..1db0af6 100644
> --- a/drivers/media/v4l2-core/videobuf-dma-sg.c
> +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
> @@ -156,6 +156,7 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
>  {
>  	unsigned long first, last;
>  	int err, rw = 0;
> +	unsigned int flags = FOLL_FORCE;
>  
>  	dma->direction = direction;
>  	switch (dma->direction) {
> @@ -178,12 +179,14 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
>  	if (NULL == dma->pages)
>  		return -ENOMEM;
>  
> +	if (rw == READ)
> +		flags |= FOLL_WRITE;
> +
>  	dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n",
>  		data, size, dma->nr_pages);
>  
>  	err = get_user_pages(data & PAGE_MASK, dma->nr_pages,
> -			     rw == READ, 1, /* force */
> -			     dma->pages, NULL);
> +			     flags, dma->pages, NULL);
>  
>  	if (err != dma->nr_pages) {
>  		dma->nr_pages = (err >= 0) ? err : 0;
> diff --git a/drivers/misc/mic/scif/scif_rma.c b/drivers/misc/mic/scif/scif_rma.c
> index e0203b1..f806a44 100644
> --- a/drivers/misc/mic/scif/scif_rma.c
> +++ b/drivers/misc/mic/scif/scif_rma.c
> @@ -1396,8 +1396,7 @@ int __scif_pin_pages(void *addr, size_t len, int *out_prot,
>  		pinned_pages->nr_pages = get_user_pages(
>  				(u64)addr,
>  				nr_pages,
> -				!!(prot & SCIF_PROT_WRITE),
> -				0,
> +				(prot & SCIF_PROT_WRITE) ? FOLL_WRITE : 0,
>  				pinned_pages->pages,
>  				NULL);
>  		up_write(&mm->mmap_sem);
> diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c
> index a2d97b9..6fb773d 100644
> --- a/drivers/misc/sgi-gru/grufault.c
> +++ b/drivers/misc/sgi-gru/grufault.c
> @@ -198,7 +198,7 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma,
>  #else
>  	*pageshift = PAGE_SHIFT;
>  #endif
> -	if (get_user_pages(vaddr, 1, write, 0, &page, NULL) <= 0)
> +	if (get_user_pages(vaddr, 1, write ? FOLL_WRITE : 0, &page, NULL) <= 0)
>  		return -EFAULT;
>  	*paddr = page_to_phys(page);
>  	put_page(page);
> diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
> index 07462d7..1aba2c7 100644
> --- a/drivers/platform/goldfish/goldfish_pipe.c
> +++ b/drivers/platform/goldfish/goldfish_pipe.c
> @@ -309,7 +309,8 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
>  		 * much memory to the process.
>  		 */
>  		down_read(&current->mm->mmap_sem);
> -		ret = get_user_pages(address, 1, !is_write, 0, &page, NULL);
> +		ret = get_user_pages(address, 1, is_write ? 0 : FOLL_WRITE,
> +				&page, NULL);
>  		up_read(&current->mm->mmap_sem);
>  		if (ret < 0)
>  			break;
> diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c
> index 436dfe8..9013a58 100644
> --- a/drivers/rapidio/devices/rio_mport_cdev.c
> +++ b/drivers/rapidio/devices/rio_mport_cdev.c
> @@ -892,7 +892,8 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode,
>  		down_read(&current->mm->mmap_sem);
>  		pinned = get_user_pages(
>  				(unsigned long)xfer->loc_addr & PAGE_MASK,
> -				nr_pages, dir == DMA_FROM_DEVICE, 0,
> +				nr_pages,
> +				dir == DMA_FROM_DEVICE ? FOLL_WRITE : 0,
>  				page_list, NULL);
>  		up_read(&current->mm->mmap_sem);
>  
> diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
> index c29040f..1091b9f 100644
> --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
> +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
> @@ -423,8 +423,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
>  		actual_pages = get_user_pages(task, task->mm,
>  				          (unsigned long)buf & ~(PAGE_SIZE - 1),
>  					  num_pages,
> -					  (type == PAGELIST_READ) /*Write */ ,
> -					  0 /*Force */ ,
> +					  (type == PAGELIST_READ) ? FOLL_WRITE : 0,
>  					  pages,
>  					  NULL /*vmas */);
>  		up_read(&task->mm->mmap_sem);
> diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
> index e11c0e0..7b6cd4d 100644
> --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
> +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
> @@ -1477,8 +1477,7 @@ dump_phys_mem(void *virt_addr, uint32_t num_bytes)
>  		current->mm,              /* mm */
>  		(unsigned long)virt_addr, /* start */
>  		num_pages,                /* len */
> -		0,                        /* write */
> -		0,                        /* force */
> +		0,                        /* gup_flags */
>  		pages,                    /* pages (array of page pointers) */
>  		NULL);                    /* vmas */
>  	up_read(&current->mm->mmap_sem);
> diff --git a/drivers/virt/fsl_hypervisor.c b/drivers/virt/fsl_hypervisor.c
> index 60bdad3..150ce2a 100644
> --- a/drivers/virt/fsl_hypervisor.c
> +++ b/drivers/virt/fsl_hypervisor.c
> @@ -245,8 +245,8 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
>  	/* Get the physical addresses of the source buffer */
>  	down_read(&current->mm->mmap_sem);
>  	num_pinned = get_user_pages(param.local_vaddr - lb_offset,
> -		num_pages, (param.source == -1) ? READ : WRITE,
> -		0, pages, NULL);
> +		num_pages, (param.source == -1) ? 0 : FOLL_WRITE,
> +		pages, NULL);
>  	up_read(&current->mm->mmap_sem);
>  
>  	if (num_pinned != num_pages) {
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 5ff084f6..686a477 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1279,7 +1279,7 @@ long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  			    int write, int force, struct page **pages,
>  			    struct vm_area_struct **vmas);
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
> -			    int write, int force, struct page **pages,
> +			    unsigned int gup_flags, struct page **pages,
>  			    struct vm_area_struct **vmas);
>  long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
>  		    unsigned int gup_flags, struct page **pages, int *locked);
> diff --git a/mm/gup.c b/mm/gup.c
> index 7a0d033..dc91303 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -977,18 +977,12 @@ EXPORT_SYMBOL(get_user_pages_remote);
>   * obviously don't pass FOLL_REMOTE in here.
>   */
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
> -		int write, int force, struct page **pages,
> +		unsigned int gup_flags, struct page **pages,
>  		struct vm_area_struct **vmas)
>  {
> -	unsigned int flags = FOLL_TOUCH;
> -
> -	if (write)
> -		flags |= FOLL_WRITE;
> -	if (force)
> -		flags |= FOLL_FORCE;
> -
>  	return __get_user_pages_locked(current, current->mm, start, nr_pages,
> -				       pages, vmas, NULL, false, flags);
> +				       pages, vmas, NULL, false,
> +				       gup_flags | FOLL_TOUCH);
>  }
>  EXPORT_SYMBOL(get_user_pages);
>  
> diff --git a/mm/mempolicy.c b/mm/mempolicy.c
> index ad1c96a..0b859af 100644
> --- a/mm/mempolicy.c
> +++ b/mm/mempolicy.c
> @@ -850,7 +850,7 @@ static int lookup_node(unsigned long addr)
>  	struct page *p;
>  	int err;
>  
> -	err = get_user_pages(addr & PAGE_MASK, 1, 0, 0, &p, NULL);
> +	err = get_user_pages(addr & PAGE_MASK, 1, 0, &p, NULL);
>  	if (err >= 0) {
>  		err = page_to_nid(p);
>  		put_page(p);
> diff --git a/mm/nommu.c b/mm/nommu.c
> index 842cfdd..70cb844 100644
> --- a/mm/nommu.c
> +++ b/mm/nommu.c
> @@ -160,18 +160,11 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
>   * - don't permit access to VMAs that don't support it, such as I/O mappings
>   */
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
> -		    int write, int force, struct page **pages,
> +		    unsigned int gup_flags, struct page **pages,
>  		    struct vm_area_struct **vmas)
>  {
> -	int flags = 0;
> -
> -	if (write)
> -		flags |= FOLL_WRITE;
> -	if (force)
> -		flags |= FOLL_FORCE;
> -
> -	return __get_user_pages(current, current->mm, start, nr_pages, flags,
> -				pages, vmas, NULL);
> +	return __get_user_pages(current, current->mm, start, nr_pages,
> +				gup_flags, pages, vmas, NULL);
>  }
>  EXPORT_SYMBOL(get_user_pages);
>  
> @@ -179,10 +172,7 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
>  			    unsigned int gup_flags, struct page **pages,
>  			    int *locked)
>  {
> -	int write = gup_flags & FOLL_WRITE;
> -	int force = gup_flags & FOLL_FORCE;
> -
> -	return get_user_pages(start, nr_pages, write, force, pages, NULL);
> +	return get_user_pages(start, nr_pages, gup_flags, pages, NULL);
>  }
>  EXPORT_SYMBOL(get_user_pages_locked);
>  
> -- 
> 2.10.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply

* [PATCH] ARM: integrator: drop EBI access use syscon
From: Linus Walleij @ 2016-10-19  7:43 UTC (permalink / raw)
  To: linux-arm-kernel

The EBI lookup is not longer in use: this has been moved to the
NAND chip driver. The syscon node is better accessed indirectly
using the regmap like the NAND chip driver does, so let's use
the syscon to set the modem control signals RTS/CTS through the
dedicated syscon register.

We also migrate the decoder status "SC_DEC" register that
enumerate the logic modules using syscon.

Cc: Russell King <linux@armlinux.org.uk>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 arch/arm/mach-integrator/integrator_ap.c | 54 ++++++++++++++++++--------------
 1 file changed, 30 insertions(+), 24 deletions(-)

diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 23b98fd414bf..a1af634f8709 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -27,6 +27,8 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/termios.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -37,11 +39,8 @@
 #include "pci_v3.h"
 #include "lm.h"
 
-/* Base address to the AP system controller */
-void __iomem *ap_syscon_base;
-/* Base address to the external bus interface */
-static void __iomem *ebi_base;
-
+/* Regmap to the AP system controller */
+static struct regmap *ap_syscon_map;
 
 /*
  * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
@@ -125,6 +124,7 @@ static void integrator_uart_set_mctrl(struct amba_device *dev,
 {
 	unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask;
 	u32 phybase = dev->res.start;
+	int ret;
 
 	if (phybase == INTEGRATOR_UART0_BASE) {
 		/* UART0 */
@@ -146,8 +146,17 @@ static void integrator_uart_set_mctrl(struct amba_device *dev,
 	else
 		ctrls |= dtr_mask;
 
-	__raw_writel(ctrls, ap_syscon_base + INTEGRATOR_SC_CTRLS_OFFSET);
-	__raw_writel(ctrlc, ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET);
+	ret = regmap_write(ap_syscon_map,
+			   INTEGRATOR_SC_CTRLS_OFFSET,
+			   ctrls);
+	if (ret)
+		pr_err("MODEM: unable to write PL010 UART CTRLS\n");
+
+	ret = regmap_write(ap_syscon_map,
+			   INTEGRATOR_SC_CTRLC_OFFSET,
+			   ctrlc);
+	if (ret)
+		pr_err("MODEM: unable to write PL010 UART CRTLC\n");
 }
 
 struct amba_pl010_data ap_uart_data = {
@@ -178,35 +187,32 @@ static const struct of_device_id ap_syscon_match[] = {
 	{ },
 };
 
-static const struct of_device_id ebi_match[] = {
-	{ .compatible = "arm,external-bus-interface"},
-	{ },
-};
-
 static void __init ap_init_of(void)
 {
-	unsigned long sc_dec;
+	u32 sc_dec;
 	struct device_node *syscon;
-	struct device_node *ebi;
+	int ret;
 	int i;
 
+	of_platform_default_populate(NULL, ap_auxdata_lookup, NULL);
+
 	syscon = of_find_matching_node(NULL, ap_syscon_match);
 	if (!syscon)
 		return;
-	ebi = of_find_matching_node(NULL, ebi_match);
-	if (!ebi)
+	ap_syscon_map = syscon_node_to_regmap(syscon);
+	if (IS_ERR(ap_syscon_map)) {
+		pr_crit("could not find Integrator/AP system controller\n");
 		return;
+	}
 
-	ap_syscon_base = of_iomap(syscon, 0);
-	if (!ap_syscon_base)
-		return;
-	ebi_base = of_iomap(ebi, 0);
-	if (!ebi_base)
+	ret = regmap_read(ap_syscon_map,
+			  INTEGRATOR_SC_DEC_OFFSET,
+			  &sc_dec);
+	if (ret) {
+		pr_crit("could not read from Integrator/AP syscon\n");
 		return;
+	}
 
-	of_platform_default_populate(NULL, ap_auxdata_lookup, NULL);
-
-	sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET);
 	for (i = 0; i < 4; i++) {
 		struct lm_device *lmdev;
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH] ARM: dt: sun8i-h3: Add sunxi-sid to dts for sun8i-h3
From: LABBE Corentin @ 2016-10-19  7:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161005122130.8cc229ff5d4990149956b49c@free.fr>

On Wed, Oct 05, 2016 at 12:21:30PM +0200, Jean-Francois Moine wrote:
> On Wed,  5 Oct 2016 11:48:24 +0200
> Corentin Labbe <clabbe.montjoie@gmail.com> wrote:
> 
> > This patch add support for the sunxi-sid driver to the device tree for sun8i-h3.
> > 
> > Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
> > ---
> >  arch/arm/boot/dts/sun8i-h3.dtsi | 5 +++++
> >  1 file changed, 5 insertions(+)
> > 
> > diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
> > index 9f58bb4..abfd29c 100644
> > --- a/arch/arm/boot/dts/sun8i-h3.dtsi
> > +++ b/arch/arm/boot/dts/sun8i-h3.dtsi
> > @@ -211,6 +211,11 @@
> >  			#size-cells = <0>;
> >  		};
> >  
> > +		sid: eeprom at 01c14200 {
> > +			compatible = "allwinner,sun7i-a20-sid";
> > +			reg = <0x01c14200 0x200>;
> 
> The datasheet says 1Kb starting at 0x01c14000.
> Is there any reason to reduce the area and to shift the offset?
> 

According to http://linux-sunxi.org/SID_Register_Guide "For Allwinner A83T and H3 the SID address space starts at 0x01c14000, and the e-fuses are at offset 0x200".
So I use this offset, since the sunxi_sid driver need the base address of e-fuses.

The easiest solution is to use 0x01c14200 since the other part of sid is not used and not known (A83T/H3 user manual doesnt give any information on all sid space, worse for A64 which reference SID only in memory map).

So probably for H3/A64/A83T, there will never any usage of the rest of the SID address space.

Regards
Corentin Labbe

^ permalink raw reply

* [PATCH 05/10] mm: replace get_vaddr_frames() write/force parameters with gup_flags
From: Jan Kara @ 2016-10-19  7:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161013002020.3062-6-lstoakes@gmail.com>

On Thu 13-10-16 01:20:15, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_vaddr_frames() and
> replaces them with a gup_flags parameter to make the use of FOLL_FORCE explicit
> in callers as use of this flag can result in surprising behaviour (and hence
> bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  drivers/gpu/drm/exynos/exynos_drm_g2d.c    |  3 ++-
>  drivers/media/platform/omap/omap_vout.c    |  2 +-
>  drivers/media/v4l2-core/videobuf2-memops.c |  6 +++++-
>  include/linux/mm.h                         |  2 +-
>  mm/frame_vector.c                          | 13 ++-----------
>  5 files changed, 11 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
> index aa92dec..fbd13fa 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
> @@ -488,7 +488,8 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
>  		goto err_free;
>  	}
>  
> -	ret = get_vaddr_frames(start, npages, true, true, g2d_userptr->vec);
> +	ret = get_vaddr_frames(start, npages, FOLL_FORCE | FOLL_WRITE,
> +		g2d_userptr->vec);
>  	if (ret != npages) {
>  		DRM_ERROR("failed to get user pages from userptr.\n");
>  		if (ret < 0)
> diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
> index e668dde..a31b95c 100644
> --- a/drivers/media/platform/omap/omap_vout.c
> +++ b/drivers/media/platform/omap/omap_vout.c
> @@ -214,7 +214,7 @@ static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
>  	if (!vec)
>  		return -ENOMEM;
>  
> -	ret = get_vaddr_frames(virtp, 1, true, false, vec);
> +	ret = get_vaddr_frames(virtp, 1, FOLL_WRITE, vec);
>  	if (ret != 1) {
>  		frame_vector_destroy(vec);
>  		return -EINVAL;
> diff --git a/drivers/media/v4l2-core/videobuf2-memops.c b/drivers/media/v4l2-core/videobuf2-memops.c
> index 3c3b517..1cd322e 100644
> --- a/drivers/media/v4l2-core/videobuf2-memops.c
> +++ b/drivers/media/v4l2-core/videobuf2-memops.c
> @@ -42,6 +42,10 @@ struct frame_vector *vb2_create_framevec(unsigned long start,
>  	unsigned long first, last;
>  	unsigned long nr;
>  	struct frame_vector *vec;
> +	unsigned int flags = FOLL_FORCE;
> +
> +	if (write)
> +		flags |= FOLL_WRITE;
>  
>  	first = start >> PAGE_SHIFT;
>  	last = (start + length - 1) >> PAGE_SHIFT;
> @@ -49,7 +53,7 @@ struct frame_vector *vb2_create_framevec(unsigned long start,
>  	vec = frame_vector_create(nr);
>  	if (!vec)
>  		return ERR_PTR(-ENOMEM);
> -	ret = get_vaddr_frames(start & PAGE_MASK, nr, write, true, vec);
> +	ret = get_vaddr_frames(start & PAGE_MASK, nr, flags, vec);
>  	if (ret < 0)
>  		goto out_destroy;
>  	/* We accept only complete set of PFNs */
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 27ab538..5ff084f6 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1305,7 +1305,7 @@ struct frame_vector {
>  struct frame_vector *frame_vector_create(unsigned int nr_frames);
>  void frame_vector_destroy(struct frame_vector *vec);
>  int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
> -		     bool write, bool force, struct frame_vector *vec);
> +		     unsigned int gup_flags, struct frame_vector *vec);
>  void put_vaddr_frames(struct frame_vector *vec);
>  int frame_vector_to_pages(struct frame_vector *vec);
>  void frame_vector_to_pfns(struct frame_vector *vec);
> diff --git a/mm/frame_vector.c b/mm/frame_vector.c
> index 81b6749..db77dcb 100644
> --- a/mm/frame_vector.c
> +++ b/mm/frame_vector.c
> @@ -11,10 +11,7 @@
>   * get_vaddr_frames() - map virtual addresses to pfns
>   * @start:	starting user address
>   * @nr_frames:	number of pages / pfns from start to map
> - * @write:	whether pages will be written to by the caller
> - * @force:	whether to force write access even if user mapping is
> - *		readonly. See description of the same argument of
> -		get_user_pages().
> + * @gup_flags:	flags modifying lookup behaviour
>   * @vec:	structure which receives pages / pfns of the addresses mapped.
>   *		It should have space for at least nr_frames entries.
>   *
> @@ -34,23 +31,17 @@
>   * This function takes care of grabbing mmap_sem as necessary.
>   */
>  int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
> -		     bool write, bool force, struct frame_vector *vec)
> +		     unsigned int gup_flags, struct frame_vector *vec)
>  {
>  	struct mm_struct *mm = current->mm;
>  	struct vm_area_struct *vma;
>  	int ret = 0;
>  	int err;
>  	int locked;
> -	unsigned int gup_flags = 0;
>  
>  	if (nr_frames == 0)
>  		return 0;
>  
> -	if (write)
> -		gup_flags |= FOLL_WRITE;
> -	if (force)
> -		gup_flags |= FOLL_FORCE;
> -
>  	if (WARN_ON_ONCE(nr_frames > vec->nr_allocated))
>  		nr_frames = vec->nr_allocated;
>  
> -- 
> 2.10.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply

* [PATCH 04/10] mm: replace get_user_pages_locked() write/force parameters with gup_flags
From: Jan Kara @ 2016-10-19  7:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161013002020.3062-5-lstoakes@gmail.com>

On Thu 13-10-16 01:20:14, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_user_pages_locked()
> and replaces them with a gup_flags parameter to make the use of FOLL_FORCE
> explicit in callers as use of this flag can result in surprising behaviour (and
> hence bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>

After our discussion the patch looks good to me. You can add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply

* [PATCH 04/10] mm: replace get_user_pages_locked() write/force parameters with gup_flags
From: Jan Kara @ 2016-10-19  7:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018135609.GA30025@lucifer>

On Tue 18-10-16 14:56:09, Lorenzo Stoakes wrote:
> On Tue, Oct 18, 2016 at 02:54:25PM +0200, Jan Kara wrote:
> > > @@ -1282,7 +1282,7 @@ long get_user_pages(unsigned long start, unsigned long nr_pages,
> > >  			    int write, int force, struct page **pages,
> > >  			    struct vm_area_struct **vmas);
> > >  long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
> > > -		    int write, int force, struct page **pages, int *locked);
> > > +		    unsigned int gup_flags, struct page **pages, int *locked);
> >
> > Hum, the prototype is inconsistent with e.g. __get_user_pages_unlocked()
> > where gup_flags come after **pages argument. Actually it makes more sense
> > to have it before **pages so that input arguments come first and output
> > arguments second but I don't care that much. But it definitely should be
> > consistent...
> 
> It was difficult to decide quite how to arrange parameters as there was
> inconsitency with regards to parameter ordering already - for example
> __get_user_pages() places its flags argument before pages whereas, as you note,
> __get_user_pages_unlocked() puts them afterwards.
> 
> I ended up compromising by trying to match the existing ordering of the function
> as much as I could by replacing write, force pairs with gup_flags in the same
> location (with the exception of get_user_pages_unlocked() which I felt should
> match __get_user_pages_unlocked() in signature) or if there was already a
> gup_flags parameter as in the case of __get_user_pages_unlocked() I simply
> removed the write, force pair and left the flags as the last parameter.
> 
> I am happy to rearrange parameters as needed, however I am not sure if it'd be
> worthwhile for me to do so (I am keen to try to avoid adding too much noise here
> :)
> 
> If we were to rearrange parameters for consistency I'd suggest adjusting
> __get_user_pages_unlocked() to put gup_flags before pages and do the same with
> get_user_pages_unlocked(), let me know what you think.

Yeah, ok. If the inconsistency is already there, just leave it for now.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply

* [PATCH] gpu: Remove depends on RESET_CONTROLLER when not a provider
From: Daniel Vetter @ 2016-10-19  7:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018205719.20575-1-stephen.boyd@linaro.org>

On Tue, Oct 18, 2016 at 01:57:19PM -0700, Stephen Boyd wrote:
> These GPU drivers only depend on the RESET_CONTROLLER config
> option to fix build issues that existed when there weren't stub
> reset APIs for reset controller consumers. Given that these
> drivers aren't providing any reset controllers themselves, they
> don't actually depend on the API to build (just to function) so
> they don't need to depend on it. Remove the dependency to fix
> recursive build errors like the following:
> 
> drivers/usb/Kconfig:39:error: recursive dependency detected!
> drivers/usb/Kconfig:39: symbol USB is selected by MOUSE_APPLETOUCH
> drivers/input/mouse/Kconfig:187:        symbol MOUSE_APPLETOUCH depends on INPUT
> drivers/input/Kconfig:8:        symbol INPUT is selected by VT
> drivers/tty/Kconfig:12: symbol VT is selected by FB_STI
> drivers/video/fbdev/Kconfig:674:        symbol FB_STI depends on FB
> drivers/video/fbdev/Kconfig:5:  symbol FB is selected by DRM_KMS_FB_HELPER
> drivers/gpu/drm/Kconfig:42:     symbol DRM_KMS_FB_HELPER is selected by DRM_KMS_CMA_HELPER
> drivers/gpu/drm/Kconfig:98:     symbol DRM_KMS_CMA_HELPER is selected by DRM_IMX
> drivers/gpu/drm/imx/Kconfig:1:  symbol DRM_IMX depends on IMX_IPUV3_CORE
> drivers/gpu/ipu-v3/Kconfig:1:   symbol IMX_IPUV3_CORE depends on RESET_CONTROLLER
> drivers/reset/Kconfig:4:        symbol RESET_CONTROLLER is selected by USB_CHIPIDEA
> drivers/usb/chipidea/Kconfig:1: symbol USB_CHIPIDEA depends on USB_EHCI_HCD
> drivers/usb/host/Kconfig:84:    symbol USB_EHCI_HCD depends on USB
> 
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: <dri-devel@lists.freedesktop.org>
> Cc: Heiko Stuebner <heiko@sntech.de>
> Cc: Mark Yao <mark.yao@rock-chips.com>
> Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
> Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org>

Yay for proper stubbing! Applied to drm-misc, thanks.
-Daniel

> ---
> 
> This has come out of some USB chipidea patches I've been working on. Please see
> http://lkml.kernel.org/r/20160907213519.27340-1-stephen.boyd at linaro.org for
> more details.
> 
> I'm resending with the ack from Philipp picked up.
> 
>  drivers/gpu/drm/rockchip/Kconfig | 1 -
>  drivers/gpu/drm/tegra/Kconfig    | 1 -
>  drivers/gpu/ipu-v3/Kconfig       | 1 -
>  3 files changed, 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
> index 3c58669a06ce..6f7f9c59f05b 100644
> --- a/drivers/gpu/drm/rockchip/Kconfig
> +++ b/drivers/gpu/drm/rockchip/Kconfig
> @@ -1,7 +1,6 @@
>  config DRM_ROCKCHIP
>  	tristate "DRM Support for Rockchip"
>  	depends on DRM && ROCKCHIP_IOMMU
> -	depends on RESET_CONTROLLER
>  	select DRM_GEM_CMA_HELPER
>  	select DRM_KMS_HELPER
>  	select DRM_PANEL
> diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig
> index 63ebb154b9b5..bbf5a4b7e0b6 100644
> --- a/drivers/gpu/drm/tegra/Kconfig
> +++ b/drivers/gpu/drm/tegra/Kconfig
> @@ -3,7 +3,6 @@ config DRM_TEGRA
>  	depends on ARCH_TEGRA || (ARM && COMPILE_TEST)
>  	depends on COMMON_CLK
>  	depends on DRM
> -	depends on RESET_CONTROLLER
>  	select DRM_KMS_HELPER
>  	select DRM_MIPI_DSI
>  	select DRM_PANEL
> diff --git a/drivers/gpu/ipu-v3/Kconfig b/drivers/gpu/ipu-v3/Kconfig
> index aefdff95356d..08766c6e7856 100644
> --- a/drivers/gpu/ipu-v3/Kconfig
> +++ b/drivers/gpu/ipu-v3/Kconfig
> @@ -1,7 +1,6 @@
>  config IMX_IPUV3_CORE
>  	tristate "IPUv3 core support"
>  	depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM
> -	depends on RESET_CONTROLLER
>  	select GENERIC_IRQ_CHIP
>  	help
>  	  Choose this if you have a i.MX5/6 system and want to use the Image
> -- 
> 2.10.0.297.gf6727b0
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply

* [PATCH v4] MMC: meson: initial support for GX platforms
From: Ulf Hansson @ 2016-10-19  7:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018195605.21145-1-khilman@baylibre.com>

On 18 October 2016 at 21:56, Kevin Hilman <khilman@baylibre.com> wrote:
> Initial support for the SD/eMMC controller in the Amlogic S905/GX*
> family of SoCs.
>
> Signed-off-by: Kevin Hilman <khilman@baylibre.com>
> ---
> Changes from v3:
> - better handling of clock error paths
> - rename to meson-gx to reflect support for newer SoCs
> - has now been tested with SDIO
>
>  .../devicetree/bindings/mmc/amlogic,meson-gxbb.txt |  33 +

Just realize this. You should split the DT doc into a separate patch,
such the DT maintainers can ack it.

Otherwise this looks good to me!

Kind regards
Uffe


>  MAINTAINERS                                        |   1 +
>  drivers/mmc/host/Kconfig                           |  10 +
>  drivers/mmc/host/Makefile                          |   1 +
>  drivers/mmc/host/meson-gx.c                        | 853 +++++++++++++++++++++
>  5 files changed, 898 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mmc/amlogic,meson-gxbb.txt
>  create mode 100644 drivers/mmc/host/meson-gx.c
>
> diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-gxbb.txt b/Documentation/devicetree/bindings/mmc/amlogic,meson-gxbb.txt
> new file mode 100644
> index 000000000000..a2fa9a1c26ae
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-gxbb.txt
> @@ -0,0 +1,33 @@
> +Amlogic SD / eMMC controller for S905/GXBB family SoCs
> +
> +The MMC 5.1 compliant host controller on Amlogic provides the
> +interface for SD, eMMC and SDIO devices.
> +
> +This file documents the properties in addition to those available in
> +the MMC core bindings, documented by mmc.txt.
> +
> +Required properties:
> +- compatible : contains one of:
> +  - "amlogic,meson-gx-mmc"
> +  - "amlogic,meson-gxbb-mmc"
> +  - "amlogic,meson-gxl-mmc"
> +  - "amlogic,meson-gxm-mmc"
> +- clocks     : A list of phandle + clock-specifier pairs for the clocks listed in clock-names.
> +- clock-names: Should contain the following:
> +       "core" - Main peripheral bus clock
> +       "clkin0" - Parent clock of internal mux
> +       "clkin1" - Other parent clock of internal mux
> +  The driver has an interal mux clock which switches between clkin0 and clkin1 depending on the
> +  clock rate requested by the MMC core.
> +
> +Example:
> +
> +       sd_emmc_a: mmc at 70000 {
> +               compatible = "amlogic,meson-gxbb-mmc";
> +               reg = <0x0 0x70000 0x0 0x2000>;
> +                interrupts = < GIC_SPI 216 IRQ_TYPE_EDGE_RISING>;
> +               clocks = <&clkc CLKID_SD_EMMC_A>, <&xtal>, <&clkc CLKID_FCLK_DIV2>;
> +               clock-names = "core", "clkin0", "clkin1";
> +               pinctrl-0 = <&emmc_pins>;
> +       };
> +
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1cd38a7e0064..73e8d64ec28c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1036,6 +1036,7 @@ F:        arch/arm/mach-meson/
>  F:     arch/arm/boot/dts/meson*
>  F:     arch/arm64/boot/dts/amlogic/
>  F:     drivers/pinctrl/meson/
> +F:     drivers/mmc/host/meson*
>  N:     meson
>
>  ARM/Annapurna Labs ALPINE ARCHITECTURE
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 5274f503a39a..5cf7ebaf1e8b 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -322,6 +322,16 @@ config MMC_SDHCI_IPROC
>
>           If unsure, say N.
>
> +config MMC_MESON_GX
> +       tristate "Amlogic S905/GX* SD/MMC Host Controller support"
> +       depends on ARCH_MESON && MMC
> +       help
> +         This selects support for the Amlogic SD/MMC Host Controller
> +         found on the S905/GX* family of SoCs.  This controller is
> +         MMC 5.1 compliant and supports SD, eMMC and SDIO interfaces.
> +
> +         If you have a controller with this interface, say Y here.
> +
>  config MMC_MOXART
>         tristate "MOXART SD/MMC Host Controller support"
>         depends on ARCH_MOXART && MMC
> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> index e2bdaaf43184..1c4852999ae4 100644
> --- a/drivers/mmc/host/Makefile
> +++ b/drivers/mmc/host/Makefile
> @@ -53,6 +53,7 @@ obj-$(CONFIG_MMC_JZ4740)      += jz4740_mmc.o
>  obj-$(CONFIG_MMC_VUB300)       += vub300.o
>  obj-$(CONFIG_MMC_USHC)         += ushc.o
>  obj-$(CONFIG_MMC_WMT)          += wmt-sdmmc.o
> +obj-$(CONFIG_MMC_MESON_GX)     += meson-gx.o
>  obj-$(CONFIG_MMC_MOXART)       += moxart-mmc.o
>  obj-$(CONFIG_MMC_SUNXI)                += sunxi-mmc.o
>  obj-$(CONFIG_MMC_USDHI6ROL0)   += usdhi6rol0.o
> diff --git a/drivers/mmc/host/meson-gx.c b/drivers/mmc/host/meson-gx.c
> new file mode 100644
> index 000000000000..fd3c40322b2d
> --- /dev/null
> +++ b/drivers/mmc/host/meson-gx.c
> @@ -0,0 +1,853 @@
> +/*
> + * Amlogic SD/eMMC driver for the GX/S905 family SoCs
> + *
> + * Copyright (c) 2016 BayLibre, SAS.
> + * Author: Kevin Hilman <khilman@baylibre.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of version 2 of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + * The full GNU General Public License is included in this distribution
> + * in the file called COPYING.
> + */
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/device.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/ioport.h>
> +#include <linux/spinlock.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/mmc/host.h>
> +#include <linux/mmc/mmc.h>
> +#include <linux/mmc/sdio.h>
> +#include <linux/mmc/slot-gpio.h>
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/regulator/consumer.h>
> +
> +#define DRIVER_NAME "meson-gxbb-mmc"
> +
> +#define SD_EMMC_CLOCK 0x0
> +#define   CLK_DIV_SHIFT 0
> +#define   CLK_DIV_WIDTH 6
> +#define   CLK_DIV_MASK 0x3f
> +#define   CLK_DIV_MAX 63
> +#define   CLK_SRC_SHIFT 6
> +#define   CLK_SRC_WIDTH 2
> +#define   CLK_SRC_MASK 0x3
> +#define   CLK_SRC_XTAL 0   /* external crystal */
> +#define   CLK_SRC_XTAL_RATE 24000000
> +#define   CLK_SRC_PLL 1    /* FCLK_DIV2 */
> +#define   CLK_SRC_PLL_RATE 1000000000
> +#define   CLK_PHASE_SHIFT 8
> +#define   CLK_PHASE_MASK 0x3
> +#define   CLK_PHASE_0 0
> +#define   CLK_PHASE_90 1
> +#define   CLK_PHASE_180 2
> +#define   CLK_PHASE_270 3
> +#define   CLK_ALWAYS_ON BIT(24)
> +
> +#define SD_EMMC_DElAY 0x4
> +#define SD_EMMC_ADJUST 0x8
> +#define SD_EMMC_CALOUT 0x10
> +#define SD_EMMC_START 0x40
> +#define   START_DESC_INIT BIT(0)
> +#define   START_DESC_BUSY BIT(1)
> +#define   START_DESC_ADDR_SHIFT 2
> +#define   START_DESC_ADDR_MASK (~0x3)
> +
> +#define SD_EMMC_CFG 0x44
> +#define   CFG_BUS_WIDTH_SHIFT 0
> +#define   CFG_BUS_WIDTH_MASK 0x3
> +#define   CFG_BUS_WIDTH_1 0x0
> +#define   CFG_BUS_WIDTH_4 0x1
> +#define   CFG_BUS_WIDTH_8 0x2
> +#define   CFG_DDR BIT(2)
> +#define   CFG_BLK_LEN_SHIFT 4
> +#define   CFG_BLK_LEN_MASK 0xf
> +#define   CFG_RESP_TIMEOUT_SHIFT 8
> +#define   CFG_RESP_TIMEOUT_MASK 0xf
> +#define   CFG_RC_CC_SHIFT 12
> +#define   CFG_RC_CC_MASK 0xf
> +#define   CFG_STOP_CLOCK BIT(22)
> +#define   CFG_CLK_ALWAYS_ON BIT(18)
> +#define   CFG_AUTO_CLK BIT(23)
> +
> +#define SD_EMMC_STATUS 0x48
> +#define   STATUS_BUSY BIT(31)
> +
> +#define SD_EMMC_IRQ_EN 0x4c
> +#define   IRQ_EN_MASK 0x3fff
> +#define   IRQ_RXD_ERR_SHIFT 0
> +#define   IRQ_RXD_ERR_MASK 0xff
> +#define   IRQ_TXD_ERR BIT(8)
> +#define   IRQ_DESC_ERR BIT(9)
> +#define   IRQ_RESP_ERR BIT(10)
> +#define   IRQ_RESP_TIMEOUT BIT(11)
> +#define   IRQ_DESC_TIMEOUT BIT(12)
> +#define   IRQ_END_OF_CHAIN BIT(13)
> +#define   IRQ_RESP_STATUS BIT(14)
> +#define   IRQ_SDIO BIT(15)
> +
> +#define SD_EMMC_CMD_CFG 0x50
> +#define SD_EMMC_CMD_ARG 0x54
> +#define SD_EMMC_CMD_DAT 0x58
> +#define SD_EMMC_CMD_RSP 0x5c
> +#define SD_EMMC_CMD_RSP1 0x60
> +#define SD_EMMC_CMD_RSP2 0x64
> +#define SD_EMMC_CMD_RSP3 0x68
> +
> +#define SD_EMMC_RXD 0x94
> +#define SD_EMMC_TXD 0x94
> +#define SD_EMMC_LAST_REG SD_EMMC_TXD
> +
> +#define SD_EMMC_CFG_BLK_SIZE 512 /* internal buffer max: 512 bytes */
> +#define SD_EMMC_CFG_RESP_TIMEOUT 256 /* in clock cycles */
> +#define SD_EMMC_CFG_CMD_GAP 16 /* in clock cycles */
> +#define MUX_CLK_NUM_PARENTS 2
> +
> +struct meson_host {
> +       struct  device          *dev;
> +       struct  mmc_host        *mmc;
> +       struct  mmc_request     *mrq;
> +       struct  mmc_command     *cmd;
> +
> +       spinlock_t lock;
> +       void __iomem *regs;
> +       int irq;
> +       u32 ocr_mask;
> +       struct clk *core_clk;
> +       struct clk_mux mux;
> +       struct clk *mux_clk;
> +       struct clk *mux_parent[MUX_CLK_NUM_PARENTS];
> +       unsigned long mux_parent_rate[MUX_CLK_NUM_PARENTS];
> +
> +       struct clk_divider cfg_div;
> +       struct clk *cfg_div_clk;
> +
> +       unsigned int bounce_buf_size;
> +       void *bounce_buf;
> +       dma_addr_t bounce_dma_addr;
> +
> +       bool vqmmc_enabled;
> +};
> +
> +struct sd_emmc_desc {
> +       u32 cmd_cfg;
> +       u32 cmd_arg;
> +       u32 cmd_data;
> +       u32 cmd_resp;
> +};
> +#define CMD_CFG_LENGTH_SHIFT 0
> +#define CMD_CFG_LENGTH_MASK 0x1ff
> +#define CMD_CFG_BLOCK_MODE BIT(9)
> +#define CMD_CFG_R1B BIT(10)
> +#define CMD_CFG_END_OF_CHAIN BIT(11)
> +#define CMD_CFG_TIMEOUT_SHIFT 12
> +#define CMD_CFG_TIMEOUT_MASK 0xf
> +#define CMD_CFG_NO_RESP BIT(16)
> +#define CMD_CFG_NO_CMD BIT(17)
> +#define CMD_CFG_DATA_IO BIT(18)
> +#define CMD_CFG_DATA_WR BIT(19)
> +#define CMD_CFG_RESP_NOCRC BIT(20)
> +#define CMD_CFG_RESP_128 BIT(21)
> +#define CMD_CFG_RESP_NUM BIT(22)
> +#define CMD_CFG_DATA_NUM BIT(23)
> +#define CMD_CFG_CMD_INDEX_SHIFT 24
> +#define CMD_CFG_CMD_INDEX_MASK 0x3f
> +#define CMD_CFG_ERROR BIT(30)
> +#define CMD_CFG_OWNER BIT(31)
> +
> +#define CMD_DATA_MASK (~0x3)
> +#define CMD_DATA_BIG_ENDIAN BIT(1)
> +#define CMD_DATA_SRAM BIT(0)
> +#define CMD_RESP_MASK (~0x1)
> +#define CMD_RESP_SRAM BIT(0)
> +
> +static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate)
> +{
> +       struct mmc_host *mmc = host->mmc;
> +       int ret = 0;
> +       u32 cfg;
> +
> +       if (clk_rate) {
> +               if (WARN_ON(clk_rate > mmc->f_max))
> +                       clk_rate = mmc->f_max;
> +               else if (WARN_ON(clk_rate < mmc->f_min))
> +                       clk_rate = mmc->f_min;
> +       }
> +
> +       if (clk_rate == mmc->actual_clock)
> +               return 0;
> +
> +       /* stop clock */
> +       cfg = readl(host->regs + SD_EMMC_CFG);
> +       if (!(cfg & CFG_STOP_CLOCK)) {
> +               cfg |= CFG_STOP_CLOCK;
> +               writel(cfg, host->regs + SD_EMMC_CFG);
> +       }
> +
> +       dev_dbg(host->dev, "change clock rate %u -> %lu\n",
> +               mmc->actual_clock, clk_rate);
> +
> +       if (clk_rate == 0) {
> +               mmc->actual_clock = 0;
> +               return 0;
> +       }
> +
> +       ret = clk_set_rate(host->cfg_div_clk, clk_rate);
> +       if (ret)
> +               dev_warn(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n",
> +                        clk_rate, ret);
> +       else if (clk_rate && clk_rate != clk_get_rate(host->cfg_div_clk))
> +               dev_warn(host->dev, "divider requested rate %lu != actual rate %lu: ret=%d\n",
> +                        clk_rate, clk_get_rate(host->cfg_div_clk), ret);
> +       else
> +               mmc->actual_clock = clk_rate;
> +
> +       /* (re)start clock, if non-zero */
> +       if (!ret && clk_rate) {
> +               cfg = readl(host->regs + SD_EMMC_CFG);
> +               cfg &= ~CFG_STOP_CLOCK;
> +               writel(cfg, host->regs + SD_EMMC_CFG);
> +       }
> +
> +       return ret;
> +}
> +
> +/*
> + * The SD/eMMC IP block has an internal mux and divider used for
> + * generating the MMC clock.  Use the clock framework to create and
> + * manage these clocks.
> + */
> +static int meson_mmc_clk_init(struct meson_host *host)
> +{
> +       struct clk_init_data init;
> +       char clk_name[32];
> +       int i, ret = 0;
> +       const char *mux_parent_names[MUX_CLK_NUM_PARENTS];
> +       unsigned int mux_parent_count = 0;
> +       const char *clk_div_parents[1];
> +       unsigned int f_min = UINT_MAX;
> +       u32 clk_reg, cfg;
> +
> +       /* get the mux parents */
> +       for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) {
> +               char name[16];
> +
> +               snprintf(name, sizeof(name), "clkin%d", i);
> +               host->mux_parent[i] = devm_clk_get(host->dev, name);
> +               if (IS_ERR(host->mux_parent[i])) {
> +                       ret = PTR_ERR(host->mux_parent[i]);
> +                       if (PTR_ERR(host->mux_parent[i]) != -EPROBE_DEFER)
> +                               dev_err(host->dev, "Missing clock %s\n", name);
> +                       host->mux_parent[i] = NULL;
> +                       return ret;
> +               }
> +
> +               host->mux_parent_rate[i] = clk_get_rate(host->mux_parent[i]);
> +               mux_parent_names[i] = __clk_get_name(host->mux_parent[i]);
> +               mux_parent_count++;
> +               if (host->mux_parent_rate[i] < f_min)
> +                       f_min = host->mux_parent_rate[i];
> +       }
> +
> +       /* cacluate f_min based on input clocks, and max divider value */
> +       if (f_min != UINT_MAX)
> +               f_min = DIV_ROUND_UP(CLK_SRC_XTAL_RATE, CLK_DIV_MAX);
> +       else
> +               f_min = 4000000;  /* default min: 400 MHz */
> +       host->mmc->f_min = f_min;
> +
> +       /* create the mux */
> +       snprintf(clk_name, sizeof(clk_name), "%s#mux", dev_name(host->dev));
> +       init.name = clk_name;
> +       init.ops = &clk_mux_ops;
> +       init.flags = 0;
> +       init.parent_names = mux_parent_names;
> +       init.num_parents = mux_parent_count;
> +
> +       host->mux.reg = host->regs + SD_EMMC_CLOCK;
> +       host->mux.shift = CLK_SRC_SHIFT;
> +       host->mux.mask = CLK_SRC_MASK;
> +       host->mux.flags = 0;
> +       host->mux.table = NULL;
> +       host->mux.hw.init = &init;
> +
> +       host->mux_clk = devm_clk_register(host->dev, &host->mux.hw);
> +       if (WARN_ON(IS_ERR(host->mux_clk)))
> +               return PTR_ERR(host->mux_clk);
> +
> +       /* create the divider */
> +       snprintf(clk_name, sizeof(clk_name), "%s#div", dev_name(host->dev));
> +       init.name = devm_kstrdup(host->dev, clk_name, GFP_KERNEL);
> +       init.ops = &clk_divider_ops;
> +       init.flags = CLK_SET_RATE_PARENT;
> +       clk_div_parents[0] = __clk_get_name(host->mux_clk);
> +       init.parent_names = clk_div_parents;
> +       init.num_parents = ARRAY_SIZE(clk_div_parents);
> +
> +       host->cfg_div.reg = host->regs + SD_EMMC_CLOCK;
> +       host->cfg_div.shift = CLK_DIV_SHIFT;
> +       host->cfg_div.width = CLK_DIV_WIDTH;
> +       host->cfg_div.hw.init = &init;
> +       host->cfg_div.flags = CLK_DIVIDER_ONE_BASED |
> +               CLK_DIVIDER_ROUND_CLOSEST | CLK_DIVIDER_ALLOW_ZERO;
> +
> +       host->cfg_div_clk = devm_clk_register(host->dev, &host->cfg_div.hw);
> +       if (WARN_ON(PTR_ERR_OR_ZERO(host->cfg_div_clk)))
> +               return PTR_ERR(host->cfg_div_clk);
> +
> +       /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */
> +       clk_reg = 0;
> +       clk_reg |= CLK_PHASE_180 << CLK_PHASE_SHIFT;
> +       clk_reg |= CLK_SRC_XTAL << CLK_SRC_SHIFT;
> +       clk_reg |= CLK_DIV_MAX << CLK_DIV_SHIFT;
> +       clk_reg &= ~CLK_ALWAYS_ON;
> +       writel(clk_reg, host->regs + SD_EMMC_CLOCK);
> +
> +       /* Ensure clock starts in "auto" mode, not "always on" */
> +       cfg = readl(host->regs + SD_EMMC_CFG);
> +       cfg &= ~CFG_CLK_ALWAYS_ON;
> +       cfg |= CFG_AUTO_CLK;
> +       writel(cfg, host->regs + SD_EMMC_CFG);
> +
> +       ret = clk_prepare_enable(host->cfg_div_clk);
> +       if (!ret)
> +               ret = meson_mmc_clk_set(host, f_min);
> +
> +       if (!ret)
> +               clk_disable_unprepare(host->cfg_div_clk);
> +
> +       return ret;
> +}
> +
> +static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> +       struct meson_host *host = mmc_priv(mmc);
> +       u32 bus_width;
> +       u32 val, orig;
> +
> +       /*
> +        * GPIO regulator, only controls switching between 1v8 and
> +        * 3v3, doesn't support MMC_POWER_OFF, MMC_POWER_ON.
> +        */
> +       switch (ios->power_mode) {
> +       case MMC_POWER_OFF:
> +               if (!IS_ERR(mmc->supply.vmmc))
> +                       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
> +
> +               if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) {
> +                       regulator_disable(mmc->supply.vqmmc);
> +                       host->vqmmc_enabled = false;
> +               }
> +
> +               break;
> +
> +       case MMC_POWER_UP:
> +               if (!IS_ERR(mmc->supply.vmmc))
> +                       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
> +               break;
> +
> +       case MMC_POWER_ON:
> +               if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) {
> +                       int ret = regulator_enable(mmc->supply.vqmmc);
> +
> +                       if (ret < 0)
> +                               dev_err(mmc_dev(mmc),
> +                                       "failed to enable vqmmc regulator\n");
> +                       else
> +                               host->vqmmc_enabled = true;
> +               }
> +
> +               break;
> +       }
> +
> +
> +       meson_mmc_clk_set(host, ios->clock);
> +
> +       /* Bus width */
> +       val = readl(host->regs + SD_EMMC_CFG);
> +       switch (ios->bus_width) {
> +       case MMC_BUS_WIDTH_1:
> +               bus_width = CFG_BUS_WIDTH_1;
> +               break;
> +       case MMC_BUS_WIDTH_4:
> +               bus_width = CFG_BUS_WIDTH_4;
> +               break;
> +       case MMC_BUS_WIDTH_8:
> +               bus_width = CFG_BUS_WIDTH_8;
> +               break;
> +       default:
> +               dev_err(host->dev, "Invalid ios->bus_width: %u.  Setting to 4.\n",
> +                       ios->bus_width);
> +               bus_width = CFG_BUS_WIDTH_4;
> +               return;
> +       }
> +
> +       val = readl(host->regs + SD_EMMC_CFG);
> +       orig = val;
> +
> +       val &= ~(CFG_BUS_WIDTH_MASK << CFG_BUS_WIDTH_SHIFT);
> +       val |= bus_width << CFG_BUS_WIDTH_SHIFT;
> +
> +       val &= ~(CFG_BLK_LEN_MASK << CFG_BLK_LEN_SHIFT);
> +       val |= ilog2(SD_EMMC_CFG_BLK_SIZE) << CFG_BLK_LEN_SHIFT;
> +
> +       val &= ~(CFG_RESP_TIMEOUT_MASK << CFG_RESP_TIMEOUT_SHIFT);
> +       val |= ilog2(SD_EMMC_CFG_RESP_TIMEOUT) << CFG_RESP_TIMEOUT_SHIFT;
> +
> +       val &= ~(CFG_RC_CC_MASK << CFG_RC_CC_SHIFT);
> +       val |= ilog2(SD_EMMC_CFG_CMD_GAP) << CFG_RC_CC_SHIFT;
> +
> +       writel(val, host->regs + SD_EMMC_CFG);
> +
> +       if (val != orig)
> +               dev_dbg(host->dev, "%s: SD_EMMC_CFG: 0x%08x -> 0x%08x\n",
> +                       __func__, orig, val);
> +}
> +
> +static int meson_mmc_request_done(struct mmc_host *mmc, struct mmc_request *mrq)
> +{
> +       struct meson_host *host = mmc_priv(mmc);
> +
> +       WARN_ON(host->mrq != mrq);
> +
> +       host->mrq = NULL;
> +       host->cmd = NULL;
> +       mmc_request_done(host->mmc, mrq);
> +
> +       return 0;
> +}
> +
> +static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
> +{
> +       struct meson_host *host = mmc_priv(mmc);
> +       struct sd_emmc_desc *desc, desc_tmp;
> +       u32 cfg;
> +       u8 blk_len, cmd_cfg_timeout;
> +       unsigned int xfer_bytes = 0;
> +
> +       /* Setup descriptors */
> +       dma_rmb();
> +       desc = &desc_tmp;
> +       memset(desc, 0, sizeof(struct sd_emmc_desc));
> +
> +       desc->cmd_cfg |= (cmd->opcode & CMD_CFG_CMD_INDEX_MASK) <<
> +               CMD_CFG_CMD_INDEX_SHIFT;
> +       desc->cmd_cfg |= CMD_CFG_OWNER;  /* owned by CPU */
> +       desc->cmd_arg = cmd->arg;
> +
> +       /* Response */
> +       if (cmd->flags & MMC_RSP_PRESENT) {
> +               desc->cmd_cfg &= ~CMD_CFG_NO_RESP;
> +               if (cmd->flags & MMC_RSP_136)
> +                       desc->cmd_cfg |= CMD_CFG_RESP_128;
> +               desc->cmd_cfg |= CMD_CFG_RESP_NUM;
> +               desc->cmd_resp = 0;
> +
> +               if (!(cmd->flags & MMC_RSP_CRC))
> +                       desc->cmd_cfg |= CMD_CFG_RESP_NOCRC;
> +
> +               if (cmd->flags & MMC_RSP_BUSY)
> +                       desc->cmd_cfg |= CMD_CFG_R1B;
> +       } else {
> +               desc->cmd_cfg |= CMD_CFG_NO_RESP;
> +       }
> +
> +       /* data? */
> +       if (cmd->data) {
> +               desc->cmd_cfg |= CMD_CFG_DATA_IO;
> +               if (cmd->data->blocks > 1) {
> +                       desc->cmd_cfg |= CMD_CFG_BLOCK_MODE;
> +                       desc->cmd_cfg |=
> +                               (cmd->data->blocks & CMD_CFG_LENGTH_MASK) <<
> +                               CMD_CFG_LENGTH_SHIFT;
> +
> +                       /* check if block-size matches, if not update */
> +                       cfg = readl(host->regs + SD_EMMC_CFG);
> +                       blk_len = cfg & (CFG_BLK_LEN_MASK << CFG_BLK_LEN_SHIFT);
> +                       blk_len >>= CFG_BLK_LEN_SHIFT;
> +                       if (blk_len != ilog2(cmd->data->blksz)) {
> +                               dev_warn(host->dev, "%s: update blk_len %d -> %d\n",
> +                                       __func__, blk_len,
> +                                        ilog2(cmd->data->blksz));
> +                               blk_len = ilog2(cmd->data->blksz);
> +                               cfg &= ~(CFG_BLK_LEN_MASK << CFG_BLK_LEN_SHIFT);
> +                               cfg |= blk_len << CFG_BLK_LEN_SHIFT;
> +                               writel(cfg, host->regs + SD_EMMC_CFG);
> +                       }
> +               } else {
> +                       desc->cmd_cfg &= ~CMD_CFG_BLOCK_MODE;
> +                       desc->cmd_cfg |=
> +                               (cmd->data->blksz & CMD_CFG_LENGTH_MASK) <<
> +                               CMD_CFG_LENGTH_SHIFT;
> +               }
> +
> +               cmd->data->bytes_xfered = 0;
> +               xfer_bytes = cmd->data->blksz * cmd->data->blocks;
> +               if (cmd->data->flags & MMC_DATA_WRITE) {
> +                       desc->cmd_cfg |= CMD_CFG_DATA_WR;
> +                       WARN_ON(xfer_bytes > host->bounce_buf_size);
> +                       sg_copy_to_buffer(cmd->data->sg, cmd->data->sg_len,
> +                                         host->bounce_buf, xfer_bytes);
> +                       cmd->data->bytes_xfered = xfer_bytes;
> +                       dma_wmb();
> +               } else {
> +                       desc->cmd_cfg &= ~CMD_CFG_DATA_WR;
> +               }
> +
> +               if (xfer_bytes > 0) {
> +                       desc->cmd_cfg &= ~CMD_CFG_DATA_NUM;
> +                       desc->cmd_data = host->bounce_dma_addr & CMD_DATA_MASK;
> +               } else {
> +                       /* write data to data_addr */
> +                       desc->cmd_cfg |= CMD_CFG_DATA_NUM;
> +                       desc->cmd_data = 0;
> +               }
> +
> +               cmd_cfg_timeout = 12;
> +       } else {
> +               desc->cmd_cfg &= ~CMD_CFG_DATA_IO;
> +               cmd_cfg_timeout = 10;
> +       }
> +       desc->cmd_cfg |= (cmd_cfg_timeout & CMD_CFG_TIMEOUT_MASK) <<
> +               CMD_CFG_TIMEOUT_SHIFT;
> +
> +       host->cmd = cmd;
> +
> +       /* Last descriptor */
> +       desc->cmd_cfg |= CMD_CFG_END_OF_CHAIN;
> +       writel(desc->cmd_cfg, host->regs + SD_EMMC_CMD_CFG);
> +       writel(desc->cmd_data, host->regs + SD_EMMC_CMD_DAT);
> +       writel(desc->cmd_resp, host->regs + SD_EMMC_CMD_RSP);
> +       wmb(); /* ensure descriptor is written before kicked */
> +       writel(desc->cmd_arg, host->regs + SD_EMMC_CMD_ARG);
> +}
> +
> +static void meson_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> +{
> +       struct meson_host *host = mmc_priv(mmc);
> +
> +       WARN_ON(host->mrq != NULL);
> +
> +       /* Stop execution */
> +       writel(0, host->regs + SD_EMMC_START);
> +
> +       /* clear, ack, enable all interrupts */
> +       writel(0, host->regs + SD_EMMC_IRQ_EN);
> +       writel(IRQ_EN_MASK, host->regs + SD_EMMC_STATUS);
> +       writel(IRQ_EN_MASK, host->regs + SD_EMMC_IRQ_EN);
> +
> +       host->mrq = mrq;
> +
> +       if (mrq->sbc)
> +               meson_mmc_start_cmd(mmc, mrq->sbc);
> +       else
> +               meson_mmc_start_cmd(mmc, mrq->cmd);
> +}
> +
> +static int meson_mmc_read_resp(struct mmc_host *mmc, struct mmc_command *cmd)
> +{
> +       struct meson_host *host = mmc_priv(mmc);
> +
> +       if (cmd->flags & MMC_RSP_136) {
> +               cmd->resp[0] = readl(host->regs + SD_EMMC_CMD_RSP3);
> +               cmd->resp[1] = readl(host->regs + SD_EMMC_CMD_RSP2);
> +               cmd->resp[2] = readl(host->regs + SD_EMMC_CMD_RSP1);
> +               cmd->resp[3] = readl(host->regs + SD_EMMC_CMD_RSP);
> +       } else if (cmd->flags & MMC_RSP_PRESENT) {
> +               cmd->resp[0] = readl(host->regs + SD_EMMC_CMD_RSP);
> +       }
> +
> +       return 0;
> +}
> +
> +static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
> +{
> +       struct meson_host *host = dev_id;
> +       struct mmc_request *mrq;
> +       struct mmc_command *cmd = host->cmd;
> +       u32 irq_en, status, raw_status;
> +       irqreturn_t ret = IRQ_HANDLED;
> +
> +       if (WARN_ON(!host))
> +               return IRQ_NONE;
> +
> +       mrq = host->mrq;
> +
> +       if (WARN_ON(!mrq))
> +               return IRQ_NONE;
> +
> +       if (WARN_ON(!cmd))
> +               return IRQ_NONE;
> +
> +       spin_lock(&host->lock);
> +       irq_en = readl(host->regs + SD_EMMC_IRQ_EN);
> +       raw_status = readl(host->regs + SD_EMMC_STATUS);
> +       status = raw_status & irq_en;
> +
> +       if (!status) {
> +               dev_warn(host->dev, "Spurious IRQ! status=0x%08x, irq_en=0x%08x\n",
> +                        raw_status, irq_en);
> +               ret = IRQ_NONE;
> +               goto out;
> +       }
> +
> +       cmd->error = 0;
> +       if (status & IRQ_RXD_ERR_MASK) {
> +               dev_dbg(host->dev, "Unhandled IRQ: RXD error\n");
> +               cmd->error = -EILSEQ;
> +       }
> +       if (status & IRQ_TXD_ERR) {
> +               dev_dbg(host->dev, "Unhandled IRQ: TXD error\n");
> +               cmd->error = -EILSEQ;
> +       }
> +       if (status & IRQ_DESC_ERR)
> +               dev_dbg(host->dev, "Unhandled IRQ: Descriptor error\n");
> +       if (status & IRQ_RESP_ERR) {
> +               dev_dbg(host->dev, "Unhandled IRQ: Response error\n");
> +               cmd->error = -EILSEQ;
> +       }
> +       if (status & IRQ_RESP_TIMEOUT) {
> +               dev_dbg(host->dev, "Unhandled IRQ: Response timeout\n");
> +               cmd->error = -ETIMEDOUT;
> +       }
> +       if (status & IRQ_DESC_TIMEOUT) {
> +               dev_dbg(host->dev, "Unhandled IRQ: Descriptor timeout\n");
> +               cmd->error = -ETIMEDOUT;
> +       }
> +       if (status & IRQ_SDIO)
> +               dev_dbg(host->dev, "Unhandled IRQ: SDIO.\n");
> +
> +       if (status & (IRQ_END_OF_CHAIN | IRQ_RESP_STATUS))
> +               ret = IRQ_WAKE_THREAD;
> +       else  {
> +               dev_warn(host->dev, "Unknown IRQ! status=0x%04x: MMC CMD%u arg=0x%08x flags=0x%08x stop=%d\n",
> +                        status, cmd->opcode, cmd->arg,
> +                        cmd->flags, mrq->stop ? 1 : 0);
> +               if (cmd->data) {
> +                       struct mmc_data *data = cmd->data;
> +
> +                       dev_warn(host->dev, "\tblksz %u blocks %u flags 0x%08x (%s%s)",
> +                                data->blksz, data->blocks, data->flags,
> +                                data->flags & MMC_DATA_WRITE ? "write" : "",
> +                                data->flags & MMC_DATA_READ ? "read" : "");
> +               }
> +       }
> +
> +out:
> +       /* ack all (enabled) interrupts */
> +       writel(status, host->regs + SD_EMMC_STATUS);
> +
> +       if (ret == IRQ_HANDLED) {
> +               meson_mmc_read_resp(host->mmc, cmd);
> +               meson_mmc_request_done(host->mmc, cmd->mrq);
> +       }
> +
> +       spin_unlock(&host->lock);
> +       return ret;
> +}
> +
> +static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
> +{
> +       struct meson_host *host = dev_id;
> +       struct mmc_request *mrq = host->mrq;
> +       struct mmc_command *cmd = host->cmd;
> +       struct mmc_data *data;
> +       unsigned int xfer_bytes;
> +       int ret = IRQ_HANDLED;
> +
> +       if (WARN_ON(!mrq))
> +               ret = IRQ_NONE;
> +
> +       if (WARN_ON(!cmd))
> +               ret = IRQ_NONE;
> +
> +       data = cmd->data;
> +       if (data) {
> +               xfer_bytes = data->blksz * data->blocks;
> +               if (data->flags & MMC_DATA_READ) {
> +                       WARN_ON(xfer_bytes > host->bounce_buf_size);
> +                       sg_copy_from_buffer(data->sg, data->sg_len,
> +                                           host->bounce_buf, xfer_bytes);
> +                       data->bytes_xfered = xfer_bytes;
> +               }
> +       }
> +
> +       meson_mmc_read_resp(host->mmc, cmd);
> +       if (!data || !data->stop || mrq->sbc)
> +               meson_mmc_request_done(host->mmc, mrq);
> +       else
> +               meson_mmc_start_cmd(host->mmc, data->stop);
> +
> +       return ret;
> +}
> +
> +/*
> + * NOTE: we only need this until the GPIO/pinctrl driver can handle
> + * interrupts.  For now, the MMC core will use this for polling.
> + */
> +static int meson_mmc_get_cd(struct mmc_host *mmc)
> +{
> +       int status = mmc_gpio_get_cd(mmc);
> +
> +       if (status == -ENOSYS)
> +               return 1; /* assume present */
> +
> +       return status;
> +}
> +
> +static const struct mmc_host_ops meson_mmc_ops = {
> +       .request        = meson_mmc_request,
> +       .set_ios        = meson_mmc_set_ios,
> +       .get_cd         = meson_mmc_get_cd,
> +};
> +
> +static int meson_mmc_probe(struct platform_device *pdev)
> +{
> +       struct resource *res;
> +       struct meson_host *host;
> +       struct mmc_host *mmc;
> +       int ret;
> +
> +       mmc = mmc_alloc_host(sizeof(struct meson_host), &pdev->dev);
> +       if (!mmc)
> +               return -ENOMEM;
> +       host = mmc_priv(mmc);
> +       host->mmc = mmc;
> +       host->dev = &pdev->dev;
> +       dev_set_drvdata(&pdev->dev, host);
> +
> +       spin_lock_init(&host->lock);
> +
> +       /* Get regulators and the supported OCR mask */
> +       host->vqmmc_enabled = false;
> +       ret = mmc_regulator_get_supply(mmc);
> +       if (ret == -EPROBE_DEFER)
> +               goto free_host;
> +
> +       ret = mmc_of_parse(mmc);
> +       if (ret) {
> +               dev_warn(&pdev->dev, "error parsing DT: %d\n", ret);
> +               goto free_host;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       host->regs = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(host->regs)) {
> +               ret = PTR_ERR(host->regs);
> +               goto free_host;
> +       }
> +
> +       host->irq = platform_get_irq(pdev, 0);
> +       if (host->irq == 0) {
> +               dev_err(&pdev->dev, "failed to get interrupt resource.\n");
> +               ret = -EINVAL;
> +               goto free_host;
> +       }
> +
> +       host->core_clk = devm_clk_get(&pdev->dev, "core");
> +       if (IS_ERR(host->core_clk)) {
> +               ret = PTR_ERR(host->core_clk);
> +               goto free_host;
> +       }
> +
> +       ret = clk_prepare_enable(host->core_clk);
> +       if (ret)
> +               goto free_host;
> +
> +       ret = meson_mmc_clk_init(host);
> +       if (ret)
> +               goto free_host;
> +
> +       /* Stop execution */
> +       writel(0, host->regs + SD_EMMC_START);
> +
> +       /* clear, ack, enable all interrupts */
> +       writel(0, host->regs + SD_EMMC_IRQ_EN);
> +       writel(IRQ_EN_MASK, host->regs + SD_EMMC_STATUS);
> +
> +       ret = devm_request_threaded_irq(&pdev->dev, host->irq,
> +                                       meson_mmc_irq, meson_mmc_irq_thread,
> +                                       IRQF_SHARED, DRIVER_NAME, host);
> +       if (ret)
> +               goto free_host;
> +
> +       /* data bounce buffer */
> +       host->bounce_buf_size = SZ_512K;
> +       host->bounce_buf =
> +               dma_alloc_coherent(host->dev, host->bounce_buf_size,
> +                                  &host->bounce_dma_addr, GFP_KERNEL);
> +       if (host->bounce_buf == NULL) {
> +               dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
> +               ret = -ENOMEM;
> +               goto free_host;
> +       }
> +
> +       mmc->ops = &meson_mmc_ops;
> +       mmc_add_host(mmc);
> +
> +       return 0;
> +
> +free_host:
> +       clk_disable_unprepare(host->cfg_div_clk);
> +       clk_disable_unprepare(host->core_clk);
> +       mmc_free_host(mmc);
> +       return ret;
> +}
> +
> +static int meson_mmc_remove(struct platform_device *pdev)
> +{
> +       struct meson_host *host = dev_get_drvdata(&pdev->dev);
> +
> +       if (WARN_ON(!host))
> +               return 0;
> +
> +       if (host->bounce_buf)
> +               dma_free_coherent(host->dev, host->bounce_buf_size,
> +                                 host->bounce_buf, host->bounce_dma_addr);
> +
> +       clk_disable_unprepare(host->cfg_div_clk);
> +       clk_disable_unprepare(host->core_clk);
> +
> +       mmc_free_host(host->mmc);
> +       return 0;
> +}
> +
> +static const struct of_device_id meson_mmc_of_match[] = {
> +       { .compatible = "amlogic,meson-gx-mmc", },
> +       { .compatible = "amlogic,meson-gxbb-mmc", },
> +       { .compatible = "amlogic,meson-gxl-mmc", },
> +       { .compatible = "amlogic,meson-gxm-mmc", },
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, meson_mmc_of_match);
> +
> +static struct platform_driver meson_mmc_driver = {
> +       .probe          = meson_mmc_probe,
> +       .remove         = meson_mmc_remove,
> +       .driver         = {
> +               .name = DRIVER_NAME,
> +               .of_match_table = of_match_ptr(meson_mmc_of_match),
> +       },
> +};
> +
> +module_platform_driver(meson_mmc_driver);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_DESCRIPTION("Amlogic S905/GXBB SD/eMMC driver");
> +MODULE_AUTHOR("Kevin Hilman <khilman@baylibre.com>");
> +MODULE_LICENSE("GPL v2");
> +
> --
> 2.9.3
>

^ permalink raw reply

* how to enable suspend to ram for arm-64 bits
From: yoma sophian @ 2016-10-19  7:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <95484b8f-58de-3588-ac91-5ec21e66ab05@arm.com>

hi Sudeep:

2016-10-18 18:59 GMT+08:00 Sudeep Holla <sudeep.holla@arm.com>:
>
>
> On 18/10/16 11:45, Mark Rutland wrote:
>>
>> On Tue, Oct 18, 2016 at 12:00:02PM +0200, Pavel Machek wrote:
>>>>>
>>>>> b. in arm64, if some platform has its own suspend flow,  couldn't it
>>>>> adopts arm/match-xxx to register its own global suspend method?
>>>>
>>>>
>>>> No, PSCI is highly recommended.
>>>
>>>
>>> Relying on firmware for suspend on x86 was a great disaster, lets not
>>> repeat
>>> that mistake. arm32 has better powermanagement than x86 ever will (see
>>> Nokia N900
>>> for example) -- feel free to copy that code from arm32.
>>
>>
>> Quite frankly, copying hundreds of lines of board-specific code
>> (including assembly that won't compile) is unlikely to help.
>>
>> So far arm64 requires well-defined, standard, reusable interfaces (e.g.
>> PSCI). That cleanly separates concerns (e.g. anyone can implement the
>> backend without mandatory changes to the kernel), and keeps things
>> maintainable.
>>
>> ARM publishes and maintains the ARM Trusted Firmware [1], which anyone
>> can use and build atop of. It's open source (three-clause BSD with DCO),
>> and accepts board ports. You can have a completely open stack,
>> regardless of whether part of that stack is firmware.
>>
>
> I think you missed to add the link[1]
> [1] https://github.com/ARM-software/arm-trusted-firmware
thanks for your kind information ^^

^ permalink raw reply

* [PATCH 2/2] iommu/mediatek: Convert M4Uv1 to iommu_fwspec
From: Honghui Zhang @ 2016-10-19  7:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <a40dbcc1ff40bf09483316354d2fdcb2d432eb81.1476704508.git.robin.murphy@arm.com>

On Mon, 2016-10-17 at 12:49 +0100, Robin Murphy wrote:
> Our per-device data consists of the M4U instance and firmware-provided
> list of LARB IDs, which is a perfect fit for the generic iommu_fwspec
> machinery. Use that directly instead of the custom archdata code - while
> we can't rely on the of_xlate() mechanism to initialise things until the
> 32-bit ARM DMA code learns about groups and default domains, it still
> results in a reasonable simplification overall.
> 
> CC: Honghui Zhang <honghui.zhang@mediatek.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>

Thanks Robin.
Tested-by: Honghui Zhang <honghui.zhang@mediatek.com>

> ---
>  drivers/iommu/mtk_iommu.h    |  6 ---
>  drivers/iommu/mtk_iommu_v1.c | 95 +++++++++++++++++---------------------------
>  2 files changed, 36 insertions(+), 65 deletions(-)
> 

^ permalink raw reply

* [PATCH] Revert "gpio/mvebu: convert to use irq_domain_add_simple()"
From: Gregory CLEMENT @ 2016-10-19  7:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476831396-24359-1-git-send-email-jgunthorpe@obsidianresearch.com>

Hi Jason,
 
 On mer., oct. 19 2016, Jason Gunthorpe <jgunthorpe@obsidianresearch.com> wrote:

> This reverts commit ce931f571b6dcf8534e8740e8cd16565cf362536.
>
> The only difference betwen _simple and _legacy is that _simple
> calls irq_alloc_descs, however mvebu_gpio_probe already called
> irq_alloc_descs a few lines above.

And what about removing the irq_alloc_descs ?

Going back to use the _legacy version seems wrong for me.

Gregory

>
> This fixes these kernel error messages from the double call
> to irq_alloc_descs:
>
>  irq: Cannot allocate irq_descs @ IRQ34, assuming pre-allocated
>  irq: Cannot allocate irq_descs @ IRQ66, assuming pre-allocated
>
> Cc: Rob Herring <rob.herring@calxeda.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> Cc: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> Cc: Andrew Lunn <andrew@lunn.ch>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Fixes: ce931f571b6d ("gpio/mvebu: convert to use irq_domain_add_simple()")
> Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
> ---
>  drivers/gpio/gpio-mvebu.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
> index cd5dc27320a2..2e0c8d8b7792 100644
> --- a/drivers/gpio/gpio-mvebu.c
> +++ b/drivers/gpio/gpio-mvebu.c
> @@ -807,8 +807,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
>  			       IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
>  
>  	/* Setup irq domain on top of the generic chip. */
> -	mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio,
> -					       mvchip->irqbase,
> +	mvchip->domain = irq_domain_add_legacy(np, mvchip->chip.ngpio,
> +					       mvchip->irqbase, 0,
>  					       &irq_domain_simple_ops,
>  					       mvchip);
>  	if (!mvchip->domain) {
> -- 
> 2.1.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* [PATCH] ARM: dts: am335x-baltos-ir5221: use both musb channels in host mode
From: yegorslists at googlemail.com @ 2016-10-19  7:09 UTC (permalink / raw)
  To: linux-arm-kernel

From: Yegor Yefremov <yegorslists@googlemail.com>

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
---
 arch/arm/boot/dts/am335x-baltos-ir5221.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/am335x-baltos-ir5221.dts b/arch/arm/boot/dts/am335x-baltos-ir5221.dts
index d0faa7b..f599350 100644
--- a/arch/arm/boot/dts/am335x-baltos-ir5221.dts
+++ b/arch/arm/boot/dts/am335x-baltos-ir5221.dts
@@ -114,7 +114,7 @@
 
 &usb1 {
 	status = "okay";
-	dr_mode = "otg";
+	dr_mode = "host";
 };
 
 &cpsw_emac0 {
-- 
2.1.4

^ permalink raw reply related

* [PATCH v9 2/2] ARM: dts: add TOPEET itop elite based board
From: Krzysztof Kozlowski @ 2016-10-19  5:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <58DB0A67-6C74-409B-80B2-9F02492D3A55@soulik.info>

On Wed, Oct 19, 2016 at 4:15 AM, Ayaka <ayaka@soulik.info> wrote:
>
>
> ??? iPad ??
>
>> Krzysztof Kozlowski <krzk@kernel.org> ? 2016?10?19? ??1:37 ???
>>
>>> On Wed, Oct 19, 2016 at 01:18:49AM +0800, Randy Li wrote:
>>> The TOPEET itop exynos 4412 have three versions base board. The
>>> Elite version is the cheap one without too much peripheral devices
>>> on it.
>>>
>>> Currently supported are serial console, wired networking(USB),
>>> USB OTG in peripheral mode, USB host, SD storage, GPIO buttons,
>>> PWM beeper, ADC and LEDs. The WM8960 analog audio codec is also
>>> enabled.
>>>
>>> The FIMC is not used for camera currently, I enabled it just for a
>>> colorspace converter.
>>>
>>> Signed-off-by: Randy Li <ayaka@soulik.info>
>>> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
>>
>> Thanks, applied, with missing Rob's ack, minor changes in commit msg and
>> fix in pin function (you used macro for pull up/down instead of
>> function).
> The last time I saw the other dts have applied that, but they are not now. A header file is also missed reported by kbuild, but I didn't meet that.

I wonder why I didn't encounter the build error on my machine... This
needs a follow up fix.

Best regards,
Krzysztof

^ permalink raw reply

* [PATCH 3/3] ARM: socfpga: defconfig: enable qspi
From: Steffen Trumtrar @ 2016-10-19  5:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.02.1610181600570.27375@linux-builds1>

On Tue, Oct 18, 2016 at 04:03:01PM -0500, Dinh Nguyen wrote:
> On Tue, 18 Oct 2016, Steffen Trumtrar wrote:
> 
> > Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
> > ---
> >  arch/arm/configs/socfpga_defconfig | 3 +++
> >  1 file changed, 3 insertions(+)
> > 
> > diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig
> > index 9f84be5b3ac5..466050663c86 100644
> > --- a/arch/arm/configs/socfpga_defconfig
> > +++ b/arch/arm/configs/socfpga_defconfig
> 
> Thanks Steffen, all patches applied. I'll fixup the commit header for the DTS
> patches. The arm-soc maintainers prefer the DTS patches to be:
> 
> "ARM: dts: <platform>"

Oops.

Thanks,
Steffen


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* [PATCH 4/4] i2c: digicolor: Fix module autoload
From: Baruch Siach @ 2016-10-19  5:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476824508-4679-5-git-send-email-javier@osg.samsung.com>

Hi Javier Martinez Canillas,

On Tue, Oct 18, 2016 at 06:01:48PM -0300, Javier Martinez Canillas wrote:
> If the driver is built as a module, autoload won't work because the module
> alias information is not filled. So user-space can't match the registered
> device with the corresponding module.
> 
> Export the module alias information using the MODULE_DEVICE_TABLE() macro.
> 
> Before this patch:
> 
> $ modinfo drivers/i2c/busses/i2c-digicolor.ko | grep alias
> $
> 
> After this patch:
> 
> $ modinfo drivers/i2c/busses/i2c-digicolor.ko | grep alias
> alias:          of:N*T*Ccnxt,cx92755-i2cC*
> alias:          of:N*T*Ccnxt,cx92755-i2c
> 
> Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>

Acked-by: Baruch Siach <baruch@tkos.co.il>

Thanks,
baruch

>  drivers/i2c/busses/i2c-digicolor.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c
> index 9604024e0eb0..49f2084f7bb5 100644
> --- a/drivers/i2c/busses/i2c-digicolor.c
> +++ b/drivers/i2c/busses/i2c-digicolor.c
> @@ -368,6 +368,7 @@ static const struct of_device_id dc_i2c_match[] = {
>  	{ .compatible = "cnxt,cx92755-i2c" },
>  	{ },
>  };
> +MODULE_DEVICE_TABLE(of, dc_i2c_match);
>  
>  static struct platform_driver dc_i2c_driver = {
>  	.probe   = dc_i2c_probe,

-- 
     http://baruch.siach.name/blog/                  ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
   - baruch at tkos.co.il - tel: +972.52.368.4656, http://www.tkos.co.il -

^ permalink raw reply

* [PATCH 4/9] regulator: lp873x: Add support for populating input supply
From: Lokesh Vutla @ 2016-10-19  4:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018142743.xfgjuaw4wlssmoxq@rob-hp-laptop>



On Tuesday 18 October 2016 07:57 PM, Rob Herring wrote:
> On Fri, Oct 14, 2016 at 06:30:28PM +0530, Lokesh Vutla wrote:
>> In order to have a proper topology of regulators for a platform, each
>> registering regulator needs to populate supply_name field for identifying
>> its supply's name. Add supply_name field for lp873x regulators.
>>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> Cc: Keerthy <j-keerthy@ti.com>
>> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
>> ---
>>  Documentation/devicetree/bindings/mfd/lp873x.txt | 8 ++++++++
>>  drivers/regulator/lp873x-regulator.c             | 1 +
>>  2 files changed, 9 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/lp873x.txt b/Documentation/devicetree/bindings/mfd/lp873x.txt
>> index 52766c2..936cba3 100644
>> --- a/Documentation/devicetree/bindings/mfd/lp873x.txt
>> +++ b/Documentation/devicetree/bindings/mfd/lp873x.txt
>> @@ -7,6 +7,9 @@ Required properties:
>>    - #gpio-cells:	Should be two.  The first cell is the pin number and
>>  			the second cell is used to specify flags.
>>  			See ../gpio/gpio.txt for more information.
>> +  - xxx-supply:		Phandle to parent supply node of each regulator
>> +			populated under regulators node. xxx should match
>> +			the supply_name populated in driver.
> 
> xxx-in-supply?

Oops. Right. Ill update it and repost.

Thanks and regards,
Lokesh

^ permalink raw reply

* [PATCH] i2c: uniphier[-f]: fix bool logic calculation
From: Masahiro Yamada @ 2016-10-19  4:38 UTC (permalink / raw)
  To: linux-arm-kernel

This code is working, but it should not depend on how "bool" is
typedef'ed, or the bit position of I2C_M_RD.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 drivers/i2c/busses/i2c-uniphier-f.c | 2 +-
 drivers/i2c/busses/i2c-uniphier.c   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
index db9105e..b54448e 100644
--- a/drivers/i2c/busses/i2c-uniphier-f.c
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -309,7 +309,7 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
 					 struct i2c_msg *msg, bool stop)
 {
 	struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
-	bool is_read = msg->flags & I2C_M_RD;
+	bool is_read = !!(msg->flags & I2C_M_RD);
 	unsigned long time_left;
 
 	dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
index 56e92af..cc80bb2 100644
--- a/drivers/i2c/busses/i2c-uniphier.c
+++ b/drivers/i2c/busses/i2c-uniphier.c
@@ -177,7 +177,7 @@ static int uniphier_i2c_stop(struct i2c_adapter *adap)
 static int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap,
 					struct i2c_msg *msg, bool stop)
 {
-	bool is_read = msg->flags & I2C_M_RD;
+	bool is_read = !!(msg->flags & I2C_M_RD);
 	bool recovery = false;
 	int ret;
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH] ARM: dts: socfpga: enable qspi on the Cyclone5 devkit
From: dinguyen at opensource.altera.com @ 2016-10-19  4:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dinh Nguyen <dinguyen@opensource.altera.com>

Enable the qspi controller on the devkit and add the flash chip.

Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
---
 arch/arm/boot/dts/socfpga_cyclone5_socdk.dts |   32 ++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
index 15e43f4..a0868e9 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
@@ -87,6 +87,38 @@
 	status = "okay";
 };
 
+&qspi {
+	status = "okay";
+
+	flash0: n25q00 at 0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "n25q00";
+		reg = <0>;	/* chip select */
+		spi-max-frequency = <100000000>;
+
+		cdns,page-size = <256>;
+		cdns,block-size = <16>;
+		cdns,read-delay = <4>;
+		cdns,tshsl-ns = <50>;
+		cdns,tsd2d-ns = <50>;
+		cdns,tchsh-ns = <4>;
+		cdns,tslch-ns = <4>;
+
+		partition at qspi-boot {
+			/* 8MB for raw data. */
+			label = "Flash 0 Raw Data";
+			reg = <0x0 0x800000>;
+		};
+
+		partition at qspi-rootfs {
+			/* 120MB for jffs2 data. */
+			label = "Flash 0 jffs2 Filesystem";
+			reg = <0x800000 0x7800000>;
+		};
+	};
+};
+
 &usb1 {
 	status = "okay";
 };
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 2/3] clk: hisilicon: add CRG driver for Hi3516CV300 SoC
From: Jiancheng Xue @ 2016-10-19  3:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAL_JsqK18RHFhDSWA_j+v_pJL6vk+a=GD7oo6O3JJaV4hHHEBg@mail.gmail.com>



? 2016/10/19 10:45, Rob Herring ??:
> On Tue, Oct 18, 2016 at 9:38 PM, Jiancheng Xue
> <xuejiancheng@hisilicon.com> wrote:
>>
>>
>> ? 2016/10/18 23:58, Rob Herring ??:
>>> On Mon, Oct 17, 2016 at 08:07:04PM +0800, Pan Wen wrote:
>>>> Add CRG driver for Hi3516CV300 SoC. CRG(Clock and Reset
>>>> Generator) module generates clock and reset signals used
>>>> by other module blocks on SoC.
>>>>
>>>> Signed-off-by: Pan Wen <wenpan@hisilicon.com>
>>>> ---
>>>>  .../devicetree/bindings/clock/hisi-crg.txt         |  50 ++++
>>>>  drivers/clk/hisilicon/Kconfig                      |   8 +
>>>>  drivers/clk/hisilicon/Makefile                     |   1 +
>>>>  drivers/clk/hisilicon/crg-hi3516cv300.c            | 330 +++++++++++++++++++++
>>>>  drivers/clk/hisilicon/crg.h                        |  34 +++
>>>>  include/dt-bindings/clock/hi3516cv300-clock.h      |  48 +++
>>>>  6 files changed, 471 insertions(+)
>>>>  create mode 100644 Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>>  create mode 100644 drivers/clk/hisilicon/crg-hi3516cv300.c
>>>>  create mode 100644 drivers/clk/hisilicon/crg.h
>>>>  create mode 100644 include/dt-bindings/clock/hi3516cv300-clock.h
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/clock/hisi-crg.txt b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>> new file mode 100644
>>>> index 0000000..cc60b3d
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>> @@ -0,0 +1,50 @@
>>>> +* HiSilicon Clock and Reset Generator(CRG)
>>>
>>> Seems kind of generic given there's already various HiSi clock bindings
>>> documented.
>>>
>>>> +
>>>> +The CRG module provides clock and reset signals to various
>>>> +modules within the SoC.
>>>> +
>>>> +This binding uses the following bindings:
>>>> +    Documentation/devicetree/bindings/clock/clock-bindings.txt
>>>> +    Documentation/devicetree/bindings/reset/reset.txt
>>>> +
>>>> +Required Properties:
>>>> +
>>>> +- compatible: should be one of the following.
>>>> +  - "hisilicon,hi3516cv300-crg"
>>>> +  - "hisilicon,hi3516cv300-sysctrl"
>>>> +  - "hisilicon,hi3519-crg"
>>>
>>> There is already a binding for this. Please merge them.
>>>
>> Hi Rob,
>>
>> Pan Wen and I work together. There's really a same file included in the patch
>> https://lkml.org/lkml/2016/9/18/42 ([PATCH v2] clk: hisilicon: add CRG driver for Hi3798CV200 SoC).
>> But that patch has not been acked. This binding file will be merged if that
>> patch is accepted first. Could you give me more comments on that patch or
>> help me to ack it?  Thank you very much.
> 
> If I haven't commented, then likely it was not sent to the DT list.
Hi,

I'm pretty sure that the patch was sent to the DT list devicetree at vger.kernel.org.
You had asked a question about "hi3798cv200-sysctrl" and I replied (https://lkml.org/lkml/2016/10/10/517).
I'm waiting for your new comments. If there's some misunderstatnding, please let me know.

Thanks,
Jiancheng

> 
> Rob
> 
> .
> 

^ permalink raw reply

* [PATCH v2] ARM: dts: rockchip: temporarily remove emmc hs200 speed from rk3288-veyron-speedy.
From: Vagrant Cascadian @ 2016-10-19  3:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476824417.1031.9.camel@paulk.fr>

On 2016-10-18, Paul Kocialkowski wrote:
> Le mardi 18 octobre 2016 ? 11:21 +0200, Heiko St?bner a ?crit?:
>> Am Sonntag, 16. Oktober 2016, 21:49:43 schrieb Paul Kocialkowski:
>> > Le mardi 27 septembre 2016 ? 13:53 -0700, Vagrant Cascadian a ?crit :
>> > > 
>> > > This essentially mimics what was done with rk3288-veyron-minnie in
>> > > commit 984926781122f034d5bc9962815d135b6c4a8e1d.
>> > > 
>> > > The eMMC of the speedy Chromebook also appears to need the same tuning
>> > > workaround, as it frequently fails to recognize the eMMC without it.
>> > 
>> > I have a device where (without this patch) eMMC sometimes fails, with:
>> > [????3.561010] dwmmc_rockchip ff0f0000.dwmmc: Successfully tuned phase to
>> > 175 [????3.571742] mmc2: new HS200 MMC card at address 0001
>> > [????3.571943] mmcblk2: mmc2:0001 HAG2e 14.7 GiB?
>> > [????3.572026] mmcblk2boot0: mmc2:0001 HAG2e partition 1 4.00 MiB
>> > [????3.572107] mmcblk2boot1: mmc2:0001 HAG2e partition 2 4.00 MiB
>> > [????3.572181] mmcblk2rpmb: mmc2:0001 HAG2e partition 3 4.00 MiB
>> > [????3.685647] mmcblk2: error -110 transferring data, sector 0, nr 8, cmd
>> > response 0x900, card status 0x0

>> > And sometimes works, with:
>> > [????3.451058] dwmmc_rockchip ff0f0000.dwmmc: Successfully tuned phase to
>> > 176 [????3.491093] mmc2: new HS200 MMC card at address 0001
>> > [????3.491277] mmcblk2: mmc2:0001 HAG2e 14.7 GiB?
>> > [????3.491345] mmcblk2boot0: mmc2:0001 HAG2e partition 1 4.00 MiB
>> > [????3.491409] mmcblk2boot1: mmc2:0001 HAG2e partition 2 4.00 MiB
>> > [????3.491474] mmcblk2rpmb: mmc2:0001 HAG2e partition 3 4.00 MiB
>> > [????3.493548]??mmcblk2: p1 p2

This is similar behavior to my veyron-speedy. Here are several boot logs
>From running 4.8.0-rc7, with some failures and some successes:

  https://cascadia.aikidev.net/~vagrant/veyron-speedy/


>> > However, with this change, it always fails, with:
>> > [????3.322129] mmc_host mmc2: Bus speed (slot 0) = 50000000Hz (slot req
>> > 52000000Hz, actual 50000000HZ div = 0) [????3.333174] mmc2: error -110
>> > whilst initialising MMC card
>> > 
>> > I don't have so much time to investigate this issue, but it's clear that
>> > this patch doesn't fix the issue (and actually worsens it) for my device.

Well, that makes things more complicated.


>> As discussed on IRC we now have varying reports of the emmc working or not?
>> working with and without that patch applied. So it's not really a bandaid fix?
>> and I've thus dropped this patch again.
>
> Thanks for dropping it! For the record, my eMMC shows up as:
> mmcblk2: mmc2:0001 HAG2e 14.7 GiB

Mine looks similar, although reporting as mmc0:

  [    3.166550] mmcblk0: mmc0:0001 HAG2e 14.7 GiB


> Maybe it could help to share what each tested device reports as eMMC model and
> associate that with the current behavior, in spite of getting a clearer idea of
> what issue affects what model.

FWIW, I'm using a veyron-speedy with 4GB of ram, not sure what other
information might be useful to distinguish between different models.

On the bottom of the case, it claims to be a C201P. Near the serial,
it's marked as C201PA-DS02-LG.


live well,
  vagrant
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161018/643b245b/attachment.sig>

^ permalink raw reply

* [PATCH v2] ARM: bcm2835: Add names for the Raspberry Pi GPIO lines
From: Eric Anholt @ 2016-10-19  3:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAPoCmYJC1TebBrspD_=mTETULSjg9or5a0Yda8p945y6ZWL99Q@mail.gmail.com>

Gottfried Haider <gottfried.haider@gmail.com> writes:

> Hi Eric, Linus,
>
> I'll hopefully find time to look at the more recent changes to the gpio
> subsystem (lsgpio?!), but since this patch is up for discussion now - what
> I was wondering: how does this change relate to /sys/class/gpio/gpio%d? Is
> this completely orthogonal - or would this change the sysfs interface as
> well?
>
> Regarding the proposed format using the header pin numbers: From what I've
> seen in terms of existing educational materials, it seems the overwhelming
> majority ends up using GPIO numbers instead of physical pin header
> numbering. (e.g. [1] [2])
> Would it be too confusing to try to pick GPIO 5 from an alphabetically
> sorted list like this "P11_GPIO17", "P12_GPIO18"? (I know, alphabetical
> sorting is an issue here already for a different reason. But applications
> might do it, I guess?)

I added the pin numbers because it was a consistent response to the
first version.  I do think the GPIO numbers without pin numbers would be
the most clear.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161018/cae67ff7/attachment.sig>

^ permalink raw reply

* [RFC PATCH] mtd: nand: Add OX820 NAND Support
From: Rob Herring @ 2016-10-19  3:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018090927.1990-1-narmstrong@baylibre.com>

On Tue, Oct 18, 2016 at 11:09:27AM +0200, Neil Armstrong wrote:
> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 ++++

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/mtd/nand/Kconfig                           |   5 +
>  drivers/mtd/nand/Makefile                          |   1 +
>  drivers/mtd/nand/oxnas_nand.c                      | 144 +++++++++++++++++++++
>  4 files changed, 174 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>  create mode 100644 drivers/mtd/nand/oxnas_nand.c

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox