Linux userland API discussions
 help / color / mirror / Atom feed
* Re: [PATCH 0/3] Allow user to request memory to be locked on page fault
From: Eric B Munson @ 2015-05-11 14:36 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Shuah Khan, linux-alpha, linux-kernel, linux-mips, linux-parisc,
	linuxppc-dev, sparclinux, linux-xtensa, linux-mm, linux-arch,
	linux-api
In-Reply-To: <20150508131523.f970d13a213bca63bd6f2619@linux-foundation.org>

[-- Attachment #1: Type: text/plain, Size: 3082 bytes --]

On Fri, 08 May 2015, Andrew Morton wrote:

> On Fri, 8 May 2015 16:06:10 -0400 Eric B Munson <emunson@akamai.com> wrote:
> 
> > On Fri, 08 May 2015, Andrew Morton wrote:
> > 
> > > On Fri,  8 May 2015 15:33:43 -0400 Eric B Munson <emunson@akamai.com> wrote:
> > > 
> > > > mlock() allows a user to control page out of program memory, but this
> > > > comes at the cost of faulting in the entire mapping when it is
> > > > allocated.  For large mappings where the entire area is not necessary
> > > > this is not ideal.
> > > > 
> > > > This series introduces new flags for mmap() and mlockall() that allow a
> > > > user to specify that the covered are should not be paged out, but only
> > > > after the memory has been used the first time.
> > > 
> > > Please tell us much much more about the value of these changes: the use
> > > cases, the behavioural improvements and performance results which the
> > > patchset brings to those use cases, etc.
> > > 
> > 
> > The primary use case is for mmaping large files read only.  The process
> > knows that some of the data is necessary, but it is unlikely that the
> > entire file will be needed.  The developer only wants to pay the cost to
> > read the data in once.  Unfortunately developer must choose between
> > allowing the kernel to page in the memory as needed and guaranteeing
> > that the data will only be read from disk once.  The first option runs
> > the risk of having the memory reclaimed if the system is under memory
> > pressure, the second forces the memory usage and startup delay when
> > faulting in the entire file.
> 
> Why can't the application mmap only those parts of the file which it
> wants and mlock those?

There are a number of problems with this approach.  The first is it
presumes the program will know what portions are needed a head of time.
In many cases this is simply not true.  The second problem is the number
of syscalls required.  With my patches, a single mmap() or mlockall()
call is needed to setup the required locking.  Without it, a separate
mmap call must be made for each piece of data that is needed.  This also
opens up problems for data that is arranged assuming it is contiguous in
memory.  With the single mmap call, the user gets a contiguous VMA
without having to know about it.  mmap() with MAP_FIXED could address
the problem, but this introduces a new failure mode of your map
colliding with another that was placed by the kernel.

Another use case for the LOCKONFAULT flag is the security use of
mlock().  If an application will be using data that cannot be written
to swap, but the exact size is unknown until run time (all we have a
build time is the maximum size the buffer can be).  The LOCKONFAULT flag
allows the developer to create the buffer and guarantee that the
contents are never written to swap without ever consuming more memory
than is actually needed.

> 
> > I am working on getting startup times with and without this change for
> > an application, I will post them as soon as I have them.
> 

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply

* Re: [PATCH 1/2] clone: Support passing tls argument via C rather than pt_regs magic
From: Vineet Gupta @ 2015-05-11 14:31 UTC (permalink / raw)
  To: Josh Triplett, Andy Lutomirski, Ingo Molnar, H. Peter Anvin,
	Peter Zijlstra, Thomas Gleixner, Linus Torvalds,
	linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	x86-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org
In-Reply-To: <20150421174711.GA5127@jtriplet-mobl1>

On Tuesday 21 April 2015 11:17 PM, Josh Triplett wrote:
> clone with CLONE_SETTLS accepts an argument to set the thread-local
> storage area for the new thread.  sys_clone declares an int argument
> tls_val in the appropriate point in the argument list (based on the
> various CLONE_BACKWARDS variants), but doesn't actually use or pass
> along that argument.  Instead, sys_clone calls do_fork, which calls
> copy_process, which calls the arch-specific copy_thread, and copy_thread
> pulls the corresponding syscall argument out of the pt_regs captured at
> kernel entry (knowing what argument of clone that architecture passes
> tls in).
> 
> Apart from being awful and inscrutable, that also only works because
> only one code path into copy_thread can pass the CLONE_SETTLS flag, and
> that code path comes from sys_clone with its architecture-specific
> argument-passing order.  This prevents introducing a new version of the
> clone system call without propagating the same architecture-specific
> position of the tls argument.
> 
> However, there's no reason to pull the argument out of pt_regs when
> sys_clone could just pass it down via C function call arguments.
> 
> Introduce a new CONFIG_HAVE_COPY_THREAD_TLS for architectures to opt
> into, and a new copy_thread_tls that accepts the tls parameter as an
> additional unsigned long (syscall-argument-sized) argument.
> Change sys_clone's tls argument to an unsigned long (which does
> not change the ABI), and pass that down to copy_thread_tls.
> 
> Architectures that don't opt into copy_thread_tls will continue to
> ignore the C argument to sys_clone in favor of the pt_regs captured at
> kernel entry, and thus will be unable to introduce new versions of the
> clone syscall.
> 
> Signed-off-by: Josh Triplett <josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org>
> Signed-off-by: Thiago Macieira <thiago.macieira-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> Acked-by: Andy Lutomirski <luto-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> ---
>  arch/Kconfig             |  7 ++++++
>  include/linux/sched.h    | 14 ++++++++++++
>  include/linux/syscalls.h |  6 +++---
>  kernel/fork.c            | 55 +++++++++++++++++++++++++++++++-----------------
>  4 files changed, 60 insertions(+), 22 deletions(-)
> 
> diff --git a/arch/Kconfig b/arch/Kconfig
> index 05d7a8a..4834a58 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -484,6 +484,13 @@ config HAVE_IRQ_EXIT_ON_IRQ_STACK
>  	  This spares a stack switch and improves cache usage on softirq
>  	  processing.
>  
> +config HAVE_COPY_THREAD_TLS
> +	bool
> +	help
> +	  Architecture provides copy_thread_tls to accept tls argument via
> +	  normal C parameter passing, rather than extracting the syscall
> +	  argument from pt_regs.
> +
>  #
>  # ABI hall of shame
>  #
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index a419b65..2cc88c6 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -2480,8 +2480,22 @@ extern struct mm_struct *mm_access(struct task_struct *task, unsigned int mode);
>  /* Remove the current tasks stale references to the old mm_struct */
>  extern void mm_release(struct task_struct *, struct mm_struct *);
>  
> +#ifdef CONFIG_HAVE_COPY_THREAD_TLS
> +extern int copy_thread_tls(unsigned long, unsigned long, unsigned long,
> +			struct task_struct *, unsigned long);
> +#else
>  extern int copy_thread(unsigned long, unsigned long, unsigned long,
>  			struct task_struct *);
> +
> +/* Architectures that haven't opted into copy_thread_tls get the tls argument
> + * via pt_regs, so ignore the tls argument passed via C. */
> +static inline int copy_thread_tls(
> +		unsigned long clone_flags, unsigned long sp, unsigned long arg,
> +		struct task_struct *p, unsigned long tls)
> +{
> +	return copy_thread(clone_flags, sp, arg, p);
> +}
> +#endif

Is this detour really needed. Can we not update copy_thread() of all arches in one
go and add the tls arg, w/o using it.

And then arch maintainers can micro-optimize their code to use that arg vs.
pt_regs->rxx version at their own leisure. The only downside I see with that is
bigger churn (touches all arches), and a interim unused arg warning ?


-Vineet

>  extern void flush_thread(void);
>  extern void exit_thread(void);
>  
> diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
> index 76d1e38..bb51bec 100644
> --- a/include/linux/syscalls.h
> +++ b/include/linux/syscalls.h
> @@ -827,15 +827,15 @@ asmlinkage long sys_syncfs(int fd);
>  asmlinkage long sys_fork(void);
>  asmlinkage long sys_vfork(void);
>  #ifdef CONFIG_CLONE_BACKWARDS
> -asmlinkage long sys_clone(unsigned long, unsigned long, int __user *, int,
> +asmlinkage long sys_clone(unsigned long, unsigned long, int __user *, unsigned long,
>  	       int __user *);
>  #else
>  #ifdef CONFIG_CLONE_BACKWARDS3
>  asmlinkage long sys_clone(unsigned long, unsigned long, int, int __user *,
> -			  int __user *, int);
> +			  int __user *, unsigned long);
>  #else
>  asmlinkage long sys_clone(unsigned long, unsigned long, int __user *,
> -	       int __user *, int);
> +	       int __user *, unsigned long);
>  #endif
>  #endif
>  
> diff --git a/kernel/fork.c b/kernel/fork.c
> index cf65139..b3dadf4 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -1192,7 +1192,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
>  					unsigned long stack_size,
>  					int __user *child_tidptr,
>  					struct pid *pid,
> -					int trace)
> +					int trace,
> +					unsigned long tls)
>  {
>  	int retval;
>  	struct task_struct *p;
> @@ -1401,7 +1402,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
>  	retval = copy_io(clone_flags, p);
>  	if (retval)
>  		goto bad_fork_cleanup_namespaces;
> -	retval = copy_thread(clone_flags, stack_start, stack_size, p);
> +	retval = copy_thread_tls(clone_flags, stack_start, stack_size, p, tls);
>  	if (retval)
>  		goto bad_fork_cleanup_io;
>  
> @@ -1613,7 +1614,7 @@ static inline void init_idle_pids(struct pid_link *links)
>  struct task_struct *fork_idle(int cpu)
>  {
>  	struct task_struct *task;
> -	task = copy_process(CLONE_VM, 0, 0, NULL, &init_struct_pid, 0);
> +	task = copy_process(CLONE_VM, 0, 0, NULL, &init_struct_pid, 0, 0);
>  	if (!IS_ERR(task)) {
>  		init_idle_pids(task->pids);
>  		init_idle(task, cpu);
> @@ -1628,11 +1629,13 @@ struct task_struct *fork_idle(int cpu)
>   * It copies the process, and if successful kick-starts
>   * it and waits for it to finish using the VM if required.
>   */
> -long do_fork(unsigned long clone_flags,
> -	      unsigned long stack_start,
> -	      unsigned long stack_size,
> -	      int __user *parent_tidptr,
> -	      int __user *child_tidptr)
> +static long _do_fork(
> +		unsigned long clone_flags,
> +		unsigned long stack_start,
> +		unsigned long stack_size,
> +		int __user *parent_tidptr,
> +		int __user *child_tidptr,
> +		unsigned long tls)
>  {
>  	struct task_struct *p;
>  	int trace = 0;
> @@ -1657,7 +1660,7 @@ long do_fork(unsigned long clone_flags,
>  	}
>  
>  	p = copy_process(clone_flags, stack_start, stack_size,
> -			 child_tidptr, NULL, trace);
> +			 child_tidptr, NULL, trace, tls);
>  	/*
>  	 * Do this prior waking up the new thread - the thread pointer
>  	 * might get invalid after that point, if the thread exits quickly.
> @@ -1698,20 +1701,34 @@ long do_fork(unsigned long clone_flags,
>  	return nr;
>  }
>  
> +#ifndef CONFIG_HAVE_COPY_THREAD_TLS
> +/* For compatibility with architectures that call do_fork directly rather than
> + * using the syscall entry points below. */
> +long do_fork(unsigned long clone_flags,
> +	      unsigned long stack_start,
> +	      unsigned long stack_size,
> +	      int __user *parent_tidptr,
> +	      int __user *child_tidptr)
> +{
> +	return _do_fork(clone_flags, stack_start, stack_size,
> +			parent_tidptr, child_tidptr, 0);
> +}
> +#endif
> +
>  /*
>   * Create a kernel thread.
>   */
>  pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
>  {
> -	return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
> -		(unsigned long)arg, NULL, NULL);
> +	return _do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
> +		(unsigned long)arg, NULL, NULL, 0);
>  }
>  
>  #ifdef __ARCH_WANT_SYS_FORK
>  SYSCALL_DEFINE0(fork)
>  {
>  #ifdef CONFIG_MMU
> -	return do_fork(SIGCHLD, 0, 0, NULL, NULL);
> +	return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);
>  #else
>  	/* can not support in nommu mode */
>  	return -EINVAL;
> @@ -1722,8 +1739,8 @@ SYSCALL_DEFINE0(fork)
>  #ifdef __ARCH_WANT_SYS_VFORK
>  SYSCALL_DEFINE0(vfork)
>  {
> -	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
> -			0, NULL, NULL);
> +	return _do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
> +			0, NULL, NULL, 0);
>  }
>  #endif
>  
> @@ -1731,27 +1748,27 @@ SYSCALL_DEFINE0(vfork)
>  #ifdef CONFIG_CLONE_BACKWARDS
>  SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
>  		 int __user *, parent_tidptr,
> -		 int, tls_val,
> +		 unsigned long, tls,
>  		 int __user *, child_tidptr)
>  #elif defined(CONFIG_CLONE_BACKWARDS2)
>  SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags,
>  		 int __user *, parent_tidptr,
>  		 int __user *, child_tidptr,
> -		 int, tls_val)
> +		 unsigned long, tls)
>  #elif defined(CONFIG_CLONE_BACKWARDS3)
>  SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,
>  		int, stack_size,
>  		int __user *, parent_tidptr,
>  		int __user *, child_tidptr,
> -		int, tls_val)
> +		unsigned long, tls)
>  #else
>  SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
>  		 int __user *, parent_tidptr,
>  		 int __user *, child_tidptr,
> -		 int, tls_val)
> +		 unsigned long, tls)
>  #endif
>  {
> -	return do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);
> +	return _do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr, tls);
>  }
>  #endif
>  
> 

^ permalink raw reply

* Re: [PATCH 1/2] clone: Support passing tls argument via C rather than pt_regs magic
From: Ingo Molnar @ 2015-05-11 14:00 UTC (permalink / raw)
  To: Josh Triplett
  Cc: Thomas Gleixner, Andy Lutomirski, Ingo Molnar, H. Peter Anvin,
	Peter Zijlstra, Linus Torvalds, linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, x86-DgEjT+Ai2ygdnm+yROfE0A
In-Reply-To: <20150511135526.GA6130@x>


* Josh Triplett <josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org> wrote:

> On Mon, May 11, 2015 at 12:13:13PM +0200, Ingo Molnar wrote:
> > 
> > * josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org <josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org> wrote:
> > 
> > > On Tue, May 05, 2015 at 08:53:03PM +0200, Thomas Gleixner wrote:
> > > > On Tue, 21 Apr 2015, Josh Triplett wrote:
> > > > > 
> > > > > Signed-off-by: Josh Triplett <josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org>
> > > > > Signed-off-by: Thiago Macieira <thiago.macieira-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> > > > 
> > > > Can you please clarify that SOB chain? It does not make any sense.
> > > 
> > > Co-authored patch.  We both worked on it together, and sadly git 
> > > doesn't support a commit with multiple authors, so this is the next 
> > > best thing.
> > 
> > No, this is not a valid SOB chain.
> > 
> > For 'co authored' patches you can add credits either to the file, 
> > as two copyright lines, or via the changelog, no need to mess up 
> > the SOB chain for that.
> 
> Fine, I'll write it another way.
> 
> Do you see any other issues with the patch other than the signoffs?

Looks good to me, but I have not looked very deeply ...

Thanks,

	Ingo

^ permalink raw reply

* Re: [PATCH 1/2] clone: Support passing tls argument via C rather than pt_regs magic
From: Josh Triplett @ 2015-05-11 13:55 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Thomas Gleixner, Andy Lutomirski, Ingo Molnar, H. Peter Anvin,
	Peter Zijlstra, Linus Torvalds, linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, x86-DgEjT+Ai2ygdnm+yROfE0A
In-Reply-To: <20150511101313.GA18058-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

On Mon, May 11, 2015 at 12:13:13PM +0200, Ingo Molnar wrote:
> 
> * josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org <josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org> wrote:
> 
> > On Tue, May 05, 2015 at 08:53:03PM +0200, Thomas Gleixner wrote:
> > > On Tue, 21 Apr 2015, Josh Triplett wrote:
> > > > 
> > > > Signed-off-by: Josh Triplett <josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org>
> > > > Signed-off-by: Thiago Macieira <thiago.macieira-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> > > 
> > > Can you please clarify that SOB chain? It does not make any sense.
> > 
> > Co-authored patch.  We both worked on it together, and sadly git 
> > doesn't support a commit with multiple authors, so this is the next 
> > best thing.
> 
> No, this is not a valid SOB chain.
> 
> For 'co authored' patches you can add credits either to the file, as 
> two copyright lines, or via the changelog, no need to mess up the SOB 
> chain for that.

Fine, I'll write it another way.

Do you see any other issues with the patch other than the signoffs?

- Josh Triplett

^ permalink raw reply

* Re: [PATCH 0/6] support "dataplane" mode for nohz_full
From: Steven Rostedt @ 2015-05-11 12:57 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Andrew Morton, Chris Metcalf, Gilad Ben Yossef, Ingo Molnar,
	Peter Zijlstra, Rik van Riel, Tejun Heo, Frederic Weisbecker,
	Thomas Gleixner, Paul E. McKenney, Christoph Lameter,
	Srivatsa S. Bhat, linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150509070538.GA9413-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>


NO_HZ_LEAVE_ME_THE_FSCK_ALONE!


On Sat, 9 May 2015 09:05:38 +0200
Ingo Molnar <mingo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
 
> So I think we should either rename NO_HZ_FULL to NO_HZ_PURE, or keep 
> it at NO_HZ_FULL: because the intention of NO_HZ_FULL was always to be 
> such a 'zero overhead' mode of operation, where if user-space runs, it 
> won't get interrupted in any way.


All kidding aside, I think this is the real answer. We don't need a new
NO_HZ, we need to make NO_HZ_FULL work. Right now it doesn't do exactly
what it was created to do. That should be fixed.

Please lets get NO_HZ_FULL up to par. That should be the main focus.

-- Steve

^ permalink raw reply

* Re: [PATCH 1/2] clone: Support passing tls argument via C rather than pt_regs magic
From: Ingo Molnar @ 2015-05-11 10:13 UTC (permalink / raw)
  To: josh
  Cc: Thomas Gleixner, Andy Lutomirski, Ingo Molnar, H. Peter Anvin,
	Peter Zijlstra, Linus Torvalds, linux-api, linux-kernel, x86
In-Reply-To: <20150505231221.GB16525@cloud>


* josh@joshtriplett.org <josh@joshtriplett.org> wrote:

> On Tue, May 05, 2015 at 08:53:03PM +0200, Thomas Gleixner wrote:
> > On Tue, 21 Apr 2015, Josh Triplett wrote:
> > > 
> > > Signed-off-by: Josh Triplett <josh@joshtriplett.org>
> > > Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
> > 
> > Can you please clarify that SOB chain? It does not make any sense.
> 
> Co-authored patch.  We both worked on it together, and sadly git 
> doesn't support a commit with multiple authors, so this is the next 
> best thing.

No, this is not a valid SOB chain.

For 'co authored' patches you can add credits either to the file, as 
two copyright lines, or via the changelog, no need to mess up the SOB 
chain for that.

Thanks,

	Ingo

^ permalink raw reply

* Re: [PATCH 07/18] media controller: rename the tuner entity
From: Hans Verkuil @ 2015-05-11  9:38 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Linux Media Mailing List, Mauro Carvalho Chehab, Jonathan Corbet,
	Matthias Schwarzott, Antti Palosaari, Olli Salonen, Prabhakar Lad,
	Sakari Ailus, Laurent Pinchart, linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150511063138.1ea10ccf-+RedX5hVuTR+urZeOPWqwQ@public.gmane.org>

On 05/11/2015 11:31 AM, Mauro Carvalho Chehab wrote:
> Em Sat, 09 May 2015 11:31:42 +0200
> Hans Verkuil <hverkuil-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org> escreveu:
> 
>>>>> Brainstorming:
>>>>>
>>>>> It might be better to map each device node to an entity and each hardware
>>>>> component (tuner, DMA engine) to an entity, and avoid this mixing of
>>>>> hw entity vs device node entity.
>>
>> There are two options here:
>>
>> either make each device node an entity, or expose the device node information
>> as properties of an entity.
>>
>> The latter would be backwards compatible with what we do today. I'm trying to
>> think of reasons why you would want to make each device node an entity in its
>> own right.
>>
>> The problem today is that a video_device representing a video/vbi/radio/swradio
>> device node is an entity, but it is really representing the dma engine. Which
>> is weird for radio devices since there is no dma engine there.
>>
>> Implementing device nodes as entities in their own right does solve this problem,
>> but implementing it as properties would be weird since a radio device node would
>> be a property of a radio tuner entity, which can be a subdevice driver which means
>> that the bridge driver would have to add the radio device property to a subdev
>> driver, which feels really wrong to me.
>>
>> With this in mind I do think representing device nodes as entities in their own
>> right makes sense.
> 
> I agree with that: devnodes should be entities, as they're the points to control
> the hardware, and need to be known by the Kernel, no matter if they have DMA
> engines associated with it or not. The better seems to map the DMA engine
> as a property on those entities.
> 
>> But I would do this also for a v4l-subdev node. It's very
>> inconsistent not to do that.
> 
> It should be easy to create an entity for each v4l-subdev node. I just
> don't see much usage on it, and this will almost double the number of
> entities.

The memory is already allocated for that since it is part of struct video_device,
which v4l-subdev uses. So I don't see this as a problem.

> Also, in order to keep it backward-compatible, both the subdev
> devnode and the subdev no-devnode entity should accept the same set of
> ioctls.

The ioctls always go through the video_device, that will not be changed by
this.

But I agree that there are other backward-compat issues. Unfortunately I cannot
dedicate much time on this at the moment.

Regards,

	Hans

^ permalink raw reply

* Re: [PATCH 07/18] media controller: rename the tuner entity
From: Mauro Carvalho Chehab @ 2015-05-11  9:31 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Linux Media Mailing List, Mauro Carvalho Chehab, Jonathan Corbet,
	Matthias Schwarzott, Antti Palosaari, Olli Salonen, Prabhakar Lad,
	Sakari Ailus, Laurent Pinchart, linux-doc, linux-api
In-Reply-To: <554DD3FE.1070806@xs4all.nl>

Em Sat, 09 May 2015 11:31:42 +0200
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> >>> Brainstorming:
> >>>
> >>> It might be better to map each device node to an entity and each hardware
> >>> component (tuner, DMA engine) to an entity, and avoid this mixing of
> >>> hw entity vs device node entity.
> 
> There are two options here:
> 
> either make each device node an entity, or expose the device node information
> as properties of an entity.
> 
> The latter would be backwards compatible with what we do today. I'm trying to
> think of reasons why you would want to make each device node an entity in its
> own right.
> 
> The problem today is that a video_device representing a video/vbi/radio/swradio
> device node is an entity, but it is really representing the dma engine. Which
> is weird for radio devices since there is no dma engine there.
> 
> Implementing device nodes as entities in their own right does solve this problem,
> but implementing it as properties would be weird since a radio device node would
> be a property of a radio tuner entity, which can be a subdevice driver which means
> that the bridge driver would have to add the radio device property to a subdev
> driver, which feels really wrong to me.
> 
> With this in mind I do think representing device nodes as entities in their own
> right makes sense.

I agree with that: devnodes should be entities, as they're the points to control
the hardware, and need to be known by the Kernel, no matter if they have DMA
engines associated with it or not. The better seems to map the DMA engine
as a property on those entities.

> But I would do this also for a v4l-subdev node. It's very
> inconsistent not to do that.

It should be easy to create an entity for each v4l-subdev node. I just
don't see much usage on it, and this will almost double the number of
entities. Also, in order to keep it backward-compatible, both the subdev
devnode and the subdev no-devnode entity should accept the same set of
ioctls.

Regards,
Mauro

^ permalink raw reply

* Re: [PATCH RFC] vfs: add a O_NOMTIME flag
From: Dave Chinner @ 2015-05-11  7:31 UTC (permalink / raw)
  To: Trond Myklebust
  Cc: Sage Weil, Zach Brown, Alexander Viro,
	Linux FS-devel Mailing List, Linux Kernel Mailing List,
	Linux API Mailing List
In-Reply-To: <CAHQdGtTFTN2XuvmarFZ9HPQV=cuhh7FosdHSrJME_U4htr=i8w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Sun, May 10, 2015 at 07:13:24PM -0400, Trond Myklebust wrote:
> On Fri, May 8, 2015 at 6:24 PM, Sage Weil <sage-BnTBU8nroG7k1uMJSBkQmQ@public.gmane.org> wrote:
> > I'm sure you realize what we're try to achieve is the same "invisible IO"
> > that the XFS open by handle ioctls do by default.  Would you be more
> > comfortable if this option where only available to the generic
> > open_by_handle syscall, and not to open(2)?
> 
> It should be an ioctl(). It has no business being part of
> open_by_handle either, since that is another generic interface.

I'm happy for it to be an ioctl interface - even an XFS specific
interface if you want to go that route, Sage - and it probably
should emit a warning to syslog first time it is used so there is
trace for bug triage purposes. i.e. we know the app is not using
mtime updates, so bug reports that are the result of mtime
mishandling don't result in large amounts of wasted developer time
trying to understand them...

Cheers,

Dave.
-- 
Dave Chinner
david-FqsqvQoI3Ljby3iVrkZq2A@public.gmane.org

^ permalink raw reply

* [PATCH] tty: fix comment of ASYNCB_SPD_HI
From: Masahiro Yamada @ 2015-05-11  1:23 UTC (permalink / raw)
  To: linux-serial
  Cc: Masahiro Yamada, Jiri Slaby, Peter Hurley, linux-api,
	linux-kernel, Greg Kroah-Hartman

This comment does not reflect the actual code.  It should be 57600,
not 56000.

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

 include/uapi/linux/tty_flags.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/uapi/linux/tty_flags.h b/include/uapi/linux/tty_flags.h
index fae4864..072e41e 100644
--- a/include/uapi/linux/tty_flags.h
+++ b/include/uapi/linux/tty_flags.h
@@ -15,7 +15,7 @@
 #define ASYNCB_FOURPORT		 1 /* Set OU1, OUT2 per AST Fourport settings */
 #define ASYNCB_SAK		 2 /* Secure Attention Key (Orange book) */
 #define ASYNCB_SPLIT_TERMIOS	 3 /* [x] Separate termios for dialin/callout */
-#define ASYNCB_SPD_HI		 4 /* Use 56000 instead of 38400 bps */
+#define ASYNCB_SPD_HI		 4 /* Use 57600 instead of 38400 bps */
 #define ASYNCB_SPD_VHI		 5 /* Use 115200 instead of 38400 bps */
 #define ASYNCB_SKIP_TEST	 6 /* Skip UART test during autoconfiguration */
 #define ASYNCB_AUTO_IRQ		 7 /* Do automatic IRQ during
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH RFC] vfs: add a O_NOMTIME flag
From: Trond Myklebust @ 2015-05-10 23:13 UTC (permalink / raw)
  To: Sage Weil
  Cc: Dave Chinner, Zach Brown, Alexander Viro,
	Linux FS-devel Mailing List, Linux Kernel Mailing List,
	Linux API Mailing List
In-Reply-To: <alpine.DEB.2.00.1505081517470.28239-vIokxiIdD2AQNTJnQDzGJqxOck334EZe@public.gmane.org>

On Fri, May 8, 2015 at 6:24 PM, Sage Weil <sage-BnTBU8nroG7k1uMJSBkQmQ@public.gmane.org> wrote:
> On Sat, 9 May 2015, Dave Chinner wrote:
>> On Thu, May 07, 2015 at 09:23:24PM -0400, Trond Myklebust wrote:
>> > On Thu, May 7, 2015 at 9:01 PM, Sage Weil <sage-BnTBU8nroG7k1uMJSBkQmQ@public.gmane.org> wrote:
>> > > On Thu, 7 May 2015, Zach Brown wrote:
>> > >> On Thu, May 07, 2015 at 10:26:17AM +1000, Dave Chinner wrote:
>> > >> > On Wed, May 06, 2015 at 03:00:12PM -0700, Zach Brown wrote:
>> > >> > > The criteria for using O_NOMTIME is the same as for using O_NOATIME:
>> > >> > > owning the file or having the CAP_FOWNER capability.  If we're not
>> > >> > > comfortable allowing owners to prevent mtime/ctime updates then we
>> > >> > > should add a tunable to allow O_NOMTIME.  Maybe a mount option?
>> > >> >
>> > >> > I dislike "turn off safety for performance" options because Joe
>> > >> > SpeedRacer will always select performance over safety.
>> > >>
>> > >> Well, for ceph there's no safety concern.  They never use cmtime in
>> > >> these files.
>> > >>
>> > >> So are you suggesting not implementing this and making them rework their
>> > >> IO paths to avoid the fs maintaining mtime so that we don't give Joe
>> > >> Speedracer more rope?  Or are we talking about adding some speed bumps
>> > >> that ceph can flip on that might give Joe Speedracer pause?
>> > >
>> > > I think this is the fundamental question: who do we give the ammunition
>> > > to, the user or app writer, or the sysadmin?
>> > >
>> > > One might argue that we gave the user a similar power with O_NOATIME (the
>> > > power to break applications that assume atime is accurate).  Here we give
>> > > developers/users the power to not update mtime and suffer the consequences
>> > > (like, obviously, breaking mtime-based backups).  It should be pretty
>> > > obvious to anyone using the flag what the consequences are.
>> > >
>> > > Note that we can suffer similar lapses in mtime with fdatasync followed by
>> > > a system crash.  And as Andy points out it's semi-broken for writable
>> > > mmap.  The crash case is obviously a slightly different thing, but the
>> > > idea that mtime can't always be trusted certainly isn't crazy talk.
>> > >
>> > > Or, we can be conservative and require a mount option so that the admin
>> > > has to explicitly allow behavior that might break some existing
>> > > assumptions about mtime/ctime ('-o user_noatime' I guess?).
>> > >
>> > > I'm happy either way, so long as in the end an unprivileged ceph daemon
>> > > avoids the useless work.  In our case we always own the entire mount/disk,
>> > > so a mount option is just fine.
>> > >
>> >
>> > So, what is the expectation here for filesystems that cannot support
>> > this flag? NFSv3 in particular would break pretty catastrophically if
>> > someone decided on a whim to turn off mtime: they will have turned off
>> > the client's ability to detect cache incoherencies.
>>
>> It's worse than that, now that I think about it. I think nomtime
>> will break nfsv4 as the I_VERSION check is done *after* the
>> NO[C]MTIME checks. e.g. the atomic change count used to detect file
>> changes is only updated during the mtime update on write() calls in
>> XFS. i.e. when the timestamp is changed, a transaction to change
>> mtime is run, and that transaction commit bumps the change count.
>>
>> So cutting out mtime updates at the VFS will prevent XFS and other
>> I_VERSION aware filesystems from updating the change count that
>> NFSv4 clients rely on to detect foreign data changes in a file.
>>
>> Not sure what to do here, because the current NOCMTIME
>> implementation intentionally cuts out the timestamp update because
>> it's usage is fully invisible IO. i.e. it is used by utilities like
>> xfs_fsr and HSMs to move data into and out of files without the
>> application being able to detect the data movement in any way. These
>> are not data modification operations, though - the file contents as
>> read by the application do not change despite the fact we are moving
>> data in and out of the file. In this case we don't want timestamps
>> or change counters to change on the data movement, so I think we've
>> actually got a difference in behaviour here between O_NOMTIME and
>> O_NOCMTIME, right?
>>
>> i.e. for nfsv4 sanity O_NOMTIME still needs to bump I_VERSION on
>> write, just not modify the timestamp? In which case, not modifying
>> the timestamps gains us nothing, because the inode is still dirtied?
>
> Right: if we dirty the inode we've defeated the purpose of the patch.
>
>> The list of caveats on O_NOMTIME seems to be growing...
>
> ...and remain consistent with our goals.  We couldn't care less if NFS or
> backup software or anything else doesn't notice these changes.  This is
> private data that is wholly managed by the ceph daemon.  The goal is to
> derive *some* value from the file system and avoid reimplementing it in
> userspace (without the bits we don't need).

That makes it completely non-generic though. By putting this in the
VFS, you are giving applications a loaded gun that is pointed straight
at the application user's head.

> I'm sure you realize what we're try to achieve is the same "invisible IO"
> that the XFS open by handle ioctls do by default.  Would you be more
> comfortable if this option where only available to the generic
> open_by_handle syscall, and not to open(2)?

It should be an ioctl(). It has no business being part of
open_by_handle either, since that is another generic interface.

Cheers
  Trond

^ permalink raw reply

* Re: [PATCH v3 01/11] coresight-etm4x: Adding CoreSight ETM4x driver
From: Greg KH @ 2015-05-10 13:37 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: linux-arm-kernel, linux-api, linux-kernel, kaixu.xia,
	zhang.chunyan
In-Reply-To: <1430926047-9125-2-git-send-email-mathieu.poirier@linaro.org>

On Wed, May 06, 2015 at 09:27:17AM -0600, Mathieu Poirier wrote:
> From: Pratik Patel <pratikp@codeaurora.org>
> 
> This driver manages the CoreSight ETMv4 (Embedded Trace Macrocell) IP block
> to support HW assisted tracing on ARMv7 and ARMv8 architectures.
> 
> Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
> Signed-off-by: Kaixu Xia <xiakaixu@huawei.com>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>  .../ABI/testing/sysfs-bus-coresight-devices-etm4x  |  28 +
>  drivers/hwtracing/coresight/Kconfig                |  11 +
>  drivers/hwtracing/coresight/Makefile               |   1 +
>  drivers/hwtracing/coresight/coresight-etm4x.c      | 825 +++++++++++++++++++++
>  drivers/hwtracing/coresight/coresight-etm4x.h      | 391 ++++++++++
>  5 files changed, 1256 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
>  create mode 100644 drivers/hwtracing/coresight/coresight-etm4x.c
>  create mode 100644 drivers/hwtracing/coresight/coresight-etm4x.h
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
> new file mode 100644
> index 000000000000..a4b623871ca0
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
> @@ -0,0 +1,28 @@
> +What:		/sys/bus/coresight/devices/<memory_map>.etm/enable_source
> +Date:		April 2015
> +KernelVersion:  4.01
> +Contact:        Mathieu Poirier <mathieu.poirier@linaro.org>
> +Description:	(RW) Enable/disable tracing on this specific trace entiry.
> +		Enabling a source implies the source has been configured
> +		properly and a sink has been identidifed for it.  The path
> +		of coresight components linking the source to the sink is
> +		configured and managed automatically by the coresight framework.
> +
> +What:		/sys/bus/coresight/devices/<memory_map>.etm/status
> +Date:		April 2015
> +KernelVersion:	4.01
> +Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
> +Description:	(R) List various control and status registers.  The specific
> +		layout and content is driver specific.
> +
> +What:		/sys/bus/coresight/devices/<memory_map>.etm/mgmt
> +Date:		April 2015
> +KernelVersion:	4.01
> +Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
> +Description:	(R) Provides the current value of all the management registers.
> +
> +What:		/sys/bus/coresight/devices/<memory_map>.etm/trcidr
> +Date:		April 2015
> +KernelVersion:	4.01
> +Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
> +Description:	(R) Provides value of all the ID registers (TRCIDRx).
> diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
> index fc1f1ae7a49d..8fac01eedee7 100644
> --- a/drivers/hwtracing/coresight/Kconfig
> +++ b/drivers/hwtracing/coresight/Kconfig
> @@ -58,4 +58,15 @@ config CORESIGHT_SOURCE_ETM3X
>  	  which allows tracing the instructions that a processor is executing
>  	  This is primarily useful for instruction level tracing.  Depending
>  	  the ETM version data tracing may also be available.
> +
> +config CORESIGHT_SOURCE_ETM4X
> +	bool "CoreSight Embedded Trace Macrocell 4.x driver"
> +	depends on ARM64
> +	select CORESIGHT_LINKS_AND_SINKS
> +	help
> +	  This driver provides support for the ETM4.x tracer module, tracing the
> +	  instructions that a processor is executing. This is primarily useful
> +	  for instruction level tracing. Depending on the implemented version
> +	  data tracing may also be available.
> +
>  endif
> diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
> index 4b4bec890ef5..0af28d43465c 100644
> --- a/drivers/hwtracing/coresight/Makefile
> +++ b/drivers/hwtracing/coresight/Makefile
> @@ -9,3 +9,4 @@ obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
>  obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
>  					   coresight-replicator.o
>  obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o
> +obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
> new file mode 100644
> index 000000000000..db0bea4d4661
> --- /dev/null
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.c
> @@ -0,0 +1,825 @@
> +/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 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.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/moduleparam.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/device.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <linux/fs.h>
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/smp.h>
> +#include <linux/sysfs.h>
> +#include <linux/stat.h>
> +#include <linux/clk.h>
> +#include <linux/cpu.h>
> +#include <linux/coresight.h>
> +#include <linux/pm_wakeup.h>
> +#include <linux/amba/bus.h>
> +#include <linux/seq_file.h>
> +#include <linux/uaccess.h>
> +#include <linux/pm_runtime.h>
> +#include <asm/sections.h>
> +
> +#include "coresight-etm4x.h"
> +
> +static int boot_enable;
> +module_param_named(boot_enable, boot_enable, int, S_IRUGO);
> +
> +/* The number of ETMv4 currently registered */
> +static int etm4_count;
> +static struct etmv4_drvdata *etmdrvdata[NR_CPUS];
> +
> +static void etm4_os_unlock(void *info)
> +{
> +	struct etmv4_drvdata *drvdata = (struct etmv4_drvdata *)info;
> +
> +	/* Writing any value to ETMOSLAR unlocks the trace registers */
> +	writel_relaxed(0x0, drvdata->base + TRCOSLAR);
> +	isb();
> +}
> +
> +static bool etm4_arch_supported(u8 arch)
> +{
> +	switch (arch) {
> +	case ETM_ARCH_V4:
> +		break;
> +	default:
> +		return false;
> +	}
> +	return true;
> +}
> +
> +static int etm4_trace_id(struct coresight_device *csdev)
> +{
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> +	unsigned long flags;
> +	int trace_id = -1;
> +
> +	if (!drvdata->enable)
> +		return drvdata->trcid;
> +
> +	pm_runtime_get_sync(drvdata->dev);
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +
> +	CS_UNLOCK(drvdata->base);
> +	trace_id = readl_relaxed(drvdata->base + TRCTRACEIDR);
> +	trace_id &= ETM_TRACEID_MASK;
> +	CS_LOCK(drvdata->base);
> +
> +	spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +	pm_runtime_put(drvdata->dev);
> +
> +	return trace_id;
> +}
> +
> +static void etm4_enable_hw(void *info)
> +{
> +	int i;
> +	struct etmv4_drvdata *drvdata = info;
> +
> +	CS_UNLOCK(drvdata->base);
> +
> +	etm4_os_unlock(drvdata);
> +
> +	/* Disable the trace unit before programming trace registers */
> +	writel_relaxed(0, drvdata->base + TRCPRGCTLR);
> +
> +	/* wait for TRCSTATR.IDLE to go up */
> +	if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 1))
> +		dev_err(drvdata->dev,
> +			"timeout observed when probing at offset %#x\n",
> +			TRCSTATR);
> +
> +	writel_relaxed(drvdata->pe_sel, drvdata->base + TRCPROCSELR);
> +	writel_relaxed(drvdata->cfg, drvdata->base + TRCCONFIGR);
> +	/* nothing specific implemented */
> +	writel_relaxed(0x0, drvdata->base + TRCAUXCTLR);
> +	writel_relaxed(drvdata->eventctrl0, drvdata->base + TRCEVENTCTL0R);
> +	writel_relaxed(drvdata->eventctrl1, drvdata->base + TRCEVENTCTL1R);
> +	writel_relaxed(drvdata->stall_ctrl, drvdata->base + TRCSTALLCTLR);
> +	writel_relaxed(drvdata->ts_ctrl, drvdata->base + TRCTSCTLR);
> +	writel_relaxed(drvdata->syncfreq, drvdata->base + TRCSYNCPR);
> +	writel_relaxed(drvdata->ccctlr, drvdata->base + TRCCCCTLR);
> +	writel_relaxed(drvdata->bb_ctrl, drvdata->base + TRCBBCTLR);
> +	writel_relaxed(drvdata->trcid, drvdata->base + TRCTRACEIDR);
> +	writel_relaxed(drvdata->vinst_ctrl, drvdata->base + TRCVICTLR);
> +	writel_relaxed(drvdata->viiectlr, drvdata->base + TRCVIIECTLR);
> +	writel_relaxed(drvdata->vissctlr,
> +		       drvdata->base + TRCVISSCTLR);
> +	writel_relaxed(drvdata->vipcssctlr,
> +		       drvdata->base + TRCVIPCSSCTLR);
> +	for (i = 0; i < drvdata->nrseqstate - 1; i++)
> +		writel_relaxed(drvdata->seq_ctrl[i],
> +			       drvdata->base + TRCSEQEVRn(i));
> +	writel_relaxed(drvdata->seq_rst, drvdata->base + TRCSEQRSTEVR);
> +	writel_relaxed(drvdata->seq_state, drvdata->base + TRCSEQSTR);
> +	writel_relaxed(drvdata->ext_inp, drvdata->base + TRCEXTINSELR);
> +	for (i = 0; i < drvdata->nr_cntr; i++) {
> +		writel_relaxed(drvdata->cntrldvr[i],
> +			       drvdata->base + TRCCNTRLDVRn(i));
> +		writel_relaxed(drvdata->cntr_ctrl[i],
> +			       drvdata->base + TRCCNTCTLRn(i));
> +		writel_relaxed(drvdata->cntr_val[i],
> +			       drvdata->base + TRCCNTVRn(i));
> +	}
> +	for (i = 0; i < drvdata->nr_resource; i++)
> +		writel_relaxed(drvdata->res_ctrl[i],
> +			       drvdata->base + TRCRSCTLRn(i));
> +
> +	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> +		writel_relaxed(drvdata->ss_ctrl[i],
> +			       drvdata->base + TRCSSCCRn(i));
> +		writel_relaxed(drvdata->ss_status[i],
> +			       drvdata->base + TRCSSCSRn(i));
> +		writel_relaxed(drvdata->ss_pe_cmp[i],
> +			       drvdata->base + TRCSSPCICRn(i));
> +	}
> +	for (i = 0; i < drvdata->nr_addr_cmp; i++) {
> +		writeq_relaxed(drvdata->addr_val[i],
> +			       drvdata->base + TRCACVRn(i));
> +		writeq_relaxed(drvdata->addr_acc[i],
> +			       drvdata->base + TRCACATRn(i));
> +	}
> +	for (i = 0; i < drvdata->numcidc; i++)
> +		writeq_relaxed(drvdata->ctxid_val[i],
> +			       drvdata->base + TRCCIDCVRn(i));
> +	writel_relaxed(drvdata->ctxid_mask0, drvdata->base + TRCCIDCCTLR0);
> +	writel_relaxed(drvdata->ctxid_mask1, drvdata->base + TRCCIDCCTLR1);
> +
> +	for (i = 0; i < drvdata->numvmidc; i++)
> +		writeq_relaxed(drvdata->vmid_val[i],
> +			       drvdata->base + TRCVMIDCVRn(i));
> +	writel_relaxed(drvdata->vmid_mask0, drvdata->base + TRCVMIDCCTLR0);
> +	writel_relaxed(drvdata->vmid_mask1, drvdata->base + TRCVMIDCCTLR1);
> +
> +	/* Enable the trace unit */
> +	writel_relaxed(1, drvdata->base + TRCPRGCTLR);
> +
> +	/* wait for TRCSTATR.IDLE to go back down to '0' */
> +	if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 0))
> +		dev_err(drvdata->dev,
> +			"timeout observed when probing at offset %#x\n",
> +			TRCSTATR);
> +
> +	CS_LOCK(drvdata->base);
> +
> +	dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
> +}
> +
> +static int etm4_enable(struct coresight_device *csdev)
> +{
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> +	int ret;
> +
> +	pm_runtime_get_sync(drvdata->dev);
> +	spin_lock(&drvdata->spinlock);
> +
> +	/*
> +	 * Executing etm4_enable_hw on the cpu whose ETM is being enabled
> +	 * ensures that register writes occur when cpu is powered.
> +	 */
> +	ret = smp_call_function_single(drvdata->cpu,
> +				       etm4_enable_hw, drvdata, 1);
> +	if (ret)
> +		goto err;
> +	drvdata->enable = true;
> +	drvdata->sticky_enable = true;
> +
> +	spin_unlock(&drvdata->spinlock);
> +
> +	dev_info(drvdata->dev, "ETM tracing enabled\n");
> +	return 0;
> +err:
> +	spin_unlock(&drvdata->spinlock);
> +	pm_runtime_put(drvdata->dev);
> +	return ret;
> +}
> +
> +static void etm4_disable_hw(void *info)
> +{
> +	u32 control;
> +	struct etmv4_drvdata *drvdata = info;
> +
> +	CS_UNLOCK(drvdata->base);
> +
> +	control = readl_relaxed(drvdata->base + TRCPRGCTLR);
> +
> +	/* EN, bit[0] Trace unit enable bit */
> +	control &= ~0x1;
> +
> +	/* make sure everything completes before disabling */
> +	mb();
> +	isb();
> +	writel_relaxed(control, drvdata->base + TRCPRGCTLR);
> +
> +	CS_LOCK(drvdata->base);
> +
> +	dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
> +}
> +
> +static void etm4_disable(struct coresight_device *csdev)
> +{
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> +
> +	/*
> +	 * Taking hotplug lock here protects from clocks getting disabled
> +	 * with tracing being left on (crash scenario) if user disable occurs
> +	 * after cpu online mask indicates the cpu is offline but before the
> +	 * DYING hotplug callback is serviced by the ETM driver.
> +	 */
> +	get_online_cpus();
> +	spin_lock(&drvdata->spinlock);
> +
> +	/*
> +	 * Executing etm4_disable_hw on the cpu whose ETM is being disabled
> +	 * ensures that register writes occur when cpu is powered.
> +	 */
> +	smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
> +	drvdata->enable = false;
> +
> +	spin_unlock(&drvdata->spinlock);
> +	put_online_cpus();
> +
> +	pm_runtime_put(drvdata->dev);
> +
> +	dev_info(drvdata->dev, "ETM tracing disabled\n");
> +}
> +
> +static const struct coresight_ops_source etm4_source_ops = {
> +	.trace_id	= etm4_trace_id,
> +	.enable		= etm4_enable,
> +	.disable	= etm4_disable,
> +};
> +
> +static const struct coresight_ops etm4_cs_ops = {
> +	.source_ops	= &etm4_source_ops,
> +};
> +
> +static ssize_t status_show(struct device *dev,
> +			   struct device_attribute *attr, char *buf)
> +{
> +	int ret;
> +	unsigned long flags;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +	pm_runtime_get_sync(drvdata->dev);
> +
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +	CS_UNLOCK(drvdata->base);
> +	ret = sprintf(buf,
> +		      "TRCCONFIGR:\t0x%08x\n"
> +		      "TRCEVENTCTL0R:\t0x%08x\n"
> +		      "TRCEVENTCTL1R:\t0x%08x\n"
> +		      "TRCSTALLCTLR:\t0x%08x\n"
> +		      "TRCSYNCPR:\t0x%08x\n"
> +		      "TRCTRACEIDR:\t0x%08x\n"
> +		      "TRCTSCTLR:\t0x%08x\n"
> +		      "TRCVDARCCTLR:\t0x%08x\n"
> +		      "TRCVDCTLR:\t0x%08x\n"
> +		      "TRCVDSACCTLR:\t0x%08x\n"
> +		      "TRCVICTLR:\t0x%08x\n"
> +		      "TRCVIIECTLR:\t0x%08x\n"
> +		      "TRCVISSCTLR:\t0x%08x\n"
> +		      "TRCPRGCTLR:\t0x%08x\n"
> +		      "CPU affinity:\t%d\n",

That is not one-value-per-file, as is the rules for sysfs.  Sorry,
please fix up.

^ permalink raw reply

* Re: [PATCH v2 0/3] add cursor blink interval terminal escape sequence
From: Greg Kroah-Hartman @ 2015-05-10 13:32 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Scot Doyle, Michael Kerrisk, Jiri Slaby, Tomi Valkeinen,
	Jean-Christophe Plagniol-Villard, Geert Uytterhoeven,
	linux-kernel, linux-fbdev, linux-man, linux-api
In-Reply-To: <20150328075443.GD5248@xo-6d-61-c0.localdomain>

On Sat, Mar 28, 2015 at 08:54:43AM +0100, Pavel Machek wrote:
> On Thu 2015-03-26 13:51:04, Scot Doyle wrote:
> > v2: Add documentation to console_codes man page (man-pages repo)
> > 
> > This patch series adds an escape sequence to specify the current console's
> > cursor blink interval. The default interval is set to fbcon's currently 
> > hardcoded 200 msecs.
> 
> Actually... Greg, can you import console_codes.4 into kernel tree somehow?

Is that file part of the manpages project?  If so, it's fine where it
is, otherwise feel free to send a patch.

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH v3 3/3] proc: add kpageidle file
From: Vladimir Davydov @ 2015-05-10 10:34 UTC (permalink / raw)
  To: Minchan Kim
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Greg Thelen,
	Michel Lespinasse, David Rientjes, Pavel Emelyanov,
	Cyrill Gorcunov, Jonathan Corbet,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA, linux-mm-Bw31MaZKKs3YtjvyW6yDsg,
	cgroups-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rik van Riel, Hugh Dickins,
	Christoph Lameter, Paul E. McKenney, Peter Zijlstra
In-Reply-To: <20150509151031.GA24141@blaptop>

On Sun, May 10, 2015 at 12:12:38AM +0900, Minchan Kim wrote:
> On Fri, May 08, 2015 at 12:56:04PM +0300, Vladimir Davydov wrote:
> > On Mon, May 04, 2015 at 07:54:59PM +0900, Minchan Kim wrote:
> > > So, I guess once below compiler optimization happens in __page_set_anon_rmap,
> > > it could be corrupt in page_refernced.
> > > 
> > > __page_set_anon_rmap:
> > >         page->mapping = (struct address_space *) anon_vma;
> > >         page->mapping = (struct address_space *)((void *)page_mapping + PAGE_MAPPING_ANON);
> > > 
> > > Because page_referenced checks it with PageAnon which has no memory barrier.
> > > So if above compiler optimization happens, page_referenced can pass the anon
> > > page in rmap_walk_file, not ramp_walk_anon. It's my theory. :)
> > 
> > FWIW
> > 
> > If such splits were possible, we would have bugs all over the kernel
> > IMO. An example is do_wp_page() vs shrink_active_list(). In do_wp_page()
> > we can call page_move_anon_rmap(), which sets page->mapping in exactly
> > the same fashion as above-mentioned __page_set_anon_rmap():
> > 
> > 	anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
> > 	page->mapping = (struct address_space *) anon_vma;
> > 
> > The page in question may be on an LRU list, because nowhere in
> > do_wp_page() we remove it from the list, neither do we take any LRU
> > related locks. The page is locked, that's true, but shrink_active_list()
> > calls page_referenced() on an unlocked page, so according to your logic
> > they can race with the latter receiving a page with page->mapping equal
> > to anon_vma w/o PAGE_MAPPING_ANON bit set:
> > 
> > CPU0				CPU1
> > ----				----
> > do_wp_page			shrink_active_list
> >  lock_page			 page_referenced
> > 				  PageAnon->yes, so skip trylock_page
> >  page_move_anon_rmap
> >   page->mapping = anon_vma
> > 				  rmap_walk
> > 				   PageAnon->no
> > 				   rmap_walk_file
> > 				    BUG
> >   page->mapping = page->mapping+PAGE_MAPPING_ANON
> > 
> > However, this does not happen.
> 
> Good spot.
> 
> However, it doesn't mean it's right so you are okay to rely on it.
> Normally, store tearing is not common and such race would be hard to hit
> but I want to call it as BUG.

But then we should call atomic64_set/atomic_long_set a big fat bug,
because it does not use ACCESS_ONCE/volatile stuff on its argument, so
it is prone to write tearing and therefore it is not atomic at all.

> 
> Rik wrote the code and commented out.
> 
>         "Protected against the rmap code by the page lock"
> 
> But unfortunately, page_referenced in shrink_active_list doesn't hold
> a page lock so isn't it a bug? Rik?
> 
> Please, read store tearing section in Documentation/memory-barrier.txt.
> If you get confused due to aligned memory, please read this link.
> 
>         https://lkml.org/lkml/2014/7/16/262

I've read it. It describes tearing of

	p = 0x00010002;

to

	*(u16 *)&p = 0x2;
	*((u16 *)&p+1) = 0x1

to avoid computation of 0x00010002 by using two 16-bit immediate-store.

AFAIU that isn't nearly the case in __page_set_anon_rmap:

	anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
	page->mapping = (struct address_space *) anon_vma;

The compiler doesn't know the value of anon_vma so there is absolutely
no benefit in tearing it - it would only result in two vs one store. I
admit we cannot rule out that some mad compiler can do that, but IMO
that would be a compiler bug, which would result in the kernel tearing
apart.

> 
> Other quote from Paul in https://lkml.org/lkml/2015/5/1/229
> "
> ..
> If the thing read/written does fit into a machine word and if the location
> read/written is properly aligned, I would be quite surprised if either
> READ_ONCE() or WRITE_ONCE() resulted in any sort of tearing.
> "
> 
> I parsed it as that "even store tearing can happen machine word at
> alinged address and that's why WRITE_ONCE is there to prevent it"

That's a sort of reading between the lines, I can't see it's written here.

> 
> If you want to claim GCC doesn't do it, please read below links
> 
>         https://lkml.org/lkml/2015/4/16/527
>         http://yarchive.net/comp/linux/ACCESS_ONCE.html
> 
> Quote from Linus
> "
> The thing is, you can't _prove_ that the compiler won't do it, especially
> if you end up changing the code later (without thinking about the fact
> that you're loading things without locking).
> 
> So the rule is: if you access unlocked values, you use ACCESS_ONCE(). You
> don't say "but it can't matter". Because you simply don't know.
> "

You took this citation from the context, which has nothing to do with
read/store tearing. It's about the value consistency in some statement.
E.g. in the following statement

	int i = x;
	if (i > y)
		y = i;

we do need ACCESS_ONCE around x, because the compiler is free to fetch
its value twice, in the comparison and the assignment. But it's not
about read/write tearing.

> 
> Yeb, I might be paranoid but my point is it might work now on most of
> arch but it seem to be buggy/fragile/subtle because we couldn't prove
> all arch/compiler don't make any trouble. So, intead of adding more
> logics based on fragile, please use right lock model. If lock becomes
> big trouble by overhead, let's fix it(for instance, use WRITE_ONCE for
> update-side and READ_ONCE  for read-side) if I don't miss something.

IMO, locking would be an overkill. READ_ONCE is OK, because it has no
performance implications, but I would prefer to be convinced that it is
100% necessary before adding it just in case.

Thanks,
Vladimir

^ permalink raw reply

* Re: [PATCH v3 3/3] proc: add kpageidle file
From: Minchan Kim @ 2015-05-09 15:12 UTC (permalink / raw)
  To: Vladimir Davydov
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Greg Thelen,
	Michel Lespinasse, David Rientjes, Pavel Emelyanov,
	Cyrill Gorcunov, Jonathan Corbet, linux-api, linux-doc, linux-mm,
	cgroups, linux-kernel, Rik van Riel, Hugh Dickins,
	Christoph Lameter, Paul E. McKenney, Peter Zijlstra
In-Reply-To: <20150508095604.GO31732@esperanza>

Hello, Vladimir

On Fri, May 08, 2015 at 12:56:04PM +0300, Vladimir Davydov wrote:
> On Mon, May 04, 2015 at 07:54:59PM +0900, Minchan Kim wrote:
> > So, I guess once below compiler optimization happens in __page_set_anon_rmap,
> > it could be corrupt in page_refernced.
> > 
> > __page_set_anon_rmap:
> >         page->mapping = (struct address_space *) anon_vma;
> >         page->mapping = (struct address_space *)((void *)page_mapping + PAGE_MAPPING_ANON);
> > 
> > Because page_referenced checks it with PageAnon which has no memory barrier.
> > So if above compiler optimization happens, page_referenced can pass the anon
> > page in rmap_walk_file, not ramp_walk_anon. It's my theory. :)
> 
> FWIW
> 
> If such splits were possible, we would have bugs all over the kernel
> IMO. An example is do_wp_page() vs shrink_active_list(). In do_wp_page()
> we can call page_move_anon_rmap(), which sets page->mapping in exactly
> the same fashion as above-mentioned __page_set_anon_rmap():
> 
> 	anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
> 	page->mapping = (struct address_space *) anon_vma;
> 
> The page in question may be on an LRU list, because nowhere in
> do_wp_page() we remove it from the list, neither do we take any LRU
> related locks. The page is locked, that's true, but shrink_active_list()
> calls page_referenced() on an unlocked page, so according to your logic
> they can race with the latter receiving a page with page->mapping equal
> to anon_vma w/o PAGE_MAPPING_ANON bit set:
> 
> CPU0				CPU1
> ----				----
> do_wp_page			shrink_active_list
>  lock_page			 page_referenced
> 				  PageAnon->yes, so skip trylock_page
>  page_move_anon_rmap
>   page->mapping = anon_vma
> 				  rmap_walk
> 				   PageAnon->no
> 				   rmap_walk_file
> 				    BUG
>   page->mapping = page->mapping+PAGE_MAPPING_ANON
> 
> However, this does not happen.

Good spot.

However, it doesn't mean it's right so you are okay to rely on it.
Normally, store tearing is not common and such race would be hard to hit
but I want to call it as BUG.

Rik wrote the code and commented out.

        "Protected against the rmap code by the page lock"

But unfortunately, page_referenced in shrink_active_list doesn't hold
a page lock so isn't it a bug? Rik?

Please, read store tearing section in Documentation/memory-barrier.txt.
If you get confused due to aligned memory, please read this link.

        https://lkml.org/lkml/2014/7/16/262

Other quote from Paul in https://lkml.org/lkml/2015/5/1/229
"
..
If the thing read/written does fit into a machine word and if the location
read/written is properly aligned, I would be quite surprised if either
READ_ONCE() or WRITE_ONCE() resulted in any sort of tearing.
"

I parsed it as that "even store tearing can happen machine word at
alinged address and that's why WRITE_ONCE is there to prevent it"

If you want to claim GCC doesn't do it, please read below links

        https://lkml.org/lkml/2015/4/16/527
        http://yarchive.net/comp/linux/ACCESS_ONCE.html

Quote from Linus
"
The thing is, you can't _prove_ that the compiler won't do it, especially
if you end up changing the code later (without thinking about the fact
that you're loading things without locking).

So the rule is: if you access unlocked values, you use ACCESS_ONCE(). You
don't say "but it can't matter". Because you simply don't know.
"

Yeb, I might be paranoid but my point is it might work now on most of
arch but it seem to be buggy/fragile/subtle because we couldn't prove
all arch/compiler don't make any trouble. So, intead of adding more
logics based on fragile, please use right lock model. If lock becomes
big trouble by overhead, let's fix it(for instance, use WRITE_ONCE for
update-side and READ_ONCE  for read-side) if I don't miss something.

> 
> Thanks,
> Vladimir

-- 
Kind regards,
Minchan Kim

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* RE: [PATCH 5/6] nohz: support PR_DATAPLANE_STRICT mode
From: Gilad Ben Yossef @ 2015-05-09 10:37 UTC (permalink / raw)
  To: Andy Lutomirski, Chris Metcalf
  Cc: Srivatsa S. Bhat, Paul E. McKenney, Frederic Weisbecker,
	Ingo Molnar, Rik van Riel, linux-doc@vger.kernel.org,
	Andrew Morton, linux-kernel@vger.kernel.org, Thomas Gleixner,
	Tejun Heo, Peter Zijlstra, Steven Rostedt, Christoph Lameter,
	Linux API
In-Reply-To: <CALCETrUoptUPVUxL87jUgry1pFac0rDPpnZ790zDKyK4a0FARA@mail.gmail.com>

> From: Andy Lutomirski [mailto:luto@amacapital.net]
> Sent: Saturday, May 09, 2015 10:29 AM
> To: Chris Metcalf
> Cc: Srivatsa S. Bhat; Paul E. McKenney; Frederic Weisbecker; Ingo Molnar;
> Rik van Riel; linux-doc@vger.kernel.org; Andrew Morton; linux-
> kernel@vger.kernel.org; Thomas Gleixner; Tejun Heo; Peter Zijlstra; Steven
> Rostedt; Christoph Lameter; Gilad Ben Yossef; Linux API
> Subject: Re: [PATCH 5/6] nohz: support PR_DATAPLANE_STRICT mode
> 
> On May 8, 2015 11:44 PM, "Chris Metcalf" <cmetcalf@ezchip.com> wrote:
> >
> > With QUIESCE mode, the task is in principle guaranteed not to be
> > interrupted by the kernel, but only if it behaves.  In particular,
> > if it enters the kernel via system call, page fault, or any of
> > a number of other synchronous traps, it may be unexpectedly
> > exposed to long latencies.  Add a simple flag that puts the process
> > into a state where any such kernel entry is fatal.
> >
> > To allow the state to be entered and exited, we add an internal
> > bit to current->dataplane_flags that is set when prctl() sets the
> > flags.  That way, when we are exiting the kernel after calling
> > prctl() to forbid future kernel exits, we don't get immediately
> > killed.
> 
> Is there any reason this can't already be addressed in userspace using
> /proc/interrupts or perf_events?  ISTM the real goal here is to detect
> when we screw up and fail to avoid an interrupt, and killing the task
> seems like overkill to me.
> 
> Also, can we please stop further torturing the exit paths?  
So, I don't know if it is a practical suggestion or not, but would it better/easier to mark a pending signal on kernel entry for this case?
The upsides I see is that the user gets her notification (killing the task or just logging the event in a signal handler) and hopefully since return to userspace with a pending signal is already handled we don't need new code in the exit path?

Gilad

^ permalink raw reply

* RE: [PATCH 0/6] support "dataplane" mode for nohz_full
From: Gilad Ben Yossef @ 2015-05-09 10:18 UTC (permalink / raw)
  To: Mike Galbraith, Ingo Molnar
  Cc: Andrew Morton, Chris Metcalf, Steven Rostedt, Ingo Molnar,
	Peter Zijlstra, Rik van Riel, Tejun Heo, Frederic Weisbecker,
	Thomas Gleixner, Paul E. McKenney, Christoph Lameter,
	Srivatsa S. Bhat,
	linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1431155983.3209.131.camel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>


> From: Mike Galbraith [mailto:umgwanakikbuti@gmail.com]
> Sent: Saturday, May 09, 2015 10:20 AM
> To: Ingo Molnar
> Cc: Andrew Morton; Chris Metcalf; Steven Rostedt; Gilad Ben Yossef; Ingo
> Molnar; Peter Zijlstra; Rik van Riel; Tejun Heo; Frederic Weisbecker;
> Thomas Gleixner; Paul E. McKenney; Christoph Lameter; Srivatsa S. Bhat;
> linux-doc@vger.kernel.org; linux-api@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: Re: [PATCH 0/6] support "dataplane" mode for nohz_full
> 
> On Sat, 2015-05-09 at 09:05 +0200, Ingo Molnar wrote:
> > * Andrew Morton <akpm@linux-foundation.org> wrote:
> >
> > > On Fri, 8 May 2015 19:11:10 -0400 Chris Metcalf <cmetcalf@ezchip.com>
> wrote:
> > >
> > > > On 5/8/2015 5:22 PM, Steven Rostedt wrote:
> > > > > On Fri, 8 May 2015 14:18:24 -0700
> > > > > Andrew Morton <akpm@linux-foundation.org> wrote:
> > > > >
> > > > >> On Fri, 8 May 2015 13:58:41 -0400 Chris Metcalf
> <cmetcalf@ezchip.com> wrote:
> > > > >>
> > > > >>> A prctl() option (PR_SET_DATAPLANE) is added
> > > > >> Dumb question: what does the term "dataplane" mean in this
> context?  I
> > > > >> can't see the relationship between those words and what this
> patch
> > > > >> does.
> > > > > I was thinking the same thing. I haven't gotten around to
> searching
> > > > > DATAPLANE yet.
> > > > >
> > > > > I would assume we want a name that is more meaningful for what is
> > > > > happening.
> > > >
> > > > The text in the commit message and the 0/6 cover letter do try to
> explain
> > > > the concept.  The terminology comes, I think, from networking line
> cards,
> > > > where the "dataplane" is the part of the application that handles
> all the
> > > > fast path processing of network packets, and the "control plane" is
> the part
> > > > that handles routing updates, etc., generally slow-path stuff.  I've
> probably
> > > > just been using the terms so long they seem normal to me.
> > > >
> > > > That said, what would be clearer?  NO_HZ_STRICT as a superset of
> > > > NO_HZ_FULL?  Or move away from the NO_HZ terminology a bit; after
> all,
> > > > we're talking about no interrupts of any kind, and maybe NO_HZ is
> too
> > > > limited in scope?  So, NO_INTERRUPTS?  USERSPACE_ONLY?  Or look
> > > > to vendors who ship bare-metal runtimes and call it BARE_METAL?
> > > > Borrow the Tilera marketing name and call it ZERO_OVERHEAD?
> > > >
> > > > Maybe BARE_METAL seems most plausible -- after DATAPLANE, to me,
> > > > of course :-)
> >
> > 'baremetal' has uses in virtualization speak, so I think that would be
> > confusing.
> >
> > > I like NO_INTERRUPTS.  Simple, direct.
> >
> > NO_HZ_PURE?
> 
> Hm, coke light, coke zero... OS_LIGHT and OS_ZERO?
LOL... you forgot OS_CLASSIC for backwards compatibility :-)
How about TASK_SOLO?
Yes, you are trying to achieve the least amount of interference but the bigger context is about monopolizing a single CPU for yourself.
Anyway it is worth pointing out that while NO_HZ_FULL is very useful in conjunction with this turning the tick off is useful also if you have multiple tasks runnable (e.g. if you know you only need to context switch in 100 ms, why keep a periodic interrupt running?) even though we don't support it *right now*. It might be a good idea not to entangle these concepts too much.

Gilad
Gilad Ben-Yossef
Chief Software Architect
EZchip Technologies Ltd.
37 Israel Pollak Ave, Kiryat Gat 82025 ,Israel
Tel: +972-4-959-6666 ext. 576, Fax: +972-8-681-1483 
Mobile: +972-52-826-0388, US Mobile: +1-973-826-0388
Email: giladb@ezchip.com, Web: http://www.ezchip.com


^ permalink raw reply

* Re: [PATCH v8 11/16] serial: stm32-usart: Add STM32 USART Driver
From: Andy Shevchenko @ 2015-05-09 10:07 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Peter Hurley, cw00.choi,
	Russell King, Daniel Lezcano, Joe Perches, Vladimir Zapolskiy,
	Lee Jones, Daniel Thompson, Jonathan Corbet, Pawel Moll,
	Mark Rutland, Ian Campbell
In-Reply-To: <1431158038-3813-12-git-send-email-mcoquelin.stm32@gmail.com>

On Sat, May 9, 2015 at 10:53 AM, Maxime Coquelin
<mcoquelin.stm32@gmail.com> wrote:
> This drivers adds support to the STM32 USART controller, which is a
> standard serial driver.
>

Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>

> Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
> Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
> Reviewed-by: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/tty/serial/Kconfig       |  17 +
>  drivers/tty/serial/Makefile      |   1 +
>  drivers/tty/serial/stm32-usart.c | 739 +++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serial_core.h |   3 +
>  4 files changed, 760 insertions(+)
>  create mode 100644 drivers/tty/serial/stm32-usart.c
>
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index f8120c1..7eb62f1 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1589,6 +1589,23 @@ config SERIAL_SPRD_CONSOLE
>           with "earlycon" on the kernel command line. The console is
>           enabled when early_param is processed.
>
> +config SERIAL_STM32
> +       tristate "STMicroelectronics STM32 serial port support"
> +       select SERIAL_CORE
> +       depends on ARM || COMPILE_TEST
> +       help
> +         This driver is for the on-chip Serial Controller on
> +         STMicroelectronics STM32 MCUs.
> +         USART supports Rx & Tx functionality.
> +         It support all industry standard baud rates.
> +
> +         If unsure, say N.
> +
> +config SERIAL_STM32_CONSOLE
> +       bool "Support for console on STM32"
> +       depends on SERIAL_STM32=y
> +       select SERIAL_CORE_CONSOLE
> +
>  endmenu
>
>  config SERIAL_MCTRL_GPIO
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index c3ac3d9..61979ce 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -93,6 +93,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)       += fsl_lpuart.o
>  obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)        += digicolor-usart.o
>  obj-$(CONFIG_SERIAL_MEN_Z135)  += men_z135_uart.o
>  obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
> +obj-$(CONFIG_SERIAL_STM32)     += stm32-usart.o
>
>  # GPIOLIB helpers for modem control lines
>  obj-$(CONFIG_SERIAL_MCTRL_GPIO)        += serial_mctrl_gpio.o
> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
> new file mode 100644
> index 0000000..4a6eab6
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,739 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Inspired by st-asc.c from STMicroelectronics (c)
> + */
> +
> +#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/module.h>
> +#include <linux/serial.h>
> +#include <linux/console.h>
> +#include <linux/sysrq.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/delay.h>
> +#include <linux/spinlock.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/serial_core.h>
> +#include <linux/clk.h>
> +
> +#define DRIVER_NAME "stm32-usart"
> +
> +/* Register offsets */
> +#define USART_SR               0x00
> +#define USART_DR               0x04
> +#define USART_BRR              0x08
> +#define USART_CR1              0x0c
> +#define USART_CR2              0x10
> +#define USART_CR3              0x14
> +#define USART_GTPR             0x18
> +
> +/* USART_SR */
> +#define USART_SR_PE            BIT(0)
> +#define USART_SR_FE            BIT(1)
> +#define USART_SR_NF            BIT(2)
> +#define USART_SR_ORE           BIT(3)
> +#define USART_SR_IDLE          BIT(4)
> +#define USART_SR_RXNE          BIT(5)
> +#define USART_SR_TC            BIT(6)
> +#define USART_SR_TXE           BIT(7)
> +#define USART_SR_LBD           BIT(8)
> +#define USART_SR_CTS           BIT(9)
> +#define USART_SR_ERR_MASK      (USART_SR_LBD | USART_SR_ORE | \
> +                                USART_SR_FE | USART_SR_PE)
> +/* Dummy bits */
> +#define USART_SR_DUMMY_RX      BIT(16)
> +
> +/* USART_DR */
> +#define USART_DR_MASK          GENMASK(8, 0)
> +
> +/* USART_BRR */
> +#define USART_BRR_DIV_F_MASK   GENMASK(3, 0)
> +#define USART_BRR_DIV_M_MASK   GENMASK(15, 4)
> +#define USART_BRR_DIV_M_SHIFT  4
> +
> +/* USART_CR1 */
> +#define USART_CR1_SBK          BIT(0)
> +#define USART_CR1_RWU          BIT(1)
> +#define USART_CR1_RE           BIT(2)
> +#define USART_CR1_TE           BIT(3)
> +#define USART_CR1_IDLEIE       BIT(4)
> +#define USART_CR1_RXNEIE       BIT(5)
> +#define USART_CR1_TCIE         BIT(6)
> +#define USART_CR1_TXEIE                BIT(7)
> +#define USART_CR1_PEIE         BIT(8)
> +#define USART_CR1_PS           BIT(9)
> +#define USART_CR1_PCE          BIT(10)
> +#define USART_CR1_WAKE         BIT(11)
> +#define USART_CR1_M            BIT(12)
> +#define USART_CR1_UE           BIT(13)
> +#define USART_CR1_OVER8                BIT(15)
> +#define USART_CR1_IE_MASK      GENMASK(8, 4)
> +
> +/* USART_CR2 */
> +#define USART_CR2_ADD_MASK     GENMASK(3, 0)
> +#define USART_CR2_LBDL         BIT(5)
> +#define USART_CR2_LBDIE                BIT(6)
> +#define USART_CR2_LBCL         BIT(8)
> +#define USART_CR2_CPHA         BIT(9)
> +#define USART_CR2_CPOL         BIT(10)
> +#define USART_CR2_CLKEN                BIT(11)
> +#define USART_CR2_STOP_2B      BIT(13)
> +#define USART_CR2_STOP_MASK    GENMASK(13, 12)
> +#define USART_CR2_LINEN                BIT(14)
> +
> +/* USART_CR3 */
> +#define USART_CR3_EIE          BIT(0)
> +#define USART_CR3_IREN         BIT(1)
> +#define USART_CR3_IRLP         BIT(2)
> +#define USART_CR3_HDSEL                BIT(3)
> +#define USART_CR3_NACK         BIT(4)
> +#define USART_CR3_SCEN         BIT(5)
> +#define USART_CR3_DMAR         BIT(6)
> +#define USART_CR3_DMAT         BIT(7)
> +#define USART_CR3_RTSE         BIT(8)
> +#define USART_CR3_CTSE         BIT(9)
> +#define USART_CR3_CTSIE                BIT(10)
> +#define USART_CR3_ONEBIT       BIT(11)
> +
> +/* USART_GTPR */
> +#define USART_GTPR_PSC_MASK    GENMASK(7, 0)
> +#define USART_GTPR_GT_MASK     GENMASK(15, 8)
> +
> +#define DRIVER_NAME "stm32-usart"
> +#define STM32_SERIAL_NAME "ttyS"
> +#define STM32_MAX_PORTS 6
> +
> +struct stm32_port {
> +       struct uart_port port;
> +       struct clk *clk;
> +       bool hw_flow_control;
> +};
> +
> +static struct stm32_port stm32_ports[STM32_MAX_PORTS];
> +static struct uart_driver stm32_usart_driver;
> +
> +static void stm32_stop_tx(struct uart_port *port);
> +
> +static inline struct stm32_port *to_stm32_port(struct uart_port *port)
> +{
> +       return container_of(port, struct stm32_port, port);
> +}
> +
> +static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +       u32 val;
> +
> +       val = readl_relaxed(port->membase + reg);
> +       val |= bits;
> +       writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +       u32 val;
> +
> +       val = readl_relaxed(port->membase + reg);
> +       val &= ~bits;
> +       writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_receive_chars(struct uart_port *port)
> +{
> +       struct tty_port *tport = &port->state->port;
> +       unsigned long c;
> +       u32 sr;
> +       char flag;
> +
> +       if (port->irq_wake)
> +               pm_wakeup_event(tport->tty->dev, 0);
> +
> +       while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
> +               sr |= USART_SR_DUMMY_RX;
> +               c = readl_relaxed(port->membase + USART_DR);
> +               flag = TTY_NORMAL;
> +               port->icount.rx++;
> +
> +               if (sr & USART_SR_ERR_MASK) {
> +                       if (sr & USART_SR_LBD) {
> +                               port->icount.brk++;
> +                               if (uart_handle_break(port))
> +                                       continue;
> +                       } else if (sr & USART_SR_ORE) {
> +                               port->icount.overrun++;
> +                       } else if (sr & USART_SR_PE) {
> +                               port->icount.parity++;
> +                       } else if (sr & USART_SR_FE) {
> +                               port->icount.frame++;
> +                       }
> +
> +                       sr &= port->read_status_mask;
> +
> +                       if (sr & USART_SR_LBD)
> +                               flag = TTY_BREAK;
> +                       else if (sr & USART_SR_PE)
> +                               flag = TTY_PARITY;
> +                       else if (sr & USART_SR_FE)
> +                               flag = TTY_FRAME;
> +               }
> +
> +               if (uart_handle_sysrq_char(port, c))
> +                       continue;
> +               uart_insert_char(port, sr, USART_SR_ORE, c, flag);
> +       }
> +
> +       spin_unlock(&port->lock);
> +       tty_flip_buffer_push(tport);
> +       spin_lock(&port->lock);
> +}
> +
> +static void stm32_transmit_chars(struct uart_port *port)
> +{
> +       struct circ_buf *xmit = &port->state->xmit;
> +
> +       if (port->x_char) {
> +               writel_relaxed(port->x_char, port->membase + USART_DR);
> +               port->x_char = 0;
> +               port->icount.tx++;
> +               return;
> +       }
> +
> +       if (uart_tx_stopped(port)) {
> +               stm32_stop_tx(port);
> +               return;
> +       }
> +
> +       if (uart_circ_empty(xmit)) {
> +               stm32_stop_tx(port);
> +               return;
> +       }
> +
> +       writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
> +       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> +       port->icount.tx++;
> +
> +       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> +               uart_write_wakeup(port);
> +
> +       if (uart_circ_empty(xmit))
> +               stm32_stop_tx(port);
> +}
> +
> +static irqreturn_t stm32_interrupt(int irq, void *ptr)
> +{
> +       struct uart_port *port = ptr;
> +       u32 sr;
> +
> +       spin_lock(&port->lock);
> +
> +       sr = readl_relaxed(port->membase + USART_SR);
> +
> +       if (sr & USART_SR_RXNE)
> +               stm32_receive_chars(port);
> +
> +       if (sr & USART_SR_TXE)
> +               stm32_transmit_chars(port);
> +
> +       spin_unlock(&port->lock);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static unsigned int stm32_tx_empty(struct uart_port *port)
> +{
> +       return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
> +}
> +
> +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +       if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
> +               stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
> +       else
> +               stm32_clr_bits(port, USART_CR3, USART_CR3_RTSE);
> +}
> +
> +static unsigned int stm32_get_mctrl(struct uart_port *port)
> +{
> +       /* This routine is used to get signals of: DCD, DSR, RI, and CTS */
> +       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
> +}
> +
> +/* Transmit stop */
> +static void stm32_stop_tx(struct uart_port *port)
> +{
> +       stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
> +}
> +
> +/* There are probably characters waiting to be transmitted. */
> +static void stm32_start_tx(struct uart_port *port)
> +{
> +       struct circ_buf *xmit = &port->state->xmit;
> +
> +       if (uart_circ_empty(xmit))
> +               return;
> +
> +       stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
> +}
> +
> +/* Throttle the remote when input buffer is about to overflow. */
> +static void stm32_throttle(struct uart_port *port)
> +{
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +/* Unthrottle the remote, the input buffer can now accept data. */
> +static void stm32_unthrottle(struct uart_port *port)
> +{
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       stm32_set_bits(port, USART_CR1, USART_CR1_RXNEIE);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +/* Receive stop */
> +static void stm32_stop_rx(struct uart_port *port)
> +{
> +       stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
> +}
> +
> +/* Handle breaks - ignored by us */
> +static void stm32_break_ctl(struct uart_port *port, int break_state)
> +{
> +}
> +
> +static int stm32_startup(struct uart_port *port)
> +{
> +       const char *name = to_platform_device(port->dev)->name;
> +       u32 val;
> +       int ret;
> +
> +       ret = request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
> +                         name, port);
> +       if (ret)
> +               return ret;
> +
> +       val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +       stm32_set_bits(port, USART_CR1, val);
> +
> +       return 0;
> +}
> +
> +static void stm32_shutdown(struct uart_port *port)
> +{
> +       u32 val;
> +
> +       val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +       stm32_set_bits(port, USART_CR1, val);
> +
> +       free_irq(port->irq, port);
> +}
> +
> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
> +                           struct ktermios *old)
> +{
> +       struct stm32_port *stm32_port = to_stm32_port(port);
> +       unsigned int baud;
> +       u32 usartdiv, mantissa, fraction, oversampling;
> +       tcflag_t cflag = termios->c_cflag;
> +       u32 cr1, cr2, cr3;
> +       unsigned long flags;
> +
> +       if (!stm32_port->hw_flow_control)
> +               cflag &= ~CRTSCTS;
> +
> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       /* Stop serial port and reset value */
> +       writel_relaxed(0, port->membase + USART_CR1);
> +
> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
> +       cr2 = 0;
> +       cr3 = 0;
> +
> +       if (cflag & CSTOPB)
> +               cr2 |= USART_CR2_STOP_2B;
> +
> +       if (cflag & PARENB) {
> +               cr1 |= USART_CR1_PCE;
> +               if ((cflag & CSIZE) == CS8)
> +                       cr1 |= USART_CR1_M;
> +       }
> +
> +       if (cflag & PARODD)
> +               cr1 |= USART_CR1_PS;
> +
> +       port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
> +       if (cflag & CRTSCTS) {
> +               port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
> +               cr3 |= USART_CR3_CTSE;
> +       }
> +
> +       usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
> +
> +       /*
> +        * The USART supports 16 or 8 times oversampling.
> +        * By default we prefer 16 times oversampling, so that the receiver
> +        * has a better tolerance to clock deviations.
> +        * 8 times oversampling is only used to achieve higher speeds.
> +        */
> +       if (usartdiv < 16) {
> +               oversampling = 8;
> +               stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
> +       } else {
> +               oversampling = 16;
> +               stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
> +       }
> +
> +       mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
> +       fraction = usartdiv % oversampling;
> +       writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
> +
> +       uart_update_timeout(port, cflag, baud);
> +
> +       port->read_status_mask = USART_SR_ORE;
> +       if (termios->c_iflag & INPCK)
> +               port->read_status_mask |= USART_SR_PE | USART_SR_FE;
> +       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
> +               port->read_status_mask |= USART_SR_LBD;
> +
> +       /* Characters to ignore */
> +       port->ignore_status_mask = 0;
> +       if (termios->c_iflag & IGNPAR)
> +               port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
> +       if (termios->c_iflag & IGNBRK) {
> +               port->ignore_status_mask |= USART_SR_LBD;
> +               /*
> +                * If we're ignoring parity and break indicators,
> +                * ignore overruns too (for real raw support).
> +                */
> +               if (termios->c_iflag & IGNPAR)
> +                       port->ignore_status_mask |= USART_SR_ORE;
> +       }
> +
> +       /* Ignore all characters if CREAD is not set */
> +       if ((termios->c_cflag & CREAD) == 0)
> +               port->ignore_status_mask |= USART_SR_DUMMY_RX;
> +
> +       writel_relaxed(cr3, port->membase + USART_CR3);
> +       writel_relaxed(cr2, port->membase + USART_CR2);
> +       writel_relaxed(cr1, port->membase + USART_CR1);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *stm32_type(struct uart_port *port)
> +{
> +       return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
> +}
> +
> +static void stm32_release_port(struct uart_port *port)
> +{
> +}
> +
> +static int stm32_request_port(struct uart_port *port)
> +{
> +       return 0;
> +}
> +
> +static void stm32_config_port(struct uart_port *port, int flags)
> +{
> +       if (flags & UART_CONFIG_TYPE)
> +               port->type = PORT_STM32;
> +}
> +
> +static int
> +stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> +       /* No user changeable parameters */
> +       return -EINVAL;
> +}
> +
> +static void stm32_pm(struct uart_port *port, unsigned int state,
> +               unsigned int oldstate)
> +{
> +       struct stm32_port *stm32port = container_of(port,
> +                       struct stm32_port, port);
> +       unsigned long flags = 0;
> +
> +       switch (state) {
> +       case UART_PM_STATE_ON:
> +               clk_prepare_enable(stm32port->clk);
> +               break;
> +       case UART_PM_STATE_OFF:
> +               spin_lock_irqsave(&port->lock, flags);
> +               stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               clk_disable_unprepare(stm32port->clk);
> +               break;
> +       }
> +}
> +
> +static const struct uart_ops stm32_uart_ops = {
> +       .tx_empty       = stm32_tx_empty,
> +       .set_mctrl      = stm32_set_mctrl,
> +       .get_mctrl      = stm32_get_mctrl,
> +       .stop_tx        = stm32_stop_tx,
> +       .start_tx       = stm32_start_tx,
> +       .throttle       = stm32_throttle,
> +       .unthrottle     = stm32_unthrottle,
> +       .stop_rx        = stm32_stop_rx,
> +       .break_ctl      = stm32_break_ctl,
> +       .startup        = stm32_startup,
> +       .shutdown       = stm32_shutdown,
> +       .set_termios    = stm32_set_termios,
> +       .pm             = stm32_pm,
> +       .type           = stm32_type,
> +       .release_port   = stm32_release_port,
> +       .request_port   = stm32_request_port,
> +       .config_port    = stm32_config_port,
> +       .verify_port    = stm32_verify_port,
> +};
> +
> +static int stm32_init_port(struct stm32_port *stm32port,
> +                         struct platform_device *pdev)
> +{
> +       struct uart_port *port = &stm32port->port;
> +       struct resource *res;
> +       int ret;
> +
> +       port->iotype    = UPIO_MEM;
> +       port->flags     = UPF_BOOT_AUTOCONF;
> +       port->ops       = &stm32_uart_ops;
> +       port->dev       = &pdev->dev;
> +       port->irq       = platform_get_irq(pdev, 0);
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       port->membase = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(port->membase))
> +               return PTR_ERR(port->membase);
> +       port->mapbase = res->start;
> +
> +       spin_lock_init(&port->lock);
> +
> +       stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> +       if (IS_ERR(stm32port->clk))
> +               return PTR_ERR(stm32port->clk);
> +
> +       /* Ensure that clk rate is correct by enabling the clk */
> +       ret = clk_prepare_enable(stm32port->clk);
> +       if (ret)
> +               return ret;
> +
> +       stm32port->port.uartclk = clk_get_rate(stm32port->clk);
> +       if (!stm32port->port.uartclk)
> +               ret = -EINVAL;
> +
> +       clk_disable_unprepare(stm32port->clk);
> +
> +       return ret;
> +}
> +
> +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       int id;
> +
> +       if (!np)
> +               return NULL;
> +
> +       id = of_alias_get_id(np, "serial");
> +       if (id < 0)
> +               id = 0;
> +
> +       if (WARN_ON(id >= STM32_MAX_PORTS))
> +               return NULL;
> +
> +       stm32_ports[id].hw_flow_control = of_property_read_bool(np,
> +                                                       "auto-flow-control");
> +       stm32_ports[id].port.line = id;
> +       return &stm32_ports[id];
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id stm32_match[] = {
> +       { .compatible = "st,stm32-usart", },
> +       { .compatible = "st,stm32-uart", },
> +       {},
> +};
> +
> +MODULE_DEVICE_TABLE(of, stm32_match);
> +#endif
> +
> +static int stm32_serial_probe(struct platform_device *pdev)
> +{
> +       int ret;
> +       struct stm32_port *stm32port;
> +
> +       stm32port = stm32_of_get_stm32_port(pdev);
> +       if (!stm32port)
> +               return -ENODEV;
> +
> +       ret = stm32_init_port(stm32port, pdev);
> +       if (ret)
> +               return ret;
> +
> +       ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
> +       if (ret)
> +               return ret;
> +
> +       platform_set_drvdata(pdev, &stm32port->port);
> +
> +       return 0;
> +}
> +
> +static int stm32_serial_remove(struct platform_device *pdev)
> +{
> +       struct uart_port *port = platform_get_drvdata(pdev);
> +
> +       return uart_remove_one_port(&stm32_usart_driver, port);
> +}
> +
> +
> +#ifdef CONFIG_SERIAL_STM32_CONSOLE
> +static void stm32_console_putchar(struct uart_port *port, int ch)
> +{
> +       while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
> +               cpu_relax();
> +
> +       writel_relaxed(ch, port->membase + USART_DR);
> +}
> +
> +static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
> +{
> +       struct uart_port *port = &stm32_ports[co->index].port;
> +       unsigned long flags;
> +       u32 old_cr1, new_cr1;
> +       int locked = 1;
> +
> +       local_irq_save(flags);
> +       if (port->sysrq)
> +               locked = 0;
> +       else if (oops_in_progress)
> +               locked = spin_trylock(&port->lock);
> +       else
> +               spin_lock(&port->lock);
> +
> +       /* Save and disable interrupts */
> +       old_cr1 = readl_relaxed(port->membase + USART_CR1);
> +       new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
> +       writel_relaxed(new_cr1, port->membase + USART_CR1);
> +
> +       uart_console_write(port, s, cnt, stm32_console_putchar);
> +
> +       /* Restore interrupt state */
> +       writel_relaxed(old_cr1, port->membase + USART_CR1);
> +
> +       if (locked)
> +               spin_unlock(&port->lock);
> +       local_irq_restore(flags);
> +}
> +
> +static int stm32_console_setup(struct console *co, char *options)
> +{
> +       struct stm32_port *stm32port;
> +       int baud = 9600;
> +       int bits = 8;
> +       int parity = 'n';
> +       int flow = 'n';
> +
> +       if (co->index >= STM32_MAX_PORTS)
> +               return -ENODEV;
> +
> +       stm32port = &stm32_ports[co->index];
> +
> +       /*
> +        * This driver does not support early console initialization
> +        * (use ARM early printk support instead), so we only expect
> +        * this to be called during the uart port registration when the
> +        * driver gets probed and the port should be mapped at that point.
> +        */
> +       if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
> +               return -ENXIO;
> +
> +       if (options)
> +               uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> +       return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
> +}
> +
> +static struct console stm32_console = {
> +       .name           = STM32_SERIAL_NAME,
> +       .device         = uart_console_device,
> +       .write          = stm32_console_write,
> +       .setup          = stm32_console_setup,
> +       .flags          = CON_PRINTBUFFER,
> +       .index          = -1,
> +       .data           = &stm32_usart_driver,
> +};
> +
> +#define STM32_SERIAL_CONSOLE (&stm32_console)
> +
> +#else
> +#define STM32_SERIAL_CONSOLE NULL
> +#endif /* CONFIG_SERIAL_STM32_CONSOLE */
> +
> +static struct uart_driver stm32_usart_driver = {
> +       .driver_name    = DRIVER_NAME,
> +       .dev_name       = STM32_SERIAL_NAME,
> +       .major          = 0,
> +       .minor          = 0,
> +       .nr             = STM32_MAX_PORTS,
> +       .cons           = STM32_SERIAL_CONSOLE,
> +};
> +
> +static struct platform_driver stm32_serial_driver = {
> +       .probe          = stm32_serial_probe,
> +       .remove         = stm32_serial_remove,
> +       .driver = {
> +               .name   = DRIVER_NAME,
> +               .of_match_table = of_match_ptr(stm32_match),
> +       },
> +};
> +
> +static int __init usart_init(void)
> +{
> +       static char banner[] __initdata = "STM32 USART driver initialized";
> +       int ret;
> +
> +       pr_info("%s\n", banner);
> +
> +       ret = uart_register_driver(&stm32_usart_driver);
> +       if (ret)
> +               return ret;
> +
> +       ret = platform_driver_register(&stm32_serial_driver);
> +       if (ret)
> +               uart_unregister_driver(&stm32_usart_driver);
> +
> +       return ret;
> +}
> +
> +static void __exit usart_exit(void)
> +{
> +       platform_driver_unregister(&stm32_serial_driver);
> +       uart_unregister_driver(&stm32_usart_driver);
> +}
> +
> +module_init(usart_init);
> +module_exit(usart_exit);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index b212281..93ba148 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -258,4 +258,7 @@
>  /* Cris v10 / v32 SoC */
>  #define PORT_CRIS      112
>
> +/* STM32 USART */
> +#define PORT_STM32     113
> +
>  #endif /* _UAPILINUX_SERIAL_CORE_H */
> --
> 1.9.1
>



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH 07/18] media controller: rename the tuner entity
From: Hans Verkuil @ 2015-05-09  9:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Linux Media Mailing List, Mauro Carvalho Chehab, Jonathan Corbet,
	Matthias Schwarzott, Antti Palosaari, Olli Salonen, Prabhakar Lad,
	Sakari Ailus, Laurent Pinchart, linux-doc, linux-api
In-Reply-To: <554CC8E3.2030308@xs4all.nl>

>>> Brainstorming:
>>>
>>> It might be better to map each device node to an entity and each hardware
>>> component (tuner, DMA engine) to an entity, and avoid this mixing of
>>> hw entity vs device node entity.

There are two options here:

either make each device node an entity, or expose the device node information
as properties of an entity.

The latter would be backwards compatible with what we do today. I'm trying to
think of reasons why you would want to make each device node an entity in its
own right.

The problem today is that a video_device representing a video/vbi/radio/swradio
device node is an entity, but it is really representing the dma engine. Which
is weird for radio devices since there is no dma engine there.

Implementing device nodes as entities in their own right does solve this problem,
but implementing it as properties would be weird since a radio device node would
be a property of a radio tuner entity, which can be a subdevice driver which means
that the bridge driver would have to add the radio device property to a subdev
driver, which feels really wrong to me.

With this in mind I do think representing device nodes as entities in their own
right makes sense. But I would do this also for a v4l-subdev node. It's very
inconsistent not to do that.

Regards,

	Hans

^ permalink raw reply

* [PATCH v8 16/16] MAINTAINERS: Add entry for STM32 MCUs
From: Maxime Coquelin @ 2015-05-09  7:53 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle, peter,
	andy.shevchenko, cw00.choi, Russell King, Daniel Lezcano, joe,
	Vladimir Zapolskiy, lee.jones, Daniel Thompson
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov,
	Rusty Russell, Kees Cook, Michal Marek, linux-doc,
	linux-arm-kernel, linux-kernel, devicetree, linux-gpio,
	linux-serial, linux-arch
In-Reply-To: <1431158038-3813-1-git-send-email-mcoquelin.stm32@gmail.com>

Add a MAINTAINER entry covering all STM32 machine and drivers files.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 2e5bbc0..858d821 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1479,6 +1479,14 @@ F:	drivers/usb/host/ehci-st.c
 F:	drivers/usb/host/ohci-st.c
 F:	drivers/ata/ahci_st.c
 
+ARM/STM32 ARCHITECTURE
+M:	Maxime Coquelin <mcoquelin.stm32@gmail.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mcoquelin/stm32.git
+N:	stm32
+F:	drivers/clocksource/armv7m_systick.c
+
 ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
 M:	Lennert Buytenhek <kernel@wantstofly.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-- 
1.9.1


^ permalink raw reply related

* [PATCH v8 15/16] ARM: configs: Add STM32 defconfig
From: Maxime Coquelin @ 2015-05-09  7:53 UTC (permalink / raw)
  To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan-XLVq0VzYD2Y,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, pebolle-IWqWACnzNjzz+pZb47iToQ,
	peter-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8,
	andy.shevchenko-Re5JQEeQqe8AvxtiuMwx3w,
	cw00.choi-Sze3O3UU22JBDgjK7y7TUQ, Russell King, Daniel Lezcano,
	joe-6d6DIl74uiNBDgjK7y7TUQ, Vladimir Zapolskiy,
	lee.jones-QSEj5FYQhm4dnm+yROfE0A, Daniel Thompson
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov,
	Rusty Russell, Kees Cook, Michal Marek,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	linux-arch-u79uwXL29TZNg+MwTxZMZA
In-Reply-To: <1431158038-3813-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

This patch adds a new config for STM32 MCUs.
STM32F429 Discovery board boots successfully with this config applied.

Tested-by: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 arch/arm/configs/stm32_defconfig | 70 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 arch/arm/configs/stm32_defconfig

diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
new file mode 100644
index 0000000..af757925
--- /dev/null
+++ b/arch/arm/configs/stm32_defconfig
@@ -0,0 +1,70 @@
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="./rootfs.cpio"
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
+CONFIG_ARCH_STM32=y
+CONFIG_SET_MEM_PARAM=y
+CONFIG_DRAM_BASE=0x90000000
+CONFIG_FLASH_MEM_BASE=0x08000000
+CONFIG_FLASH_SIZE=0x00200000
+CONFIG_PREEMPT=y
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_XIP_KERNEL=y
+CONFIG_XIP_PHYS_ADDR=0x08008000
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_COREDUMP is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_EEPROM_93CX6=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_STM32=y
+CONFIG_SERIAL_STM32_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_NLS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
-- 
1.9.1

^ permalink raw reply related

* [PATCH v8 14/16] ARM: dts: Introduce STM32F429 MCU
From: Maxime Coquelin @ 2015-05-09  7:53 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle, peter,
	andy.shevchenko, cw00.choi, Russell King, Daniel Lezcano, joe,
	Vladimir Zapolskiy, lee.jones, Daniel Thompson
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov,
	Rusty Russell, Kees Cook, Michal Marek, linux-doc,
	linux-arm-kernel, linux-kernel, devicetree, linux-gpio,
	linux-serial, linux-arch
In-Reply-To: <1431158038-3813-1-git-send-email-mcoquelin.stm32@gmail.com>

The STMicrolectornics's STM32F429 MCU has the following main features:
 - Cortex-M4 core running up to @180MHz
 - 2MB internal flash, 256KBytes internal RAM
 - FMC controller to connect SDRAM, NOR and NAND memories
 - SD/MMC/SDIO support
 - Ethernet controller
 - USB OTFG FS & HS controllers
 - I2C, SPI, CAN busses support
 - Several 16 & 32 bits general purpose timers
 - Serial Audio interface
 - LCD controller

Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/boot/dts/Makefile            |   1 +
 arch/arm/boot/dts/stm32f429-disco.dts |  71 +++++++++++
 arch/arm/boot/dts/stm32f429.dtsi      | 227 ++++++++++++++++++++++++++++++++++
 3 files changed, 299 insertions(+)
 create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
 create mode 100644 arch/arm/boot/dts/stm32f429.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 86217db..db1d8c6 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -520,6 +520,7 @@ dtb-$(CONFIG_ARCH_STI) += \
 	stih416-b2020.dtb \
 	stih416-b2020e.dtb \
 	stih418-b2199.dtb
+dtb-$(CONFIG_ARCH_STM32)+= stm32f429-disco.dtb
 dtb-$(CONFIG_MACH_SUN4I) += \
 	sun4i-a10-a1000.dtb \
 	sun4i-a10-ba10-tvbox.dtb \
diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
new file mode 100644
index 0000000..6b9aa59
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429-disco.dts
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 - Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file 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 file; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "stm32f429.dtsi"
+
+/ {
+	model = "STMicroelectronics STM32F429i-DISCO board";
+	compatible = "st,stm32f429i-disco", "st,stm32f429";
+
+	chosen {
+		bootargs = "console=ttyS0,115200 root=/dev/ram rdinit=/linuxrc";
+		linux,stdout-path = &usart1;
+	};
+
+	memory {
+		reg = <0x90000000 0x800000>;
+	};
+
+	aliases {
+		serial0 = &usart1;
+	};
+};
+
+&usart1 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
new file mode 100644
index 0000000..2719f3a
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2015 - Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file 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 file; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "armv7-m.dtsi"
+#include  <dt-bindings/mfd/stm32f4-rcc.h>
+
+/ {
+	clocks {
+		clk_sysclk: clk-sysclk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_hclk: clk-hclk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_pclk1: clk-pclk1 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <45000000>;
+		};
+
+		clk_pclk2: clk-pclk2 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <90000000>;
+		};
+
+		clk_pmtr1: clk-pmtr1 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <90000000>;
+		};
+
+		clk_pmtr2: clk-pmtr2 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_systick: clk-systick {
+			compatible = "fixed-factor-clock";
+			clocks = <&clk_hclk>;
+			#clock-cells = <0>;
+			clock-div = <8>;
+			clock-mult = <1>;
+		};
+	};
+
+	soc {
+		timer2: timer@40000000 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000000 0x400>;
+			interrupts = <28>;
+			resets = <&rcc STM32F4_APB1_RESET(TIM2)>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer3: timer@40000400 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000400 0x400>;
+			interrupts = <29>;
+			resets = <&rcc STM32F4_APB1_RESET(TIM3)>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer4: timer@40000800 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000800 0x400>;
+			interrupts = <30>;
+			resets = <&rcc STM32F4_APB1_RESET(TIM4)>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer5: timer@40000c00 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000c00 0x400>;
+			interrupts = <50>;
+			resets = <&rcc STM32F4_APB1_RESET(TIM5)>;
+			clocks = <&clk_pmtr1>;
+		};
+
+		timer6: timer@40001000 {
+			compatible = "st,stm32-timer";
+			reg = <0x40001000 0x400>;
+			interrupts = <54>;
+			resets = <&rcc STM32F4_APB1_RESET(TIM6)>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer7: timer@40001400 {
+			compatible = "st,stm32-timer";
+			reg = <0x40001400 0x400>;
+			interrupts = <55>;
+			resets = <&rcc STM32F4_APB1_RESET(TIM7)>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		usart2: serial@40004400 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40004400 0x400>;
+			interrupts = <38>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart3: serial@40004800 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40004800 0x400>;
+			interrupts = <39>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart4: serial@40004c00 {
+			compatible = "st,stm32-uart";
+			reg = <0x40004c00 0x400>;
+			interrupts = <52>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart5: serial@40005000 {
+			compatible = "st,stm32-uart";
+			reg = <0x40005000 0x400>;
+			interrupts = <53>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart7: serial@40007800 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40007800 0x400>;
+			interrupts = <82>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart8: serial@40007c00 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40007c00 0x400>;
+			interrupts = <83>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart1: serial@40011000 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40011000 0x400>;
+			interrupts = <37>;
+			clocks = <&clk_pclk2>;
+			status = "disabled";
+		};
+
+		usart6: serial@40011400 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40011400 0x400>;
+			interrupts = <71>;
+			clocks = <&clk_pclk2>;
+			status = "disabled";
+		};
+
+		rcc: rcc@40023810 {
+			#reset-cells = <1>;
+			compatible = "st,stm32-rcc";
+			reg = <0x40023800 0x400>;
+		};
+	};
+};
+
+&systick {
+	clocks = <&clk_systick>;
+	status = "okay";
+};
-- 
1.9.1

^ permalink raw reply related

* [PATCH v8 13/16] ARM: dts: Add ARM System timer as clocksource in armv7m
From: Maxime Coquelin @ 2015-05-09  7:53 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle, peter,
	andy.shevchenko, cw00.choi, Russell King, Daniel Lezcano, joe,
	Vladimir Zapolskiy, lee.jones, Daniel Thompson
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov,
	Rusty Russell, Kees Cook, Michal Marek, linux-doc,
	linux-arm-kernel, linux-kernel, devicetree, linux-gpio,
	linux-serial, linux-arch
In-Reply-To: <1431158038-3813-1-git-send-email-mcoquelin.stm32@gmail.com>

Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/boot/dts/armv7-m.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/armv7-m.dtsi b/arch/arm/boot/dts/armv7-m.dtsi
index 5a660d0..b1ad7cf 100644
--- a/arch/arm/boot/dts/armv7-m.dtsi
+++ b/arch/arm/boot/dts/armv7-m.dtsi
@@ -8,6 +8,12 @@
 		reg = <0xe000e100 0xc00>;
 	};
 
+	systick: timer@e000e010 {
+		compatible = "arm,armv7m-systick";
+		reg = <0xe000e010 0x10>;
+		status = "disabled";
+	};
+
 	soc {
 		#address-cells = <1>;
 		#size-cells = <1>;
-- 
1.9.1

^ permalink raw reply related

* [PATCH v8 12/16] ARM: Add STM32 family machine
From: Maxime Coquelin @ 2015-05-09  7:53 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle, peter,
	andy.shevchenko, cw00.choi, Russell King, Daniel Lezcano, joe,
	Vladimir Zapolskiy, lee.jones, Daniel Thompson
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov,
	Rusty Russell, Kees Cook, Michal Marek, linux-doc,
	linux-arm-kernel, linux-kernel, devicetree, linux-gpio,
	linux-serial, linux-arch
In-Reply-To: <1431158038-3813-1-git-send-email-mcoquelin.stm32@gmail.com>

STMicrolectronics's STM32 series is a family of Cortex-M
microcontrollers. It is used in various applications, and
proposes a wide range of peripherals.

Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 Documentation/arm/stm32/overview.txt           | 32 ++++++++++++++++++++++++++
 Documentation/arm/stm32/stm32f429-overview.txt | 22 ++++++++++++++++++
 arch/arm/Kconfig                               | 18 +++++++++++++++
 arch/arm/Makefile                              |  1 +
 arch/arm/mach-stm32/Makefile                   |  1 +
 arch/arm/mach-stm32/Makefile.boot              |  3 +++
 arch/arm/mach-stm32/board-dt.c                 | 19 +++++++++++++++
 7 files changed, 96 insertions(+)
 create mode 100644 Documentation/arm/stm32/overview.txt
 create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
 create mode 100644 arch/arm/mach-stm32/Makefile
 create mode 100644 arch/arm/mach-stm32/Makefile.boot
 create mode 100644 arch/arm/mach-stm32/board-dt.c

diff --git a/Documentation/arm/stm32/overview.txt b/Documentation/arm/stm32/overview.txt
new file mode 100644
index 0000000..09aed55
--- /dev/null
+++ b/Documentation/arm/stm32/overview.txt
@@ -0,0 +1,32 @@
+			STM32 ARM Linux Overview
+			========================
+
+Introduction
+------------
+
+  The STMicroelectronics family of Cortex-M based MCUs are supported by the
+  'STM32' platform of ARM Linux. Currently only the STM32F429 is supported.
+
+
+Configuration
+-------------
+
+  A generic configuration is provided for STM32 family, and can be used as the
+  default by
+	make stm32_defconfig
+
+Layout
+------
+
+  All the files for multiple machine families are located in the platform code
+  contained in arch/arm/mach-stm32
+
+  There is a generic board board-dt.c in the mach folder which support
+  Flattened Device Tree, which means, it works with any compatible board with
+  Device Trees.
+
+
+Document Author
+---------------
+
+  Maxime Coquelin <mcoquelin.stm32@gmail.com>
diff --git a/Documentation/arm/stm32/stm32f429-overview.txt b/Documentation/arm/stm32/stm32f429-overview.txt
new file mode 100644
index 0000000..5206822
--- /dev/null
+++ b/Documentation/arm/stm32/stm32f429-overview.txt
@@ -0,0 +1,22 @@
+			STM32F429 Overview
+			==================
+
+  Introduction
+  ------------
+	The STM32F429 is a Cortex-M4 MCU aimed at various applications.
+	It features:
+	- ARM Cortex-M4 up to 180MHz with FPU
+	- 2MB internal Flash Memory
+	- External memory support through FMC controller (PSRAM, SDRAM, NOR, NAND)
+	- I2C, SPI, SAI, CAN, USB OTG, Ethernet controllers
+	- LCD controller & Camera interface
+	- Cryptographic processor
+
+  Resources
+  ---------
+	Datasheet and reference manual are publicly available on ST website:
+	- http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1577/LN1806?ecmp=stm32f429-439_pron_pr-ces2014_nov2013
+
+  Document Author
+  ---------------
+	Maxime Coquelin <mcoquelin.stm32@gmail.com>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 45df48b..21fe5c8 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -757,6 +757,24 @@ config ARCH_OMAP1
 	help
 	  Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
 
+config ARCH_STM32
+	bool "STMicrolectronics STM32"
+	depends on !MMU
+	select ARCH_HAS_RESET_CONTROLLER
+	select ARM_NVIC
+	select ARMV7M_SYSTICK
+	select AUTO_ZRELADDR
+	select CLKSRC_OF
+	select COMMON_CLK
+	select CPU_V7M
+	select GENERIC_CLOCKEVENTS
+	select NO_IOPORT_MAP
+	select RESET_CONTROLLER
+	select SPARSE_IRQ
+	select USE_OF
+	help
+	  Support for STMicroelectronics STM32 processors.
+
 endchoice
 
 menu "Multiple platform selection"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 985227c..0fac562 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -196,6 +196,7 @@ machine-$(CONFIG_ARCH_SHMOBILE) 	+= shmobile
 machine-$(CONFIG_ARCH_SIRF)		+= prima2
 machine-$(CONFIG_ARCH_SOCFPGA)		+= socfpga
 machine-$(CONFIG_ARCH_STI)		+= sti
+machine-$(CONFIG_ARCH_STM32)		+= stm32
 machine-$(CONFIG_ARCH_SUNXI)		+= sunxi
 machine-$(CONFIG_ARCH_TEGRA)		+= tegra
 machine-$(CONFIG_ARCH_U300)		+= u300
diff --git a/arch/arm/mach-stm32/Makefile b/arch/arm/mach-stm32/Makefile
new file mode 100644
index 0000000..bd0b7b5
--- /dev/null
+++ b/arch/arm/mach-stm32/Makefile
@@ -0,0 +1 @@
+obj-y += board-dt.o
diff --git a/arch/arm/mach-stm32/Makefile.boot b/arch/arm/mach-stm32/Makefile.boot
new file mode 100644
index 0000000..eacfc3f
--- /dev/null
+++ b/arch/arm/mach-stm32/Makefile.boot
@@ -0,0 +1,3 @@
+# Empty file waiting for deletion once Makefile.boot isn't needed any more.
+# Patch waits for application at
+# http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7889/1 .
diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c
new file mode 100644
index 0000000..f2ad772
--- /dev/null
+++ b/arch/arm/mach-stm32/board-dt.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <asm/v7m.h>
+#include <asm/mach/arch.h>
+
+static const char *const stm32_compat[] __initconst = {
+	"st,stm32f429",
+	NULL
+};
+
+DT_MACHINE_START(STM32DT, "STM32 (Device Tree Support)")
+	.dt_compat = stm32_compat,
+	.restart = armv7m_restart,
+MACHINE_END
-- 
1.9.1


^ permalink raw reply related

* [PATCH v8 11/16] serial: stm32-usart: Add STM32 USART Driver
From: Maxime Coquelin @ 2015-05-09  7:53 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle, peter,
	andy.shevchenko, cw00.choi, Russell King, Daniel Lezcano, joe,
	Vladimir Zapolskiy, lee.jones, Daniel Thompson
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov,
	Rusty Russell, Kees Cook, Michal Marek, linux-doc,
	linux-arm-kernel, linux-kernel, devicetree, linux-gpio,
	linux-serial, linux-arch
In-Reply-To: <1431158038-3813-1-git-send-email-mcoquelin.stm32@gmail.com>

This drivers adds support to the STM32 USART controller, which is a
standard serial driver.

Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
Reviewed-by: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/tty/serial/Kconfig       |  17 +
 drivers/tty/serial/Makefile      |   1 +
 drivers/tty/serial/stm32-usart.c | 739 +++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h |   3 +
 4 files changed, 760 insertions(+)
 create mode 100644 drivers/tty/serial/stm32-usart.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index f8120c1..7eb62f1 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1589,6 +1589,23 @@ config SERIAL_SPRD_CONSOLE
 	  with "earlycon" on the kernel command line. The console is
 	  enabled when early_param is processed.
 
+config SERIAL_STM32
+	tristate "STMicroelectronics STM32 serial port support"
+	select SERIAL_CORE
+	depends on ARM || COMPILE_TEST
+	help
+	  This driver is for the on-chip Serial Controller on
+	  STMicroelectronics STM32 MCUs.
+	  USART supports Rx & Tx functionality.
+	  It support all industry standard baud rates.
+
+	  If unsure, say N.
+
+config SERIAL_STM32_CONSOLE
+	bool "Support for console on STM32"
+	depends on SERIAL_STM32=y
+	select SERIAL_CORE_CONSOLE
+
 endmenu
 
 config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index c3ac3d9..61979ce 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
 obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)	+= digicolor-usart.o
 obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o
 obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
+obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
 
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
new file mode 100644
index 0000000..4a6eab6
--- /dev/null
+++ b/drivers/tty/serial/stm32-usart.c
@@ -0,0 +1,739 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Inspired by st-asc.c from STMicroelectronics (c)
+ */
+
+#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "stm32-usart"
+
+/* Register offsets */
+#define USART_SR		0x00
+#define USART_DR		0x04
+#define USART_BRR		0x08
+#define USART_CR1		0x0c
+#define USART_CR2		0x10
+#define USART_CR3		0x14
+#define USART_GTPR		0x18
+
+/* USART_SR */
+#define USART_SR_PE		BIT(0)
+#define USART_SR_FE		BIT(1)
+#define USART_SR_NF		BIT(2)
+#define USART_SR_ORE		BIT(3)
+#define USART_SR_IDLE		BIT(4)
+#define USART_SR_RXNE		BIT(5)
+#define USART_SR_TC		BIT(6)
+#define USART_SR_TXE		BIT(7)
+#define USART_SR_LBD		BIT(8)
+#define USART_SR_CTS		BIT(9)
+#define USART_SR_ERR_MASK	(USART_SR_LBD | USART_SR_ORE | \
+				 USART_SR_FE | USART_SR_PE)
+/* Dummy bits */
+#define USART_SR_DUMMY_RX	BIT(16)
+
+/* USART_DR */
+#define USART_DR_MASK		GENMASK(8, 0)
+
+/* USART_BRR */
+#define USART_BRR_DIV_F_MASK	GENMASK(3, 0)
+#define USART_BRR_DIV_M_MASK	GENMASK(15, 4)
+#define USART_BRR_DIV_M_SHIFT	4
+
+/* USART_CR1 */
+#define USART_CR1_SBK		BIT(0)
+#define USART_CR1_RWU		BIT(1)
+#define USART_CR1_RE		BIT(2)
+#define USART_CR1_TE		BIT(3)
+#define USART_CR1_IDLEIE	BIT(4)
+#define USART_CR1_RXNEIE	BIT(5)
+#define USART_CR1_TCIE		BIT(6)
+#define USART_CR1_TXEIE		BIT(7)
+#define USART_CR1_PEIE		BIT(8)
+#define USART_CR1_PS		BIT(9)
+#define USART_CR1_PCE		BIT(10)
+#define USART_CR1_WAKE		BIT(11)
+#define USART_CR1_M		BIT(12)
+#define USART_CR1_UE		BIT(13)
+#define USART_CR1_OVER8		BIT(15)
+#define USART_CR1_IE_MASK	GENMASK(8, 4)
+
+/* USART_CR2 */
+#define USART_CR2_ADD_MASK	GENMASK(3, 0)
+#define USART_CR2_LBDL		BIT(5)
+#define USART_CR2_LBDIE		BIT(6)
+#define USART_CR2_LBCL		BIT(8)
+#define USART_CR2_CPHA		BIT(9)
+#define USART_CR2_CPOL		BIT(10)
+#define USART_CR2_CLKEN		BIT(11)
+#define USART_CR2_STOP_2B	BIT(13)
+#define USART_CR2_STOP_MASK	GENMASK(13, 12)
+#define USART_CR2_LINEN		BIT(14)
+
+/* USART_CR3 */
+#define USART_CR3_EIE		BIT(0)
+#define USART_CR3_IREN		BIT(1)
+#define USART_CR3_IRLP		BIT(2)
+#define USART_CR3_HDSEL		BIT(3)
+#define USART_CR3_NACK		BIT(4)
+#define USART_CR3_SCEN		BIT(5)
+#define USART_CR3_DMAR		BIT(6)
+#define USART_CR3_DMAT		BIT(7)
+#define USART_CR3_RTSE		BIT(8)
+#define USART_CR3_CTSE		BIT(9)
+#define USART_CR3_CTSIE		BIT(10)
+#define USART_CR3_ONEBIT	BIT(11)
+
+/* USART_GTPR */
+#define USART_GTPR_PSC_MASK	GENMASK(7, 0)
+#define USART_GTPR_GT_MASK	GENMASK(15, 8)
+
+#define DRIVER_NAME "stm32-usart"
+#define STM32_SERIAL_NAME "ttyS"
+#define STM32_MAX_PORTS 6
+
+struct stm32_port {
+	struct uart_port port;
+	struct clk *clk;
+	bool hw_flow_control;
+};
+
+static struct stm32_port stm32_ports[STM32_MAX_PORTS];
+static struct uart_driver stm32_usart_driver;
+
+static void stm32_stop_tx(struct uart_port *port);
+
+static inline struct stm32_port *to_stm32_port(struct uart_port *port)
+{
+	return container_of(port, struct stm32_port, port);
+}
+
+static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+	u32 val;
+
+	val = readl_relaxed(port->membase + reg);
+	val |= bits;
+	writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+	u32 val;
+
+	val = readl_relaxed(port->membase + reg);
+	val &= ~bits;
+	writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_receive_chars(struct uart_port *port)
+{
+	struct tty_port *tport = &port->state->port;
+	unsigned long c;
+	u32 sr;
+	char flag;
+
+	if (port->irq_wake)
+		pm_wakeup_event(tport->tty->dev, 0);
+
+	while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
+		sr |= USART_SR_DUMMY_RX;
+		c = readl_relaxed(port->membase + USART_DR);
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+
+		if (sr & USART_SR_ERR_MASK) {
+			if (sr & USART_SR_LBD) {
+				port->icount.brk++;
+				if (uart_handle_break(port))
+					continue;
+			} else if (sr & USART_SR_ORE) {
+				port->icount.overrun++;
+			} else if (sr & USART_SR_PE) {
+				port->icount.parity++;
+			} else if (sr & USART_SR_FE) {
+				port->icount.frame++;
+			}
+
+			sr &= port->read_status_mask;
+
+			if (sr & USART_SR_LBD)
+				flag = TTY_BREAK;
+			else if (sr & USART_SR_PE)
+				flag = TTY_PARITY;
+			else if (sr & USART_SR_FE)
+				flag = TTY_FRAME;
+		}
+
+		if (uart_handle_sysrq_char(port, c))
+			continue;
+		uart_insert_char(port, sr, USART_SR_ORE, c, flag);
+	}
+
+	spin_unlock(&port->lock);
+	tty_flip_buffer_push(tport);
+	spin_lock(&port->lock);
+}
+
+static void stm32_transmit_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (port->x_char) {
+		writel_relaxed(port->x_char, port->membase + USART_DR);
+		port->x_char = 0;
+		port->icount.tx++;
+		return;
+	}
+
+	if (uart_tx_stopped(port)) {
+		stm32_stop_tx(port);
+		return;
+	}
+
+	if (uart_circ_empty(xmit)) {
+		stm32_stop_tx(port);
+		return;
+	}
+
+	writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
+	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+	port->icount.tx++;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		stm32_stop_tx(port);
+}
+
+static irqreturn_t stm32_interrupt(int irq, void *ptr)
+{
+	struct uart_port *port = ptr;
+	u32 sr;
+
+	spin_lock(&port->lock);
+
+	sr = readl_relaxed(port->membase + USART_SR);
+
+	if (sr & USART_SR_RXNE)
+		stm32_receive_chars(port);
+
+	if (sr & USART_SR_TXE)
+		stm32_transmit_chars(port);
+
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int stm32_tx_empty(struct uart_port *port)
+{
+	return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
+}
+
+static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
+		stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
+	else
+		stm32_clr_bits(port, USART_CR3, USART_CR3_RTSE);
+}
+
+static unsigned int stm32_get_mctrl(struct uart_port *port)
+{
+	/* This routine is used to get signals of: DCD, DSR, RI, and CTS */
+	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* Transmit stop */
+static void stm32_stop_tx(struct uart_port *port)
+{
+	stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
+}
+
+/* There are probably characters waiting to be transmitted. */
+static void stm32_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (uart_circ_empty(xmit))
+		return;
+
+	stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
+}
+
+/* Throttle the remote when input buffer is about to overflow. */
+static void stm32_throttle(struct uart_port *port)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Unthrottle the remote, the input buffer can now accept data. */
+static void stm32_unthrottle(struct uart_port *port)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	stm32_set_bits(port, USART_CR1, USART_CR1_RXNEIE);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Receive stop */
+static void stm32_stop_rx(struct uart_port *port)
+{
+	stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+}
+
+/* Handle breaks - ignored by us */
+static void stm32_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static int stm32_startup(struct uart_port *port)
+{
+	const char *name = to_platform_device(port->dev)->name;
+	u32 val;
+	int ret;
+
+	ret = request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
+			  name, port);
+	if (ret)
+		return ret;
+
+	val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+	stm32_set_bits(port, USART_CR1, val);
+
+	return 0;
+}
+
+static void stm32_shutdown(struct uart_port *port)
+{
+	u32 val;
+
+	val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+	stm32_set_bits(port, USART_CR1, val);
+
+	free_irq(port->irq, port);
+}
+
+static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
+			    struct ktermios *old)
+{
+	struct stm32_port *stm32_port = to_stm32_port(port);
+	unsigned int baud;
+	u32 usartdiv, mantissa, fraction, oversampling;
+	tcflag_t cflag = termios->c_cflag;
+	u32 cr1, cr2, cr3;
+	unsigned long flags;
+
+	if (!stm32_port->hw_flow_control)
+		cflag &= ~CRTSCTS;
+
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* Stop serial port and reset value */
+	writel_relaxed(0, port->membase + USART_CR1);
+
+	cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
+	cr2 = 0;
+	cr3 = 0;
+
+	if (cflag & CSTOPB)
+		cr2 |= USART_CR2_STOP_2B;
+
+	if (cflag & PARENB) {
+		cr1 |= USART_CR1_PCE;
+		if ((cflag & CSIZE) == CS8)
+			cr1 |= USART_CR1_M;
+	}
+
+	if (cflag & PARODD)
+		cr1 |= USART_CR1_PS;
+
+	port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
+	if (cflag & CRTSCTS) {
+		port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
+		cr3 |= USART_CR3_CTSE;
+	}
+
+	usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
+
+	/*
+	 * The USART supports 16 or 8 times oversampling.
+	 * By default we prefer 16 times oversampling, so that the receiver
+	 * has a better tolerance to clock deviations.
+	 * 8 times oversampling is only used to achieve higher speeds.
+	 */
+	if (usartdiv < 16) {
+		oversampling = 8;
+		stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
+	} else {
+		oversampling = 16;
+		stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
+	}
+
+	mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
+	fraction = usartdiv % oversampling;
+	writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
+
+	uart_update_timeout(port, cflag, baud);
+
+	port->read_status_mask = USART_SR_ORE;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= USART_SR_PE | USART_SR_FE;
+	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+		port->read_status_mask |= USART_SR_LBD;
+
+	/* Characters to ignore */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= USART_SR_LBD;
+		/*
+		 * If we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |= USART_SR_ORE;
+	}
+
+	/* Ignore all characters if CREAD is not set */
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |= USART_SR_DUMMY_RX;
+
+	writel_relaxed(cr3, port->membase + USART_CR3);
+	writel_relaxed(cr2, port->membase + USART_CR2);
+	writel_relaxed(cr1, port->membase + USART_CR1);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *stm32_type(struct uart_port *port)
+{
+	return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
+}
+
+static void stm32_release_port(struct uart_port *port)
+{
+}
+
+static int stm32_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void stm32_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE)
+		port->type = PORT_STM32;
+}
+
+static int
+stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	/* No user changeable parameters */
+	return -EINVAL;
+}
+
+static void stm32_pm(struct uart_port *port, unsigned int state,
+		unsigned int oldstate)
+{
+	struct stm32_port *stm32port = container_of(port,
+			struct stm32_port, port);
+	unsigned long flags = 0;
+
+	switch (state) {
+	case UART_PM_STATE_ON:
+		clk_prepare_enable(stm32port->clk);
+		break;
+	case UART_PM_STATE_OFF:
+		spin_lock_irqsave(&port->lock, flags);
+		stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
+		spin_unlock_irqrestore(&port->lock, flags);
+		clk_disable_unprepare(stm32port->clk);
+		break;
+	}
+}
+
+static const struct uart_ops stm32_uart_ops = {
+	.tx_empty	= stm32_tx_empty,
+	.set_mctrl	= stm32_set_mctrl,
+	.get_mctrl	= stm32_get_mctrl,
+	.stop_tx	= stm32_stop_tx,
+	.start_tx	= stm32_start_tx,
+	.throttle	= stm32_throttle,
+	.unthrottle	= stm32_unthrottle,
+	.stop_rx	= stm32_stop_rx,
+	.break_ctl	= stm32_break_ctl,
+	.startup	= stm32_startup,
+	.shutdown	= stm32_shutdown,
+	.set_termios	= stm32_set_termios,
+	.pm		= stm32_pm,
+	.type		= stm32_type,
+	.release_port	= stm32_release_port,
+	.request_port	= stm32_request_port,
+	.config_port	= stm32_config_port,
+	.verify_port	= stm32_verify_port,
+};
+
+static int stm32_init_port(struct stm32_port *stm32port,
+			  struct platform_device *pdev)
+{
+	struct uart_port *port = &stm32port->port;
+	struct resource *res;
+	int ret;
+
+	port->iotype	= UPIO_MEM;
+	port->flags	= UPF_BOOT_AUTOCONF;
+	port->ops	= &stm32_uart_ops;
+	port->dev	= &pdev->dev;
+	port->irq	= platform_get_irq(pdev, 0);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	port->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(port->membase))
+		return PTR_ERR(port->membase);
+	port->mapbase = res->start;
+
+	spin_lock_init(&port->lock);
+
+	stm32port->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(stm32port->clk))
+		return PTR_ERR(stm32port->clk);
+
+	/* Ensure that clk rate is correct by enabling the clk */
+	ret = clk_prepare_enable(stm32port->clk);
+	if (ret)
+		return ret;
+
+	stm32port->port.uartclk = clk_get_rate(stm32port->clk);
+	if (!stm32port->port.uartclk)
+		ret = -EINVAL;
+
+	clk_disable_unprepare(stm32port->clk);
+
+	return ret;
+}
+
+static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int id;
+
+	if (!np)
+		return NULL;
+
+	id = of_alias_get_id(np, "serial");
+	if (id < 0)
+		id = 0;
+
+	if (WARN_ON(id >= STM32_MAX_PORTS))
+		return NULL;
+
+	stm32_ports[id].hw_flow_control = of_property_read_bool(np,
+							"auto-flow-control");
+	stm32_ports[id].port.line = id;
+	return &stm32_ports[id];
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id stm32_match[] = {
+	{ .compatible = "st,stm32-usart", },
+	{ .compatible = "st,stm32-uart", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, stm32_match);
+#endif
+
+static int stm32_serial_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct stm32_port *stm32port;
+
+	stm32port = stm32_of_get_stm32_port(pdev);
+	if (!stm32port)
+		return -ENODEV;
+
+	ret = stm32_init_port(stm32port, pdev);
+	if (ret)
+		return ret;
+
+	ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, &stm32port->port);
+
+	return 0;
+}
+
+static int stm32_serial_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	return uart_remove_one_port(&stm32_usart_driver, port);
+}
+
+
+#ifdef CONFIG_SERIAL_STM32_CONSOLE
+static void stm32_console_putchar(struct uart_port *port, int ch)
+{
+	while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
+		cpu_relax();
+
+	writel_relaxed(ch, port->membase + USART_DR);
+}
+
+static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
+{
+	struct uart_port *port = &stm32_ports[co->index].port;
+	unsigned long flags;
+	u32 old_cr1, new_cr1;
+	int locked = 1;
+
+	local_irq_save(flags);
+	if (port->sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock(&port->lock);
+	else
+		spin_lock(&port->lock);
+
+	/* Save and disable interrupts */
+	old_cr1 = readl_relaxed(port->membase + USART_CR1);
+	new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
+	writel_relaxed(new_cr1, port->membase + USART_CR1);
+
+	uart_console_write(port, s, cnt, stm32_console_putchar);
+
+	/* Restore interrupt state */
+	writel_relaxed(old_cr1, port->membase + USART_CR1);
+
+	if (locked)
+		spin_unlock(&port->lock);
+	local_irq_restore(flags);
+}
+
+static int stm32_console_setup(struct console *co, char *options)
+{
+	struct stm32_port *stm32port;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index >= STM32_MAX_PORTS)
+		return -ENODEV;
+
+	stm32port = &stm32_ports[co->index];
+
+	/*
+	 * This driver does not support early console initialization
+	 * (use ARM early printk support instead), so we only expect
+	 * this to be called during the uart port registration when the
+	 * driver gets probed and the port should be mapped at that point.
+	 */
+	if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
+		return -ENXIO;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
+}
+
+static struct console stm32_console = {
+	.name		= STM32_SERIAL_NAME,
+	.device		= uart_console_device,
+	.write		= stm32_console_write,
+	.setup		= stm32_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &stm32_usart_driver,
+};
+
+#define STM32_SERIAL_CONSOLE (&stm32_console)
+
+#else
+#define STM32_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_STM32_CONSOLE */
+
+static struct uart_driver stm32_usart_driver = {
+	.driver_name	= DRIVER_NAME,
+	.dev_name	= STM32_SERIAL_NAME,
+	.major		= 0,
+	.minor		= 0,
+	.nr		= STM32_MAX_PORTS,
+	.cons		= STM32_SERIAL_CONSOLE,
+};
+
+static struct platform_driver stm32_serial_driver = {
+	.probe		= stm32_serial_probe,
+	.remove		= stm32_serial_remove,
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.of_match_table = of_match_ptr(stm32_match),
+	},
+};
+
+static int __init usart_init(void)
+{
+	static char banner[] __initdata = "STM32 USART driver initialized";
+	int ret;
+
+	pr_info("%s\n", banner);
+
+	ret = uart_register_driver(&stm32_usart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&stm32_serial_driver);
+	if (ret)
+		uart_unregister_driver(&stm32_usart_driver);
+
+	return ret;
+}
+
+static void __exit usart_exit(void)
+{
+	platform_driver_unregister(&stm32_serial_driver);
+	uart_unregister_driver(&stm32_usart_driver);
+}
+
+module_init(usart_init);
+module_exit(usart_exit);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index b212281..93ba148 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -258,4 +258,7 @@
 /* Cris v10 / v32 SoC */
 #define PORT_CRIS	112
 
+/* STM32 USART */
+#define PORT_STM32	113
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
1.9.1


^ permalink raw reply related


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