Linux Serial subsystem development
 help / color / mirror / Atom feed
* Re: [RFC PATCH v1 08/25] printk: add ring buffer and kthread
From: Petr Mladek @ 2019-02-19 13:54 UTC (permalink / raw)
  To: John Ogness
  Cc: linux-kernel, Peter Zijlstra, Sergey Senozhatsky, Steven Rostedt,
	Daniel Wang, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	Alan Cox, Jiri Slaby, Peter Feiner, linux-serial,
	Sergey Senozhatsky
In-Reply-To: <20190212143003.48446-9-john.ogness@linutronix.de>

On Tue 2019-02-12 15:29:46, John Ogness wrote:
> The printk ring buffer provides an NMI-safe interface for writing
> messages to a ring buffer. Using such a buffer for alleviates printk
> callers from the current burdens of disabled preemption while calling
> the console drivers (and possibly printing out many messages that
> another task put into the log buffer).
> 
> Create a ring buffer to be used for storing messages to be
> printed to the consoles.
> 
> Create a dedicated printk kthread to block on the ring buffer
> and call the console drivers for the read messages.

It was already mentioned in the reply to the cover letter.
An offloading console handling to a kthread is very problematic:

  + It reduces the chance that the messages will ever reach
    the console when the system becomes unstable or is dying.
    Note that panic() is the better alternative. The system
    could die without calling panic().

  + There are situations when the kthread will not be usable
    by definition, for example, early boot, suspend, kexec,
    shutdown.

  + It is hard to do a single thread efficient enough. It could
    not have too high priority to avoid staling normal processes.
    It won't be scheduled in time when processed with a higher
    priority produce too many messages.


That said, I think that some offloading would be useful and
even necessary, especially on the real time systems. But we
need to be more conservative, for example:

  + offload only when it takes too long
  + do not offload in emergency situations
  + keep the console owner logic

The above ideas come from the old discussions about introducing
printk kthread. This patchset brings one more idea to push
emergency messages directly to "lockless" consoles.

I could imagine that the default setting will be more
conservative while real time kernel would do a more
aggressive offloading.

Anyway, I would split this entire patchset into two.
The first one would replace the existing main buffer
and per-cpu safe buffers with the lockless one.
The other patchset would try to reduce delays caused
by console handling by introducing lockless consoles,
offloading, ...


> NOTE: The printk_delay is relocated to _after_ the message is
>       printed, where it makes more sense.
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>
> ---
>  kernel/printk/printk.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 105 insertions(+)
> 
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index d3d170374ceb..08e079b95652 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -44,6 +44,8 @@
>  #include <linux/irq_work.h>
>  #include <linux/ctype.h>
>  #include <linux/uio.h>
> +#include <linux/kthread.h>
> +#include <linux/printk_ringbuffer.h>
>  #include <linux/sched/clock.h>
>  #include <linux/sched/debug.h>
>  #include <linux/sched/task_stack.h>
> @@ -397,7 +399,12 @@ DEFINE_RAW_SPINLOCK(logbuf_lock);
>  		printk_safe_exit_irqrestore(flags);	\
>  	} while (0)
>  
> +DECLARE_STATIC_PRINTKRB_CPULOCK(printk_cpulock);
> +
>  #ifdef CONFIG_PRINTK
> +/* record buffer */
> +DECLARE_STATIC_PRINTKRB(printk_rb, CONFIG_LOG_BUF_SHIFT, &printk_cpulock);
> +
>  DECLARE_WAIT_QUEUE_HEAD(log_wait);
>  /* the next printk record to read by syslog(READ) or /proc/kmsg */
>  static u64 syslog_seq;
> @@ -744,6 +751,10 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
>  	return p - buf;
>  }
>  
> +#define PRINTK_SPRINT_MAX (LOG_LINE_MAX + PREFIX_MAX)
> +#define PRINTK_RECORD_MAX (sizeof(struct printk_log) + \
> +				CONSOLE_EXT_LOG_MAX + PRINTK_SPRINT_MAX)
> +
>  /* /dev/kmsg - userspace message inject/listen interface */
>  struct devkmsg_user {
>  	u64 seq;
> @@ -1566,6 +1577,34 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
>  	return do_syslog(type, buf, len, SYSLOG_FROM_READER);
>  }
>  
> +static void format_text(struct printk_log *msg, u64 seq,
> +			char *ext_text, size_t *ext_len,
> +			char *text, size_t *len, bool time)
> +{
> +	if (suppress_message_printing(msg->level)) {
> +		/*
> +		 * Skip record that has level above the console
> +		 * loglevel and update each console's local seq.
> +		 */
> +		*len = 0;
> +		*ext_len = 0;
> +		return;
> +	}
> +
> +	*len = msg_print_text(msg, console_msg_format & MSG_FORMAT_SYSLOG,
> +			      time, text, PRINTK_SPRINT_MAX);
> +	if (nr_ext_console_drivers) {
> +		*ext_len = msg_print_ext_header(ext_text, CONSOLE_EXT_LOG_MAX,
> +						msg, seq);
> +		*ext_len += msg_print_ext_body(ext_text + *ext_len,
> +					       CONSOLE_EXT_LOG_MAX - *ext_len,
> +					       log_dict(msg), msg->dict_len,
> +					       log_text(msg), msg->text_len);
> +	} else {
> +		*ext_len = 0;
> +	}
> +}

Please, refactor the existing code instead of cut&pasting. It will
help to check eventual regressions. Also it will help to understand
the evolution when digging in the git history. [*]

> +
>  /*
>   * Special console_lock variants that help to reduce the risk of soft-lockups.
>   * They allow to pass console_lock to another printk() call using a busy wait.
> @@ -2899,6 +2938,72 @@ void wake_up_klogd(void)
>  	preempt_enable();
>  }
>  
> +static int printk_kthread_func(void *data)
> +{
> +	struct prb_iterator iter;
> +	struct printk_log *msg;
> +	size_t ext_len;
> +	char *ext_text;
> +	u64 master_seq;
> +	size_t len;
> +	char *text;
> +	char *buf;
> +	int ret;
> +
> +	ext_text = kmalloc(CONSOLE_EXT_LOG_MAX, GFP_KERNEL);
> +	text = kmalloc(PRINTK_SPRINT_MAX, GFP_KERNEL);
> +	buf = kmalloc(PRINTK_RECORD_MAX, GFP_KERNEL);
> +	if (!ext_text || !text || !buf)
> +		return -1;

We need to have some fallback solution when the kthread can't
get started properly.


> +
> +	prb_iter_init(&iter, &printk_rb, NULL);
> +
> +	/* the printk kthread never exits */
> +	for (;;) {
> +		ret = prb_iter_wait_next(&iter, buf,
> +					 PRINTK_RECORD_MAX, &master_seq);
> +		if (ret == -ERESTARTSYS) {
> +			continue;
> +		} else if (ret < 0) {
> +			/* iterator invalid, start over */
> +			prb_iter_init(&iter, &printk_rb, NULL);
> +			continue;
> +		}
> +
> +		msg = (struct printk_log *)buf;
> +		format_text(msg, master_seq, ext_text, &ext_len, text,
> +			    &len, printk_time);
> +
> +		console_lock();
> +		if (len > 0 || ext_len > 0) {
> +			call_console_drivers(ext_text, ext_len, text, len);
> +			boot_delay_msec(msg->level);
> +			printk_delay();
> +		}
> +		console_unlock();

This calls console_unlock() that still calls console drivers at this
stage. Note the each patch should keep the kernel buildable and
avoid regressions. Otherwise, it would break bisection. [*]

> +	}
> +
> +	kfree(ext_text);
> +	kfree(text);
> +	kfree(buf);

This will never get called. Well, I think that the kthread
will look different when it is used only as a callback.
We will need some buffers also when the direct console
is handled by the printk() caller directly.


> +	return 0;
> +}
> +

[*] I am not sure whether I should comment this "details" at this
    stage [RFC]. I guess that you worked on this patchset many
    weeks or even months. You tried various approaches,
    refactored the code several times. It is hard to keep
    such a big patchset clean. It might even be wasting of time.


Best Regards,
Petr

^ permalink raw reply

* Re: [RFC PATCH v1 09/25] printk: remove exclusive console hack
From: Petr Mladek @ 2019-02-19 14:03 UTC (permalink / raw)
  To: John Ogness
  Cc: linux-kernel, Peter Zijlstra, Sergey Senozhatsky, Steven Rostedt,
	Daniel Wang, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	Alan Cox, Jiri Slaby, Peter Feiner, linux-serial,
	Sergey Senozhatsky
In-Reply-To: <20190212143003.48446-10-john.ogness@linutronix.de>

On Tue 2019-02-12 15:29:47, John Ogness wrote:
> In order to support printing the printk log history when new
> consoles are registered, a global exclusive_console variable is
> temporarily set. This only works because printk runs with
> preemption disabled.
> 
> When console printing is moved to a fully preemptible dedicated
> kthread, this hack no longer works.

We need to keep this functionality. Otherwise, people would miss
the beginning of the log on some consoles. Kernel does not know
what console is important for monitoring or debugging.

Fortunately, it should be easy to implement this with
the new ring buffer a much cleaner way. Anyway, you
need to switch to the new implementation in a single
patch to avoid regression.

I would personally postpone this into a separate patchset.

Best Regards,
Petr

^ permalink raw reply

* Re: [PATCH v7 3/6] dt-bindings: pinctrl: mt8183: add binding document
From: Rob Herring @ 2019-02-19 15:21 UTC (permalink / raw)
  To: Zhiyong Tao
  Cc: Erin Lo, Linus Walleij, Matthias Brugger, Mark Rutland,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Greg Kroah-Hartman,
	Stephen Boyd, devicetree, srv_heupstream,
	linux-kernel@vger.kernel.org, open list:SERIAL DRIVERS,
	moderated list:ARM/Mediatek SoC support,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Yingjoe Chen
In-Reply-To: <1550544357.4739.32.camel@mhfsdcap03>

On Mon, Feb 18, 2019 at 8:46 PM Zhiyong Tao <zhiyong.tao@mediatek.com> wrote:
>
> On Mon, 2019-02-18 at 10:32 -0600, Rob Herring wrote:
> > On Fri, Feb 15, 2019 at 02:02:35PM +0800, Erin Lo wrote:
> > > From: Zhiyong Tao <zhiyong.tao@mediatek.com>
> > >
> > > The commit adds mt8183 compatible node in binding document.
> > >
> > > Signed-off-by: Zhiyong Tao <zhiyong.tao@mediatek.com>
> > > Signed-off-by: Erin Lo <erin.lo@mediatek.com>
> > > ---
> > >  .../devicetree/bindings/pinctrl/pinctrl-mt8183.txt | 115 +++++++++++++++++++++
> > >  1 file changed, 115 insertions(+)
> > >  create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-mt8183.txt
> > >
> > > diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8183.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8183.txt
> > > new file mode 100644
> > > index 0000000..364e673
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8183.txt
> > > @@ -0,0 +1,115 @@
> > > +* Mediatek MT8183 Pin Controller
> > > +
> > > +The Mediatek's Pin controller is used to control SoC pins.
> > > +
> > > +Required properties:
> > > +- compatible: value should be one of the following.
> > > +   "mediatek,mt8183-pinctrl", compatible with mt8183 pinctrl.
> > > +- gpio-controller : Marks the device node as a gpio controller.
> > > +- #gpio-cells: number of cells in GPIO specifier. Since the generic GPIO
> > > +  binding is used, the amount of cells must be specified as 2. See the below
> > > +  mentioned gpio binding representation for description of particular cells.
> > > +- gpio-ranges : gpio valid number range.
> > > +- reg: physicall address base for gpio base registers. There are nine
> > > +  physicall address base in mt8183. They are 0x10005000, 0x11F20000,
> > > +  0x11E80000, 0x11E70000, 0x11E90000, 0x11D30000, 0x11D20000, 0x11C50000,
> > > +  0x11F30000.
> >
> > You don't need to list out each address, just what each address is. (Or
> > just '9 GPIO base addresses'.)
>
> ==>ok, we will change it.
> >
> > > +
> > > +   Eg: <&pio 6 0>
> >
> > How is this an example of reg? Seems something is missing.
> >
> > > +   <[phandle of the gpio controller node]
> > > +   [line number within the gpio controller]
> > > +   [flags]>
> > > +
> > > +   Values for gpio specifier:
> > > +   - Line number: is a value between 0 to 202.
> > > +   - Flags:  bit field of flags, as defined in <dt-bindings/gpio/gpio.h>.
> > > +            Only the following flags are supported:
> > > +            0 - GPIO_ACTIVE_HIGH
> > > +            1 - GPIO_ACTIVE_LOW
> > > +
> > > +Optional properties:
> > > +- reg-names: gpio base register names. There are nine gpio base register
> > > +  names in mt8183. They are "iocfg0", "iocfg1", "iocfg2", "iocfg3", "iocfg4",
> > > +  "iocfg5", "iocfg6", "iocfg7", "iocfg8".
> > > +- interrupt-controller: Marks the device node as an interrupt controller
> > > +- #interrupt-cells: Should be two.
> > > +- interrupts : The interrupt outputs from the controller.
> >
> > outputs? More than 1? If so, need to say what they are and the order.
> >
> ==> there is only use one interrupt in mt8183. we will change
> "interrupts" to "interrupt" in v8.

No, 'interrupts' is always plural. The problem is 'outputs'.

Rob

^ permalink raw reply

* Re: [RFC PATCH v1 05/25] printk-rb: add basic non-blocking reading interface
From: John Ogness @ 2019-02-19 21:44 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Peter Zijlstra, Sergey Senozhatsky, Steven Rostedt,
	Daniel Wang, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	Alan Cox, Jiri Slaby, Peter Feiner, linux-serial,
	Sergey Senozhatsky
In-Reply-To: <20190218125407.ljvkuplvaa3zyj6n@pathway.suse.cz>

Hi Petr,

Below I make several comments, responding to your questions. But I like
the new API I believe you are trying to propose. So really only my final
comments are of particular importance. There I show you what I think
reader code would look like using your proposed API.

On 2019-02-18, Petr Mladek <pmladek@suse.com> wrote:
>> Add reader iterator static declaration/initializer, dynamic
>> initializer, and functions to iterate and retrieve ring buffer data.
>> 
>> Signed-off-by: John Ogness <john.ogness@linutronix.de>
>> ---
>>  include/linux/printk_ringbuffer.h |  20 ++++
>>  lib/printk_ringbuffer.c           | 190 ++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 210 insertions(+)
>> 
>> diff --git a/include/linux/printk_ringbuffer.h b/include/linux/printk_ringbuffer.h
>> index 1aec9d5666b1..5fdaf632c111 100644
>> --- a/include/linux/printk_ringbuffer.h
>> +++ b/include/linux/printk_ringbuffer.h
>> @@ -43,6 +43,19 @@ static struct prb_cpulock name = {					\
>>  	.irqflags = &_##name##_percpu_irqflags,				\
>>  }
>>  
>> +#define PRB_INIT ((unsigned long)-1)
>> +
>> +#define DECLARE_STATIC_PRINTKRB_ITER(name, rbaddr)			\
>> +static struct prb_iterator name = {					\
>
> Please, define the macro without static. The static variable
> should get declared as:
>
> static DECLARE_PRINTKRB_ITER();

OK.

>> +	.rb = rbaddr,							\
>> +	.lpos = PRB_INIT,						\
>> +}
>> +
>> +struct prb_iterator {
>> +	struct printk_ringbuffer *rb;
>> +	unsigned long lpos;
>> +};
>
> Please, define the structure before it is used (even in macros).
> It is strange to initialize something that is not yet defined.

Agreed.

>>  #define DECLARE_STATIC_PRINTKRB(name, szbits, cpulockptr)		\
>>  static char _##name##_buffer[1 << (szbits)]				\
>>  	__aligned(__alignof__(long));					\
>> @@ -62,6 +75,13 @@ char *prb_reserve(struct prb_handle *h, struct printk_ringbuffer *rb,
>>  		  unsigned int size);
>>  void prb_commit(struct prb_handle *h);
>>  
>> +/* reader interface */
>> +void prb_iter_init(struct prb_iterator *iter, struct printk_ringbuffer *rb,
>> +		   u64 *seq);
>> +void prb_iter_copy(struct prb_iterator *dest, struct prb_iterator *src);
>> +int prb_iter_next(struct prb_iterator *iter, char *buf, int size, u64 *seq);
>> +int prb_iter_data(struct prb_iterator *iter, char *buf, int size, u64 *seq);
>> +
>>  /* utility functions */
>>  void prb_lock(struct prb_cpulock *cpu_lock, unsigned int *cpu_store);
>>  void prb_unlock(struct prb_cpulock *cpu_lock, unsigned int cpu_store);
>> diff --git a/lib/printk_ringbuffer.c b/lib/printk_ringbuffer.c
>> index 90c7f9a9f861..1d1e886a0966 100644
>> --- a/lib/printk_ringbuffer.c
>> +++ b/lib/printk_ringbuffer.c
>> @@ -1,5 +1,7 @@
>>  // SPDX-License-Identifier: GPL-2.0
>>  #include <linux/smp.h>
>> +#include <linux/string.h>
>> +#include <linux/errno.h>
>>  #include <linux/printk_ringbuffer.h>
>>  
>>  #define PRB_SIZE(rb) (1 << rb->size_bits)
>> @@ -8,6 +10,7 @@
>>  #define PRB_WRAPS(rb, lpos) (lpos >> rb->size_bits)
>>  #define PRB_WRAP_LPOS(rb, lpos, xtra) \
>>  	((PRB_WRAPS(rb, lpos) + xtra) << rb->size_bits)
>> +#define PRB_DATA_SIZE(e) (e->size - sizeof(struct prb_entry))
>>  #define PRB_DATA_ALIGN sizeof(long)
>>  
>>  static bool __prb_trylock(struct prb_cpulock *cpu_lock,
>> @@ -247,3 +250,190 @@ char *prb_reserve(struct prb_handle *h, struct printk_ringbuffer *rb,
>>  
>>  	return &h->entry->data[0];
>>  }
>> +
>> +/*
>> + * prb_iter_copy: Copy an iterator.
>> + * @dest: The iterator to copy to.
>> + * @src: The iterator to copy from.
>> + *
>> + * Make a deep copy of an iterator. This is particularly useful for making
>> + * backup copies of an iterator in case a form of rewinding it needed.
>> + *
>> + * It is safe to call this function from any context and state. But
>> + * note that this function is not atomic. Callers should not make copies
>> + * to/from iterators that can be accessed by other tasks/contexts.
>> + */
>> +void prb_iter_copy(struct prb_iterator *dest, struct prb_iterator *src)
>> +{
>> +	memcpy(dest, src, sizeof(*dest));
>> +}
>> +
>> +/*
>> + * prb_iter_init: Initialize an iterator for a ring buffer.
>> + * @iter: The iterator to initialize.
>> + * @rb: A ring buffer to that @iter should iterate.
>> + * @seq: The sequence number of the position preceding the first record.
>> + *       May be NULL.
>> + *
>> + * Initialize an iterator to be used with a specified ring buffer. If @seq
>> + * is non-NULL, it will be set such that prb_iter_next() will provide a
>> + * sequence value of "@seq + 1" if no records were missed.
>> + *
>> + * It is safe to call this function from any context and state.
>> + */
>> +void prb_iter_init(struct prb_iterator *iter, struct printk_ringbuffer *rb,
>> +		   u64 *seq)
>> +{
>> +	memset(iter, 0, sizeof(*iter));
>> +	iter->rb = rb;
>> +	iter->lpos = PRB_INIT;
>> +
>> +	if (!seq)
>> +		return;
>> +
>> +	for (;;) {
>> +		struct prb_iterator tmp_iter;
>> +		int ret;
>> +
>> +		prb_iter_copy(&tmp_iter, iter);
>
> It looks strange to copy something that has been hardly initialized.
> I hope that we could do this without a copy, see below.
>
>> +
>> +		ret = prb_iter_next(&tmp_iter, NULL, 0, seq);
>
> prb_iter_next() and prb_iter_data() are too complex spaghetti
> code. They do basically the same but they do not share
> any helper function. The error handling is different
> which is really confusing. See below.

I don't follow why you think they do basically the same
thing. prb_iter_next() moves forward to the next entry, then calls
prb_iter_data() to retrieve the data. prb_iter_data() _is_ the helper
function.

(I do not intend to defend the ringbuffer API. I am only addressing your
comment that they do the same thing. I mentioned in the cover letter
that the API is not pretty. I am thankful on tips to improve it.)

>> +		if (ret < 0)
>> +			continue;
>> +
>> +		if (ret == 0)
>> +			*seq = 0;
>> +		else
>> +			(*seq)--;
>
> The decrement is another suspicious things here.

"seq" represents the last entry that we have seen. If we initialize the
iterator and then call prb_iter_next(), it is expected that we will see
the first unseen entry. The caller expects prb_iter_next() to yield a
seq that is 1 more than what prb_iter_init() set.

The purpose of the interface working this way is to have loops where we
do not need to call prb_iter_data() for the first entry and
prb_iter_next() for all other elements. The call order would be:

prb_iter_init();
while (prb_iter_next()) {
}

If prb_iter_init() can return a seq value, then the logic to check if
any entries were missed will verify that seq has incremented by exactly
1 for each prb_iter_next() call.


>> +		break;
>
> Finally, I am confused by the semantic of this function.
> What is supposed to be the initialized lpos, seq number,
> please?

lpos (an internal field) is initialized with the PRB_INIT constant so
mark that the iterator has been initialized but not yet used. This is so
that the next call to prb_iter_next() will be valid no matter what
(after which lpos is set to the seq of that returned entry). I did not
like the idea of iterators becoming invalid before they were even used.

seq (an optional by-reference variable from the caller), if non-NULL,
will be set with a seq number such that the next call to prb_iter_next()
will return that value + 1. As mentioned above, these semantics are to
simplify the init/next loop/logic.

But prb_iter_init() notis is only used for read loops. It is also used,
for example, by printk to set the clear_seq marker in some cases of
"dmesg -c". As I've mentioned, the API grew out of printk
requirements. I am more than happy to simplify this.

> I would expect a function that initializes the iterator
> either to the first valid entry (tail-one) or
> to the one defined by the given seq number.
>
> Well, I think that we need to start with a more low-level functions.
> IMHO. we need something to read one entry a safe way. Then it will
> be much easier to live with races in the rest of the code:
>
> /*
>  * Return valid entry on the given lpos. Data are read
>  * only when the buffer is is not zero.
>  */
> int prb_get_entry(struct struct printk_ringbuffer *rb,
> 		    unsigned long lpos,
> 		    struct prb_entry *entry,
> 		    unsigned int data_buf_size)
> {
> 	/*
> 	 * Pointer to the ring buffer. The data might get lost
> 	 * at any time.
> 	 */
> 	struct prb_entry *weak_entry;
>
> 	if (!is_valid(lpos))
> 		return -EINVAL;
>
> 	/* Make sure that data are valid for the given valid lpos. */
> 	smp_rmb();
>
> 	weak_entry = to_entry(lpos);
> 	entry->seq = weak_entry->seq;
>
> 	if (data_buf_size) {
> 		unsigned int size;
>
> 		size = min(data_buf_size, weak_entry->size);

weak_entry->size is untrusted data here. The following memcpy could grab
data beyond the data array. (But we can ignore these details for now. I
realize you are trying to refactor, not focus on these details.)

> 		memcpy(entry->data, weak_entry->data, size);
> 		entry->size = size;
> 	} else {
> 		entry->size = weak_data->size;
> 	}
>
> 	/* Make sure that the copy is done before we check validity. */
> 	smp_mb();
>
> 	return is_valid(lpos);
> }
>
> Then I would do the support for iterating the following way.
> First, I would extend the structure:
>
> struct prb_iterator {
> 	struct printk_ringbuffer *rb;
> 	struct prb_entry *entry;
> 	unsigned int data_buffer_size;
> 	unsigned long lpos;
> };
>
> And do something like:
>
> void prg_iter_init(struct struct printk_ringbuffer *rb,
> 		       struct prb_entry *entry,
> 		       unsigned int data_buffer_size,
> 		       struct prb_iterator *iter)
> {
> 	iter->rb = rb;
> 	iter->entry = entry;
> 	iter->data_buffer_size = data_buffer_size;
> 	lpos = 0UL;
> }
>
> Then we could do iterator support the following way:
>
> /* Start iteration with reading the tail entry. */
> int prb_iter_tail_entry(struct prb_iterator *iter);

A name like prb_iter_oldest_entry() might simplify things. I really
don't want the caller to be concerned with heads and tails and which is
which. That's an implementation detail of the ringbuffer.

> {
> 	unsigned long tail;
> 	int ret;
>
> 	for (;;) {
> 		tail = atomic_long_read(&rb->tail);
>
> 		/* Ring buffer is empty? */

The ring buffer is only empty at the beginning (when tail == head). Readers
are non-consuming, so it is never empty again once an entry is committed.

 		if (unlikely(atomic_long_read(head) == atomic_long_read(tail)))
 			return -EINVAL;

The check for valid is to make sure the tail we just read hasn't already
been overtaken by writers. I suppose this could be put into a nested
loop so that we continue trying again until we get a valid tail.

> 		if (unlikely(!is_valid(tail)))
> 			return -EINVAL;
>
> 		ret = prb_get_entry(iter->rb, tail,
> 				    iter->entry, iter->data_buf_size);
> 		if (!ret) {
> 			iter->lpos = tail;
> 			break;
> 		}
> 	}
>
> 	return 0;
> }
>
> unsigned long next_lpos(unsineg long lpos, struct prb_entry *entry)
> {
> 	return lpos + sizeof(struct entry) + entry->size;

entry->size already includes sizeof(struct prb_entry) plus alignment
padding. (Again, not important right now.)

> }
>
> /* Try to get next entry using a valid iterator */
> int prb_iter_next_entry(struct prb_iterator *iter)
> {
> 	iter->lpos = next_lpos(iter->lpos, iter->etnry);
>
> 	return prb_get_entry(rb, lpos, entry, data_buf_size;
> }
>
> /* Try to get the next entry. Allow to skip lost messages. */
> int prb_iter_next_valid_entry(struct prb_iterator *iter)
> {
> 	int ret;
>
> 	ret = prb_iter_next_entry(iter);
> 	if (!ret)
> 		return 0;
>
> 	/* Next entry has been lost. Skip to the current tail. */
> 	return prb_iter_tail_entry(rb, *lpos, entry, data_buf_size);

You return values are geting mixed up here and you are not
distinguishing between overtaken by writers and hit the end of the
ringbuffer, but I think what you are trying to write is that
prb_iter_next_valid_entry() should either return 0 for success or !0 if
the end of the ringbuffer was hit.

> }
>
>> +static bool is_valid(struct printk_ringbuffer *rb, unsigned long lpos)
>> +{
>> +	unsigned long head, tail;
>> +
>> +	tail = atomic_long_read(&rb->tail);
>> +	head = atomic_long_read(&rb->head);
>> +	head -= tail;
>> +	lpos -= tail;
>> +
>> +	if (lpos >= head)
>> +		return false;
>> +	return true;
>> +}

I am trying to understand what you want the reader code should look
like. Keep in mind that readers can be overtaken at any moment. They
also need to track entries they have missed. If I understand your idea,
it is something like this (trying to keep it as simple as possible):

void print_all_entries(...)
{
    char buf[sizeof(struct prb_entry) + DATASIZE + sizeof(long)];
    struct prb_entry *entry = (struct prb_entry *)&buf[0];
    struct prb_iterator iter;
    u64 last_seq;

    prb_iter_init(rb, entry, DATASIZE, &iter);
    if (prb_iter_oldest_entry(&iter) != 0)
        return; /* ringbuffer empty */

    for (;;) {
        do_print_entry(entry);
        last_seq = entry->seq;
        if (prb_iter_next_valid_entry(&iter) != 0)
            break; /* ringbuffer empty */
        if (entry->seq - last_seq != 1)
            print("lost %d\n", ((entry->seq - last_seq) + 1));
    }
}

I like the idea of the caller passing in a prb_entry struct. That really
helps to reduce the parameters. And having the functions
prb_iter_oldest_entry() and prb_iter_next_valid_entry() internally loop
until they get a valid result also helps so that the reader doesn't have
to do that. And if the reader doesn't have to track lost entries (for
example, /dev/kmsg), then it becomes even less code.

> IMPORTANT:
>
> Please, do not start rewriting the entire patchset after reading this
> mail. I suggest to take a rest from coding. Just read the feadback,
> ask if anything is unclear, and let your brain processing it on
> background.

Thank you for this tip.

John Ogness

^ permalink raw reply

* Re: [RFC PATCH v1 06/25] printk-rb: add blocking reader support
From: John Ogness @ 2019-02-19 21:47 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Peter Zijlstra, Sergey Senozhatsky, Steven Rostedt,
	Daniel Wang, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	Alan Cox, Jiri Slaby, Peter Feiner, linux-serial,
	Sergey Senozhatsky
In-Reply-To: <20190218140538.5sug36qiji2rurxx@pathway.suse.cz>

On 2019-02-18, Petr Mladek <pmladek@suse.com> wrote:
>> Add a blocking read function for readers. An irq_work function is
>> used to signal the wait queue so that write notification can
>> be triggered from any context.
>
> I would be more precise what exacly is problematic in which context.
> Something like:
>
> An irq_work function is used because wake_up() cannot be called safely
> from NMI and scheduler context.

OK.

>> Signed-off-by: John Ogness <john.ogness@linutronix.de>
>> ---
>>  include/linux/printk_ringbuffer.h | 20 ++++++++++++++++
>>  lib/printk_ringbuffer.c           | 49 +++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 69 insertions(+)
>> 
>> diff --git a/include/linux/printk_ringbuffer.h b/include/linux/printk_ringbuffer.h
>> index 5fdaf632c111..106f20ef8b4d 100644
>> --- a/include/linux/printk_ringbuffer.h
>> +++ b/include/linux/printk_ringbuffer.h
>> @@ -2,8 +2,10 @@
>>  #ifndef _LINUX_PRINTK_RINGBUFFER_H
>>  #define _LINUX_PRINTK_RINGBUFFER_H
>>  
>> +#include <linux/irq_work.h>
>>  #include <linux/atomic.h>
>>  #include <linux/percpu.h>
>> +#include <linux/wait.h>
>>  
>>  struct prb_cpulock {
>>  	atomic_t owner;
>> @@ -22,6 +24,10 @@ struct printk_ringbuffer {
>>  
>>  	struct prb_cpulock *cpulock;
>>  	atomic_t ctx;
>> +
>> +	struct wait_queue_head *wq;
>> +	atomic_long_t wq_counter;
>> +	struct irq_work *wq_work;
>>  };
>>  
>>  struct prb_entry {
>> @@ -59,6 +65,15 @@ struct prb_iterator {
>>  #define DECLARE_STATIC_PRINTKRB(name, szbits, cpulockptr)		\
>>  static char _##name##_buffer[1 << (szbits)]				\
>>  	__aligned(__alignof__(long));					\
>> +static DECLARE_WAIT_QUEUE_HEAD(_##name##_wait);				\
>> +static void _##name##_wake_work_func(struct irq_work *irq_work)		\
>> +{									\
>> +	wake_up_interruptible_all(&_##name##_wait);			\
>> +}									\
>
> All ring buffers might share the same generic function, something like:
>
> void prb_wake_readers_work_func(struct irq_work *irq_work)
> {
> 	struct printk_ringbuffer *rb;
>
> 	rb = container_of(irq_work, struct printk_ring_buffer, wq_work);
> 	wake_up_interruptible_all(rb->wq);			\
> }

Agreed.

>> +static struct irq_work _##name##_wake_work = {				\
>> +	.func = _##name##_wake_work_func,				\
>> +	.flags = IRQ_WORK_LAZY,						\
>> +};									\
>>  static struct printk_ringbuffer name = {				\
>>  	.buffer = &_##name##_buffer[0],					\
>>  	.size_bits = szbits,						\
>> diff --git a/lib/printk_ringbuffer.c b/lib/printk_ringbuffer.c
>> index 1d1e886a0966..c2ddf4cb9f92 100644
>> --- a/lib/printk_ringbuffer.c
>> +++ b/lib/printk_ringbuffer.c
>> @@ -185,6 +188,12 @@ void prb_commit(struct prb_handle *h)
>>  	}
>>  
>>  	prb_unlock(rb->cpulock, h->cpu);
>> +
>> +	if (changed) {
>> +		atomic_long_inc(&rb->wq_counter);
>> +		if (wq_has_sleeper(rb->wq))
>> +			irq_work_queue(rb->wq_work);
>> +	}
>>  }
>>  
>>  /*
>> @@ -437,3 +446,43 @@ int prb_iter_next(struct prb_iterator *iter, char *buf, int size, u64 *seq)
>>  
>>  	return 1;
>>  }
>> +
>> +/*
>> + * prb_iter_wait_next: Advance to the next record, blocking if none available.
>> + * @iter: Iterator tracking the current position.
>> + * @buf: A buffer to store the data of the next record. May be NULL.
>> + * @size: The size of @buf. (Ignored if @buf is NULL.)
>> + * @seq: The sequence number of the next record. May be NULL.
>> + *
>> + * If a next record is already available, this function works like
>> + * prb_iter_next(). Otherwise block interruptible until a next record is
>> + * available.
>> + *
>> + * When a next record is available, @iter is advanced and (if specified)
>> + * the data and/or sequence number of that record are provided.
>> + *
>> + * This function might sleep.
>> + *
>> + * Returns 1 if @iter was advanced, -EINVAL if @iter is now invalid, or
>> + * -ERESTARTSYS if interrupted by a signal.
>> + */
>> +int prb_iter_wait_next(struct prb_iterator *iter, char *buf, int size, u64 *seq)
>> +{
>> +	unsigned long last_seen;
>> +	int ret;
>> +
>> +	for (;;) {
>> +		last_seen = atomic_long_read(&iter->rb->wq_counter);
>> +
>> +		ret = prb_iter_next(iter, buf, size, seq);
>> +		if (ret != 0)
>> +			break;
>> +
>> +		ret = wait_event_interruptible(*iter->rb->wq,
>> +			last_seen != atomic_long_read(&iter->rb->wq_counter));
>
> Do we really need yet another counter here?
>
> I think that rb->seq might do the same job. Or if there is problem
> with atomicity then rb->head might work as well. Or do I miss
> anything?

You are correct. rb->head would be appropriate.

John Ogness

^ permalink raw reply

* Re: [RFC PATCH v1 07/25] printk-rb: add functionality required by printk
From: John Ogness @ 2019-02-19 22:08 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Peter Zijlstra, Sergey Senozhatsky, Steven Rostedt,
	Daniel Wang, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	Alan Cox, Jiri Slaby, Peter Feiner, linux-serial,
	Sergey Senozhatsky
In-Reply-To: <20190218155921.rxksi2hyasxnmu7a@pathway.suse.cz>

On 2019-02-18, Petr Mladek <pmladek@suse.com> wrote:
>> The printk subsystem needs to be able to query the size of the ring
>> buffer, seek to specific entries within the ring buffer, and track
>> if records could not be stored in the ring buffer.
>> 
>> diff --git a/lib/printk_ringbuffer.c b/lib/printk_ringbuffer.c
>> index c2ddf4cb9f92..ce33b5add5a1 100644
>> --- a/lib/printk_ringbuffer.c
>> +++ b/lib/printk_ringbuffer.c
>> @@ -175,11 +175,16 @@ void prb_commit(struct prb_handle *h)
>>  				head = PRB_WRAP_LPOS(rb, head, 1);
>>  				continue;
>>  			}
>> +			while (atomic_long_read(&rb->lost)) {
>> +				atomic_long_dec(&rb->lost);
>> +				rb->seq++;
>
> The lost-messages handling should be in a separate patch.
> At least I do not see any close relation with prb_iter_seek().

Agreed.

> I would personally move prb_iter_seek() to the 5th patch that
> implements the other get/iterator functions.

Agreed.

> On the contrary, the patch adding support for lost messages
> should implement a way how to inform the user about lost messages.
> E.g. to add a warning when some space becomes available again.

The readers will see that messages were lost. I think that is enough. I
don't know how useful it would be to notify writers that space is
available. The writers are holding the prb_cpulock, so they definitely
shouldn't be waiting around for anything.

This situation should be quite rare because it means the _entire_ ring
buffer was filled up by an NMI context that interrupted a context that
was in the reserve/commit window. NMI contexts probably should not be
doing _so_ much printk'ing within a single NMI.

>> +			}
>>  			e->seq = ++rb->seq;
>>  			head += e->size;
>>  			changed = true;
>>  		}
>>  		atomic_long_set_release(&rb->head, res);
>> +
>>  		atomic_dec(&rb->ctx);
>>  
>>  		if (atomic_long_read(&rb->reserve) == res)
>> @@ -486,3 +491,93 @@ int prb_iter_wait_next(struct prb_iterator *iter, char *buf, int size, u64 *seq)
>>  
>>  	return ret;
>>  }
>> +
>> +/*
>> + * prb_iter_seek: Seek forward to a specific record.
>> + * @iter: Iterator to advance.
>> + * @seq: Record number to advance to.
>> + *
>> + * Advance @iter such that a following call to prb_iter_data() will provide
>> + * the contents of the specified record. If a record is specified that does
>> + * not yet exist, advance @iter to the end of the record list.
>> + *
>> + * Note that iterators cannot be rewound. So if a record is requested that
>> + * exists but is previous to @iter in position, @iter is considered invalid.
>> + *
>> + * It is safe to call this function from any context and state.
>> + *
>> + * Returns 1 on succces, 0 if specified record does not yet exist (@iter is
>> + * now at the end of the list), or -EINVAL if @iter is now invalid.
>> + */
>
> Do we really need to distinguish when the iterator is invalid and when
> we are at the end of the buffer?

Sure! There is big difference between "stop iterating because we hit the
newest entry" and "reset the iterator to the oldest entry because we
were overtaken by a writer".

> It seems that the reaction in both situation always is to call
> prb_iter_init(&iter, &printk_rb, &some_seq).

prb_iter_init() is only called to reset the iterator to the oldest
entry. That's all it is really doing. The fact that it can optionally
return a sequence number is just a convenience side-effect implemented
for some printk demands.

> I am still a bit
> confused what your prb_iter_init() does. Therefore I am not
> sure what it is supposed to do.
>
> Anyway, it seems to be typically used when you need to start
> from tail. I would personally do something like (based on my code
> in reply to 5th patch:
>
> int prb_iter_seek_to_seq(struct prb_iterator *iter, u64 seq)
> {
> 	int ret;
>
> 	ret = prb_iter_tail_entry(iter);
>
> 	while (!ret && iter->entry->seq != seq)
> 		ret = prb_iter_next_valid_entry(iter);
>
> 	return ret;
> }

Yes. Moving the loops inside prb_iter_tail_entry() and
prb_iter_next_valid_entry() definitely simplify the code.

> When I see it, I would make the functionality more obvious
> by renaming:
>
>     prb_iter_tail_entry() -> prb_iter_set_tail_entry()

I would say: prb_iter_set_oldest_entry()

>> +int prb_iter_seek(struct prb_iterator *iter, u64 seq)
>> +{
>> +	u64 cur_seq;
>> +	int ret;
>> +
>> +	/* first check if the iterator is already at the wanted seq */
>> +	if (seq == 0) {
>> +		if (iter->lpos == PRB_INIT)
>> +			return 1;
>> +		else
>> +			return -EINVAL;
>> +	}
>> +	if (iter->lpos != PRB_INIT) {
>> +		if (prb_iter_data(iter, NULL, 0, &cur_seq) >= 0) {
>> +			if (cur_seq == seq)
>> +				return 1;
>> +			if (cur_seq > seq)
>> +				return -EINVAL;
>> +		}
>> +	}
>> +
>> +	/* iterate to find the wanted seq */
>> +	for (;;) {
>> +		ret = prb_iter_next(iter, NULL, 0, &cur_seq);
>> +		if (ret <= 0)
>> +			break;
>> +
>> +		if (cur_seq == seq)
>> +			break;
>> +
>> +		if (cur_seq > seq) {
>> +			ret = -EINVAL;
>> +			break;
>> +		}
>
> This is a good example why prb_iter_data() and prb_iter_next() is
> a weird interface. You need to read the documentation very carefully
> to understand the difference (functionality, error codes). At least
> for me, it is far from obvious why they are used this way and
> if it is correct.

Agreed. I prefer your suggested API. They significantly simplify the
reader code, which as you'll see in later printk.c patches, is
everywhere.

John Ogness

^ permalink raw reply

* [PATCH v3 0/9] Add basic support for Socionext Milbeaut M10V SoC
From: Sugaya Taichi @ 2019-02-20  7:42 UTC (permalink / raw)
  To: devicetree, linux-serial, linux-arm-kernel, linux-kernel, soc
  Cc: Mark Rutland, Shinji Kanematsu, Masami Hiramatsu, Arnd Bergmann,
	Jassi Brar, Sugaya Taichi, Greg Kroah-Hartman, Daniel Lezcano,
	Russell King, Masahiro Yamada, Rob Herring, Takao Orito,
	Thomas Gleixner, Kazuhiro Kasai

Hi,

Here is the series of patches the initial support for SC2000(M10V) of
Milbeaut SoCs. "M10V" is the internal name of SC2000, so commonly used in
source code.

SC2000 is a SoC of the Milbeaut series. equipped with a DSP optimized for
computer vision. It also features advanced functionalities such as 360-degree,
real-time spherical stitching with multi cameras, image stabilization for
without mechanical gimbals, and rolling shutter correction. More detail is
below:
https://www.socionext.com/en/products/assp/milbeaut/SC2000.html

Specifications for developers are below:
 - Quad-core 32bit Cortex-A7 on ARMv7-A architecture
 - NEON support
 - DSP
 - GPU
 - MAX 3GB DDR3
 - Cortex-M0 for power control
 - NAND Flash Interface
 - SD UHS-I
 - SD UHS-II
 - SDIO
 - USB2.0 HOST / Device
 - USB3.0 HOST / Device
 - PCI express Gen2
 - Ethernet Engine
 - I2C
 - UART
 - SPI
 - PWM

Support is quite minimal for now, since it only includes timer, clock,
pictrl and serial controller drivers, so we can only boot to userspace
through initramfs. Support for the other peripherals  will come eventually.

Changes since v2:
* Drop clk, pinctrl, and serial driver.
* Drop unneeded options from defconfig.
* Convert milbeaut soc binding to yaml.
* Fix serial driver binding.
* Change serial id of aliases in DT.
* Add platform checking when entering suspend/resume.
* Drop pr_err()s.

Changes since v1:
* Change file names.
* Change #define names.
* Refine cpu-enable-method and bindigs.
* Add documentation for Milbeaut SoCs.
* Add more infomation for timer driver.
* Add sched_clock to timer driver.
* Refine whole of clk driver.
* Add earlycon instead of earlyprintk.
* Refine Device Tree.

Sugaya Taichi (9):
  dt-bindings: sram: milbeaut: Add binding for Milbeaut smp-sram
  dt-bindings: arm: Add SMP enable-method for Milbeaut
  dt-bindings: Add documentation for Milbeaut SoCs
  ARM: milbeaut: Add basic support for Milbeaut m10v SoC
  dt-bindings: timer: Add Milbeaut M10V timer description
  clocksource/drivers/timer-milbeaut: Introduce timer for Milbeaut SoCs
  dt-bindings: serial: Add Milbeaut serial driver description
  ARM: dts: milbeaut: Add device tree set for the Milbeaut M10V board
  ARM: configs: Add Milbeaut M10V defconfig

 Documentation/devicetree/bindings/arm/cpus.yaml    |   1 +
 .../bindings/arm/socionext/milbeaut.yaml           |  22 +++
 .../devicetree/bindings/serial/milbeaut-uart.txt   |  21 +++
 .../devicetree/bindings/sram/milbeaut-smp-sram.txt |  24 +++
 .../bindings/timer/socionext,milbeaut-timer.txt    |  17 ++
 arch/arm/Kconfig                                   |   2 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/Makefile                         |   1 +
 arch/arm/boot/dts/milbeaut-m10v-evb.dts            |  32 ++++
 arch/arm/boot/dts/milbeaut-m10v.dtsi               |  95 +++++++++++
 arch/arm/configs/milbeaut_m10v_defconfig           | 175 +++++++++++++++++++++
 arch/arm/configs/multi_v7_defconfig                |   2 +
 arch/arm/mach-milbeaut/Kconfig                     |  20 +++
 arch/arm/mach-milbeaut/Makefile                    |   1 +
 arch/arm/mach-milbeaut/platsmp.c                   | 143 +++++++++++++++++
 drivers/clocksource/Kconfig                        |   9 ++
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-milbeaut.c               | 161 +++++++++++++++++++
 18 files changed, 728 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/socionext/milbeaut.yaml
 create mode 100644 Documentation/devicetree/bindings/serial/milbeaut-uart.txt
 create mode 100644 Documentation/devicetree/bindings/sram/milbeaut-smp-sram.txt
 create mode 100644 Documentation/devicetree/bindings/timer/socionext,milbeaut-timer.txt
 create mode 100644 arch/arm/boot/dts/milbeaut-m10v-evb.dts
 create mode 100644 arch/arm/boot/dts/milbeaut-m10v.dtsi
 create mode 100644 arch/arm/configs/milbeaut_m10v_defconfig
 create mode 100644 arch/arm/mach-milbeaut/Kconfig
 create mode 100644 arch/arm/mach-milbeaut/Makefile
 create mode 100644 arch/arm/mach-milbeaut/platsmp.c
 create mode 100644 drivers/clocksource/timer-milbeaut.c

-- 
1.9.1

^ permalink raw reply

* [PATCH v3 7/9] dt-bindings: serial: Add Milbeaut serial driver description
From: Sugaya Taichi @ 2019-02-20  7:44 UTC (permalink / raw)
  To: linux-serial, devicetree, linux-kernel, linux-arm-kernel, soc
  Cc: Greg Kroah-Hartman, Rob Herring, Mark Rutland, Takao Orito,
	Kazuhiro Kasai, Shinji Kanematsu, Jassi Brar, Masami Hiramatsu,
	Sugaya Taichi

Add DT bindings document for Milbeaut serial driver.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 .../devicetree/bindings/serial/milbeaut-uart.txt    | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/milbeaut-uart.txt

diff --git a/Documentation/devicetree/bindings/serial/milbeaut-uart.txt b/Documentation/devicetree/bindings/serial/milbeaut-uart.txt
new file mode 100644
index 0000000..3d2fb1a
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/milbeaut-uart.txt
@@ -0,0 +1,21 @@
+Socionext Milbeaut UART controller
+
+Required properties:
+- compatible: should be "socionext,milbeaut-usio-uart".
+- reg: offset and length of the register set for the device.
+- interrupts: two interrupts specifier.
+- interrupt-names: should be "rx", "tx".
+- clocks: phandle to the input clock.
+
+Optional properties:
+- auto-flow-control: flow control enable.
+
+Example:
+	usio1: usio_uart@1e700010 {
+		compatible = "socionext,milbeaut-usio-uart";
+		reg = <0x1e700010 0x10>;
+		interrupts = <0 141 0x4>, <0 149 0x4>;
+		interrupt-names = "rx", "tx";
+		clocks = <&clk 2>;
+		auto-flow-control;
+	};
-- 
1.9.1

^ permalink raw reply related

* Re: [RFC PATCH v1 10/25] printk: redirect emit/store to new ringbuffer
From: Petr Mladek @ 2019-02-20  9:01 UTC (permalink / raw)
  To: John Ogness
  Cc: linux-kernel, Peter Zijlstra, Sergey Senozhatsky, Steven Rostedt,
	Daniel Wang, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	Alan Cox, Jiri Slaby, Peter Feiner, linux-serial,
	Sergey Senozhatsky
In-Reply-To: <20190212143003.48446-11-john.ogness@linutronix.de>

On Tue 2019-02-12 15:29:48, John Ogness wrote:
> vprintk_emit and vprintk_store are the main functions that all printk
> variants eventually go through. Change these to store the message in
> the new printk ring buffer that the printk kthread is reading.

We need to switch the two buffers in a single commit
without disabling important functionality.

By other words, we need to change vprintk_emit(), vprintk_store(),
console_unlock(), syslog(), devkmsg(), and syslog in one patch.

The only exception might continuous lines handling. We might
temporary store them right away. It should not break bisectability.

The patch will be huge but I do not see other reasonable solution
at the moment. In each case, the patch should do only
a "straightforward" switch. Any refactoring or logical
changes should be done in preliminary patches.


> Remove functions no longer in use because of the changes to
> vprintk_emit and vprintk_store.
> 
> In order to handle interrupts and NMIs, a second per-cpu ring buffer
> (sprint_rb) is added. This ring buffer is used for NMI-safe memory
> allocation in order to format the printk messages.
> 
> NOTE: LOG_CONT is ignored for now and handled as individual messages.
>       LOG_CONT functions are masked behind "#if 0" blocks until their
>       functionality can be restored
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>
> ---
>  kernel/printk/printk.c | 319 ++++++++-----------------------------------------
>  1 file changed, 51 insertions(+), 268 deletions(-)
> 
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index 5a5a685bb128..b6a6f1002741 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -584,54 +500,36 @@ static int log_store(int facility, int level,
>  		     const char *text, u16 text_len)

>  	memcpy(log_dict(msg), dict, dict_len);
>  	msg->dict_len = dict_len;
>  	msg->facility = facility;
>  	msg->level = level & 7;
>  	msg->flags = flags & 0x1f;

The existing struct printk_log is stored into the data field
of struct prb_entry. It is because printk_ring_buffer is supposed
to be a generic ring buffer.

It makes the code more complicated. Also it needs more space for
the size and seq items from struct prb_entry.

printk() is already very complicated code. We should not make
it unnecessarily worse.

Please, are there any candidates or plans to reuse the new ring
buffer implementation? For example, would it be usable
for ftrace? Steven?

If not, I would prefer to make it printk-specific
and hopefully simplify the code a bit.


> -	if (ts_nsec > 0)
> -		msg->ts_nsec = ts_nsec;
> -	else
> -		msg->ts_nsec = local_clock();
> -	memset(log_dict(msg) + dict_len, 0, pad_len);
> +	msg->ts_nsec = ts_nsec;
>  	msg->len = size;
>  
>  	/* insert message */
> -	log_next_idx += msg->len;
> -	log_next_seq++;
> +	prb_commit(&h);
>  
>  	return msg->text_len;
>  }

[...]

>  int vprintk_store(int facility, int level,
>  		  const char *dict, size_t dictlen,
>  		  const char *fmt, va_list args)
>  {
> -	static char textbuf[LOG_LINE_MAX];
> -	char *text = textbuf;
> -	size_t text_len;
> +	return vprintk_emit(facility, level, dict, dictlen, fmt, args);
> +}
> +
> +/* ring buffer used as memory allocator for temporary sprint buffers */
> +DECLARE_STATIC_PRINTKRB(sprint_rb,
> +			ilog2(PRINTK_RECORD_MAX + sizeof(struct prb_entry) +
> +			      sizeof(long)) + 2, &printk_cpulock);
> +
> +asmlinkage int vprintk_emit(int facility, int level,
> +			    const char *dict, size_t dictlen,
> +			    const char *fmt, va_list args)

[...]

> +	rbuf = prb_reserve(&h, &sprint_rb, PRINTK_SPRINT_MAX);

The second ring buffer for temporary buffers is really interesting
idea.

Well, it brings some questions. For example, how many users might
need a reservation in parallel. Or if the nested use might cause
some problems when we decide to use printk-specific ring buffer
implementation. I still have to think about it.


> -	/* If called from the scheduler, we can not call up(). */
> -	if (!in_sched && pending_output) {
> -		/*
> -		 * Disable preemption to avoid being preempted while holding
> -		 * console_sem which would prevent anyone from printing to
> -		 * console
> -		 */
> -		preempt_disable();
> -		/*
> -		 * Try to acquire and then immediately release the console
> -		 * semaphore.  The release will print out buffers and wake up
> -		 * /dev/kmsg and syslog() users.
> -		 */
> -		if (console_trylock_spinning())
> -			console_unlock();
> -		preempt_enable();
> -	}

I guess that it is clear from the other mails. But to be sure.
This patch should just switch the buffers. The console handling
optimizations/fixes should be done in later patches or even
in a separate patchset.

Best Regards,
Petr

PS: I have just finished a mail that I started writing yesterday
evening. I am going to proceed some other pending mails now. I'll
come back to this thread soon.

^ permalink raw reply

* Re: possible deadlock in console_unlock
From: Tetsuo Handa @ 2019-02-20 10:52 UTC (permalink / raw)
  To: Sergey Senozhatsky, Petr Mladek
  Cc: Sergey Senozhatsky, syzbot, linux-kernel, rostedt, syzkaller-bugs,
	Greg Kroah-Hartman, Jiri Slaby, linux-serial, Andrew Morton
In-Reply-To: <20180619080812.GC405@jagdpanzerIV>

FTR, this topic seems to be moved to
https://lkml.kernel.org/r/ebc01f4f-5b1d-4f8a-1d0d-463d5218ee45@huawei.com .

^ permalink raw reply

* [PATCH 1/9] serial: uapi: add SER_RS485_DELAY_IN_USEC flag to struct serial_rs485
From: Martin Kepplinger @ 2019-02-20 15:27 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel

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

This extends the user interface for rs485 communication:

We add a new flag, SER_RS485_DELAY_IN_USEC, to struct serial_rs485 that
indicates that delay_rts_before_send and delay_rts_after_send values are
interpreted in microsecond units.

Up until now, the code comment defined these values to hold the delays in
millisecond units. Especially with fast data rates (1Mbaut or more) that
are not too uncommon for RS485, 1ms become quite long. Users need to be
able to set shorter delays than 1 ms in order not to slow down the channel
unnecessarily.

So when delays are needed, but not as long as 1ms, this enables faster
communication channels without changing the baudrate.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
Hi,

We have this totally quirky patch that uses udelay() in our tree
for a looong time now because of the above reasons - and because we are lazy.
This is an attempt to get rid of said patch on our side and fix this properly.

What do you thing about adding a flag in general?

The following patches should integrate this idea in devicetree and drivers.
These changes are NOT tested on hardware but should behave predictably
enough. I use the delays in a driver that doesn't implement them yet at
all. I'll do that after this (or something similar) is merged - it's a 2-liner
then.

Also, a patch to the rs485conf tool, that is sometimes used instead of
ioctl() directly, will be prepared as well.

thanks

                                 martin



 include/uapi/linux/serial.h | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h
index 93eb3c496ff1..c16c950ebca2 100644
--- a/include/uapi/linux/serial.h
+++ b/include/uapi/linux/serial.h
@@ -126,8 +126,15 @@ struct serial_rs485 {
 #define SER_RS485_TERMINATE_BUS		(1 << 5)	/* Enable bus
 							   termination
 							   (if supported) */
-	__u32	delay_rts_before_send;	/* Delay before send (milliseconds) */
-	__u32	delay_rts_after_send;	/* Delay after send (milliseconds) */
+#define SER_RS485_DELAY_IN_USEC		(1 << 6)	/* delay_rts_*_send
+							   values are given in
+							   microseconds */
+	__u32	delay_rts_before_send;	/* Delay before send (milliseconds
+					   by default. microseconds if flag
+					   is set) */
+	__u32	delay_rts_after_send;	/* Delay after send (milliseconds
+					   by default. microseconds if flag
+					   is set) */
 	__u32	padding[5];		/* Memory is cheap, new structs
 					   are a royal PITA .. */
 };
-- 
2.20.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

^ permalink raw reply related

* [PATCH 2/9] Documentation: serial-rs485: document SER_RS485_DELAY_IN_USEC flag
From: Martin Kepplinger @ 2019-02-20 15:27 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel
In-Reply-To: <20190220152731.4051-1-martin.kepplinger@ginzinger.com>

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

Document the new RS485 flag, SER_RS485_DELAY_IN_USEC that specifies that the
rts delay values stored in struct serial_rs485 hold values in microseconds
instead of milliseconds (the default).

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 Documentation/serial/serial-rs485.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/serial/serial-rs485.txt b/Documentation/serial/serial-rs485.txt
index ce0c1a9b8aab..a1e15e9efc2e 100644
--- a/Documentation/serial/serial-rs485.txt
+++ b/Documentation/serial/serial-rs485.txt
@@ -75,6 +75,9 @@
 	/* Set rts delay after send, if needed: */
 	rs485conf.delay_rts_after_send = ...;
 
+	/* Specify the rts delay to be microseconds, not milliseconds */
+	rs485conf.flags |= SER_RS485_DELAY_IN_USEC;
+
 	/* Set this flag if you want to receive data even while sending data */
 	rs485conf.flags |= SER_RS485_RX_DURING_TX;
 
-- 
2.20.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

^ permalink raw reply related

* [PATCH 3/9] serial: core: add rs485-rts-delay-us devicetree property for RS485
From: Martin Kepplinger @ 2019-02-20 15:27 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel
In-Reply-To: <20190220152731.4051-1-martin.kepplinger@ginzinger.com>


[-- Attachment #1.1: Type: text/plain, Size: 2141 bytes --]

struct serial_rs485 now optionally holds the rts delay values in
microseconds. Users can set these delays in their devicetree descriptions,
so this adds the microseconds-option with the "rs485-rts-delay-us" boolean
property.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 Documentation/devicetree/bindings/serial/rs485.txt |  1 +
 drivers/tty/serial/serial_core.c                   | 11 +++++++++++
 2 files changed, 12 insertions(+)

diff --git a/Documentation/devicetree/bindings/serial/rs485.txt b/Documentation/devicetree/bindings/serial/rs485.txt
index b92592dff6dd..77396c62b383 100644
--- a/Documentation/devicetree/bindings/serial/rs485.txt
+++ b/Documentation/devicetree/bindings/serial/rs485.txt
@@ -12,6 +12,7 @@ Optional properties:
   * b is the delay between end of data sent and rts signal in milliseconds
       it corresponds to the delay after sending data and actual release of the line.
   If this property is not specified, <0 0> is assumed.
+- rs485-rts-delay-us: the same as rs485-rts-delay, but in microseconds.
 - rs485-rts-active-low: drive RTS low when sending (default is high).
 - linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485
   feature at boot time. It can be disabled later with proper ioctl.
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 556f50aa1b58..4fb265b2c0fe 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -3097,6 +3097,17 @@ void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf)
 		rs485conf->delay_rts_after_send = 0;
 	}
 
+	ret = device_property_read_u32_array(dev, "rs485-rts-delay-us",
+					     rs485_delay, 2);
+	if (!ret) {
+		rs485conf->delay_rts_before_send = rs485_delay[0];
+		rs485conf->delay_rts_after_send = rs485_delay[1];
+		rs485conf->flags |= SER_RS485_DELAY_IN_USEC;
+	} else {
+		rs485conf->delay_rts_before_send = 0;
+		rs485conf->delay_rts_after_send = 0;
+	}
+
 	/*
 	 * Clear full-duplex and enabled flags, set RTS polarity to active high
 	 * to get to a defined state with the following properties:
-- 
2.20.1


[-- Attachment #1.2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 4/9] serial: 8250: add support for rs485 RTS delays in microseconds
From: Martin Kepplinger @ 2019-02-20 15:27 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel
In-Reply-To: <20190220152731.4051-1-martin.kepplinger@ginzinger.com>

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

Read struct serial_rs485's flag SER_RS485_DELAY_IN_USEC and apply the delay
accordingly.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 drivers/tty/serial/8250/8250_omap.c | 13 +++++++++++--
 drivers/tty/serial/8250/8250_port.c | 25 +++++++++++++++++++++----
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 0a8316632d75..cbce43ac60b1 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -720,8 +720,17 @@ static int omap_8250_rs485_config(struct uart_port *port,
 	struct uart_8250_port *up = up_to_u8250p(port);
 
 	/* Clamp the delays to [0, 100ms] */
-	rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
-	rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send, 100U);
+	if (rs485->flags & SER_RS485_DELAY_IN_USEC) {
+		rs485->delay_rts_before_send = min(rs485->delay_rts_before_send,
+						   100000U);
+		rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send,
+						   100000U);
+	} else {
+		rs485->delay_rts_before_send = min(rs485->delay_rts_before_send,
+						   100U);
+		rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send,
+						   100U);
+	}
 
 	port->rs485 = *rs485;
 
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index d2f3310abe54..0cee4aa8323d 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1483,6 +1483,15 @@ static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
 	hrtimer_start(hrt, t, HRTIMER_MODE_REL);
 }
 
+static void start_hrtimer_us(struct hrtimer *hrt, unsigned long usec)
+{
+	long sec = usec / 1000000;
+	long nsec = (usec % 1000000) * 1000000000;
+	ktime_t t = ktime_set(sec, nsec);
+
+	hrtimer_start(hrt, t, HRTIMER_MODE_REL);
+}
+
 static void __stop_tx_rs485(struct uart_8250_port *p)
 {
 	struct uart_8250_em485 *em485 = p->em485;
@@ -1493,8 +1502,12 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
 	 */
 	if (p->port.rs485.delay_rts_after_send > 0) {
 		em485->active_timer = &em485->stop_tx_timer;
-		start_hrtimer_ms(&em485->stop_tx_timer,
-				   p->port.rs485.delay_rts_after_send);
+		if (p->port.rs485.flags & SER_RS485_DELAY_IN_USEC)
+			start_hrtimer_us(&em485->stop_tx_timer,
+					 p->port.rs485.delay_rts_after_send);
+		else
+			start_hrtimer_ms(&em485->stop_tx_timer,
+					 p->port.rs485.delay_rts_after_send);
 	} else {
 		__do_stop_tx_rs485(p);
 	}
@@ -1600,8 +1613,12 @@ static inline void start_tx_rs485(struct uart_port *port)
 
 		if (up->port.rs485.delay_rts_before_send > 0) {
 			em485->active_timer = &em485->start_tx_timer;
-			start_hrtimer_ms(&em485->start_tx_timer,
-					 up->port.rs485.delay_rts_before_send);
+			if (up->port.rs485.flags & SER_RS485_DELAY_IN_USEC)
+				start_hrtimer_us(&em485->start_tx_timer,
+					up->port.rs485.delay_rts_before_send);
+			else
+				start_hrtimer_ms(&em485->start_tx_timer,
+					up->port.rs485.delay_rts_before_send);
 			return;
 		}
 	}
-- 
2.20.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

^ permalink raw reply related

* [PATCH 5/9] serial: omap-serial: add support for rs485 RTS delays in microseconds
From: Martin Kepplinger @ 2019-02-20 15:27 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel
In-Reply-To: <20190220152731.4051-1-martin.kepplinger@ginzinger.com>

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

Read struct serial_rs485's flag SER_RS485_DELAY_IN_USEC and apply the delay
accordingly.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 drivers/tty/serial/omap-serial.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 6420ae581a80..adcd75ce5112 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -310,7 +310,11 @@ static void serial_omap_stop_tx(struct uart_port *port)
 			res = (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) ?
 				1 : 0;
 			if (gpio_get_value(up->rts_gpio) != res) {
-				if (port->rs485.delay_rts_after_send > 0)
+				if (port->rs485.delay_rts_after_send > 0 &&
+				    port->rs485.flags & SER_RS485_DELAY_IN_USEC)
+					udelay(
+					port->rs485.delay_rts_after_send);
+				else if (port->rs485.delay_rts_after_send > 0)
 					mdelay(
 					port->rs485.delay_rts_after_send);
 				gpio_set_value(up->rts_gpio, res);
@@ -420,7 +424,11 @@ static void serial_omap_start_tx(struct uart_port *port)
 		res = (port->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0;
 		if (gpio_get_value(up->rts_gpio) != res) {
 			gpio_set_value(up->rts_gpio, res);
-			if (port->rs485.delay_rts_before_send > 0)
+			if (port->rs485.delay_rts_before_send > 0 &&
+			    port->rs485.flags & SER_RS485_DELAY_IN_USEC)
+				udelay(port->rs485.delay_rts_before_send);
+			else if (port->rs485.delay_rts_before_send > 0 &&
+				 !(port->rs485.flags & SER_RS485_DELAY_IN_USEC)
 				mdelay(port->rs485.delay_rts_before_send);
 		}
 	}
@@ -1407,8 +1415,17 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
 	serial_out(up, UART_IER, 0);
 
 	/* Clamp the delays to [0, 100ms] */
-	rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
-	rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send, 100U);
+	if (port->rs485.flags & SER_RS485_DELAY_IN_USEC) {
+		rs485->delay_rts_before_send = min(rs485->delay_rts_before_send,
+						   100000U);
+		rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send,
+						   100000U);
+	} else {
+		rs485->delay_rts_before_send = min(rs485->delay_rts_before_send,
+						   100);
+		rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send,
+						   100U);
+	}
 
 	/* store new config */
 	port->rs485 = *rs485;
-- 
2.20.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

^ permalink raw reply related

* [PATCH 6/9] serial: sc16is7xx: add support for rs485 RTS delays in microseconds
From: Martin Kepplinger @ 2019-02-20 15:31 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel

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

Read struct serial_rs485's flag SER_RS485_DELAY_IN_USEC and apply the delay
accordingly.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 drivers/tty/serial/sc16is7xx.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 635178cf3eed..b0e00b9fb177 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -743,7 +743,13 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws)
 	struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
 
 	if ((port->rs485.flags & SER_RS485_ENABLED) &&
-	    (port->rs485.delay_rts_before_send > 0))
+	    (port->rs485.delay_rts_before_send > 0) &&
+	    (port->rs485.flags & SER_RS485_DELAY_IN_USEC))
+		usleep_range(port->rs485.delay_rts_before_send,
+			     port->rs485.delay_rts_before_send);
+	else if ((port->rs485.flags & SER_RS485_ENABLED) &&
+		 (port->rs485.delay_rts_before_send > 0) &&
+		 !(port->rs485.flags & SER_RS485_DELAY_IN_USEC))
 		msleep(port->rs485.delay_rts_before_send);
 
 	sc16is7xx_handle_tx(port);
-- 
2.20.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

^ permalink raw reply related

* [PATCH 7/9] serial: atmel_serial: set SER_RS485_DELAY_IN_USEC accordingly
From: Martin Kepplinger @ 2019-02-20 15:31 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel
In-Reply-To: <20190220153119.4423-1-martin.kepplinger@ginzinger.com>

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

Unset the SER_RS485_DELAY_IN_USEC flag during rs485 config for
userspace to get the correct setting.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 drivers/tty/serial/atmel_serial.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 05147fe24343..36ab1c131d36 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -346,6 +346,9 @@ static int atmel_config_rs485(struct uart_port *port,
 
 	port->rs485 = *rs485conf;
 
+	/* delays are in milliseconds */
+	rs485conf->flags &= ~SER_RS485_DELAY_IN_USEC;
+
 	if (rs485conf->flags & SER_RS485_ENABLED) {
 		dev_dbg(port->dev, "Setting UART to RS485\n");
 		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
-- 
2.20.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

^ permalink raw reply related

* [PATCH 8/9] serial: fsl_lpuart: set SER_RS485_DELAY_IN_USEC accordingly
From: Martin Kepplinger @ 2019-02-20 15:31 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel
In-Reply-To: <20190220153119.4423-1-martin.kepplinger@ginzinger.com>

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

Clear SER_RS485_DELAY_IN_USEC for userspace to get correct settings.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 drivers/tty/serial/fsl_lpuart.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index ea1c85e3b432..a63aa22e3a25 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1124,6 +1124,7 @@ static int lpuart_config_rs485(struct uart_port *port,
 	rs485->delay_rts_before_send = 0;
 	rs485->delay_rts_after_send = 0;
 	rs485->flags &= ~SER_RS485_RX_DURING_TX;
+	rs485->flags &= ~SER_RS485_DELAY_IN_USEC;
 
 	if (rs485->flags & SER_RS485_ENABLED) {
 		/* Enable auto RS-485 RTS mode */
-- 
2.20.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

^ permalink raw reply related

* [PATCH 9/9] serial: st32-usart: set SER_RS485_DELAY_IN_USEC accordingly
From: Martin Kepplinger @ 2019-02-20 15:31 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel
In-Reply-To: <20190220153119.4423-1-martin.kepplinger@ginzinger.com>

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

Unset SER_RS485_DELAY_IN_USEC for userspace to get correct settings.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 drivers/tty/serial/stm32-usart.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index e8d7a7bb4339..4daf5fc71644 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -112,6 +112,7 @@ static int stm32_config_rs485(struct uart_port *port,
 
 	port->rs485 = *rs485conf;
 
+	rs485conf->flags &= ~SER_RS485_DELAY_IN_USEC;
 	rs485conf->flags |= SER_RS485_RX_DURING_TX;
 
 	if (rs485conf->flags & SER_RS485_ENABLED) {
-- 
2.20.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

^ permalink raw reply related

* Re: [RFC PATCH v1 10/25] printk: redirect emit/store to new ringbuffer
From: John Ogness @ 2019-02-20 21:25 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Peter Zijlstra, Sergey Senozhatsky, Steven Rostedt,
	Daniel Wang, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	Alan Cox, Jiri Slaby, Peter Feiner, linux-serial,
	Sergey Senozhatsky
In-Reply-To: <20190220090112.xbnauwt2w7gwtebo@pathway.suse.cz>

On 2019-02-20, Petr Mladek <pmladek@suse.com> wrote:
>> vprintk_emit and vprintk_store are the main functions that all printk
>> variants eventually go through. Change these to store the message in
>> the new printk ring buffer that the printk kthread is reading.
>
> We need to switch the two buffers in a single commit
> without disabling important functionality.
>
> By other words, we need to change vprintk_emit(), vprintk_store(),
> console_unlock(), syslog(), devkmsg(), and syslog in one patch.

Agreed. But for the review process I expect it makes things much easier
to change them one at a time. Patch-squashing is not a problem once all
the individuals have been ack'd.

>> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
>> index 5a5a685bb128..b6a6f1002741 100644
>> --- a/kernel/printk/printk.c
>> +++ b/kernel/printk/printk.c
>> @@ -584,54 +500,36 @@ static int log_store(int facility, int level,
>>  		     const char *text, u16 text_len)
>
>>  	memcpy(log_dict(msg), dict, dict_len);
>>  	msg->dict_len = dict_len;
>>  	msg->facility = facility;
>>  	msg->level = level & 7;
>>  	msg->flags = flags & 0x1f;
>
> The existing struct printk_log is stored into the data field
> of struct prb_entry. It is because printk_ring_buffer is supposed
> to be a generic ring buffer.

Yes.

> It makes the code more complicated. Also it needs more space for
> the size and seq items from struct prb_entry.
>
> printk() is already very complicated code. We should not make
> it unnecessarily worse.

In my opinion it makes things considerably easier. My experience with
printk-code is that it is so complicated because it is mixing
printk-features with ring buffer handling code. By providing a strict
API (and hiding the details) of the ring buffer, the implementation of
the printk-features became pretty straight forward.

Now I will admit that the ring buffer API I proposed is not easy to
digest. Mostly because I leave a lot of work up to the readers and have
lots of arguments. Your proposed changes of passing a struct and moving
loops under the ring buffer API should provide some major
simplification.

> Please, are there any candidates or plans to reuse the new ring
> buffer implementation?

As you pointed out below, this patch already uses the ring buffer
implementation for a totally different purpose: NMI safe dynamic memory
allocation.

> For example, would it be usable for ftrace? Steven?
>
> If not, I would prefer to make it printk-specific
> and hopefully simplify the code a bit.
>
>
>> -	if (ts_nsec > 0)
>> -		msg->ts_nsec = ts_nsec;
>> -	else
>> -		msg->ts_nsec = local_clock();
>> -	memset(log_dict(msg) + dict_len, 0, pad_len);
>> +	msg->ts_nsec = ts_nsec;
>>  	msg->len = size;
>>  
>>  	/* insert message */
>> -	log_next_idx += msg->len;
>> -	log_next_seq++;
>> +	prb_commit(&h);
>>  
>>  	return msg->text_len;
>>  }
>
> [...]
>
>>  int vprintk_store(int facility, int level,
>>  		  const char *dict, size_t dictlen,
>>  		  const char *fmt, va_list args)
>>  {
>> -	static char textbuf[LOG_LINE_MAX];
>> -	char *text = textbuf;
>> -	size_t text_len;
>> +	return vprintk_emit(facility, level, dict, dictlen, fmt, args);
>> +}
>> +
>> +/* ring buffer used as memory allocator for temporary sprint buffers */
>> +DECLARE_STATIC_PRINTKRB(sprint_rb,
>> +			ilog2(PRINTK_RECORD_MAX + sizeof(struct prb_entry) +
>> +			      sizeof(long)) + 2, &printk_cpulock);
>> +
>> +asmlinkage int vprintk_emit(int facility, int level,
>> +			    const char *dict, size_t dictlen,
>> +			    const char *fmt, va_list args)
>
> [...]
>
>> +	rbuf = prb_reserve(&h, &sprint_rb, PRINTK_SPRINT_MAX);
>
> The second ring buffer for temporary buffers is really interesting
> idea.
>
> Well, it brings some questions. For example, how many users might
> need a reservation in parallel. Or if the nested use might cause
> some problems when we decide to use printk-specific ring buffer
> implementation. I still have to think about it.

Keep in mind that it is only used by the writers, which have the
prb_cpulock. Typically there would only be 2 max users: a non-NMI writer
that was interrupted during the reserve/commit window and the
interrupting NMI that does printk. The only exception would be if the
printk-code code itself triggers a BUG_ON or WARN_ON within the
reserve/commit window. Then you will have an additional user per
recursion level.

John Ogness

^ permalink raw reply

* Re: [RFC PATCH v1 04/25] printk-rb: add writer interface
From: Petr Mladek @ 2019-02-21 13:51 UTC (permalink / raw)
  To: John Ogness
  Cc: linux-kernel, Peter Zijlstra, Sergey Senozhatsky, Steven Rostedt,
	Daniel Wang, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	Alan Cox, Jiri Slaby, Peter Feiner, linux-serial,
	Sergey Senozhatsky
In-Reply-To: <87d0nr5heh.fsf@linutronix.de>

On Sun 2019-02-17 02:32:22, John Ogness wrote:
> Hi Petr,
> 
> I've made changes to the patch that hopefully align with what you are
> looking for. I would appreciate it if you could go over it and see if
> the changes are in the right direction. And if so, you should decide
> whether I should make these kinds of changes for the whole series and
> submit a v2 before you continue with the review.
> 
> The list of changes:
> 
> - Added comments everywhere I think they could be useful. Is it too
>   much?

Some comments probably can get shortened. But I personally find
them really helpful.

I am not going to do a detailed review of this variant at the moment.
I would like to finish the review of the entire patchset first.

> - I tried moving calc_next() into prb_reserve(), but it was pure
>   insanity. I played with refactoring for a while until I found
>   something that I think looks nice. I moved the implementation of
>   calc_next() along with its containing loop into a new function
>   find_res_ptrs(). This function does what calc_next() and push_tail()
>   did. With this solution, I think prb_reserve() looks pretty
>   clean. However, the optimization of communicating about the wrap is
>   gone. So even though find_res_ptrs() knew if a wrap occurred,
>   prb_reserve() figures it out again for itself. If we want the
>   optimization, I still think the best approach is the -1,0,1 return
>   value of find_res_ptrs().

I still have to go more deeply into it. Anyway, the new code looks
much better than the previous one.

Best Regards,
Petr

^ permalink raw reply

* Re: [RFC PATCH v1 05/25] printk-rb: add basic non-blocking reading interface
From: Petr Mladek @ 2019-02-21 16:22 UTC (permalink / raw)
  To: John Ogness
  Cc: linux-kernel, Peter Zijlstra, Sergey Senozhatsky, Steven Rostedt,
	Daniel Wang, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	Alan Cox, Jiri Slaby, Peter Feiner, linux-serial,
	Sergey Senozhatsky
In-Reply-To: <87o977v4go.fsf@linutronix.de>

On Tue 2019-02-19 22:44:07, John Ogness wrote:
> Hi Petr,
> 
> Below I make several comments, responding to your questions. But I like
> the new API I believe you are trying to propose. So really only my final
> comments are of particular importance. There I show you what I think
> reader code would look like using your proposed API.
> 
> On 2019-02-18, Petr Mladek <pmladek@suse.com> wrote:
> >> + * prb_iter_init: Initialize an iterator for a ring buffer.
> >> + * @iter: The iterator to initialize.
> >> + * @rb: A ring buffer to that @iter should iterate.
> >> + * @seq: The sequence number of the position preceding the first record.
> >> + *       May be NULL.
> >> + *
> >> + * Initialize an iterator to be used with a specified ring buffer. If @seq
> >> + * is non-NULL, it will be set such that prb_iter_next() will provide a
> >> + * sequence value of "@seq + 1" if no records were missed.
> >> + *
> >> + * It is safe to call this function from any context and state.
> >> + */
> >> +void prb_iter_init(struct prb_iterator *iter, struct printk_ringbuffer *rb,
> >> +		   u64 *seq)
> >> +{
> >> +	memset(iter, 0, sizeof(*iter));
> >> +	iter->rb = rb;
> >> +	iter->lpos = PRB_INIT;
> >> +
> >> +	if (!seq)
> >> +		return;
> >> +
> >> +	for (;;) {
> >> +		struct prb_iterator tmp_iter;
> >> +		int ret;
> >> +
> >> +		prb_iter_copy(&tmp_iter, iter);
> >
> > It looks strange to copy something that has been hardly initialized.
> > I hope that we could do this without a copy, see below.
> >
> >> +
> >> +		ret = prb_iter_next(&tmp_iter, NULL, 0, seq);
> >
> > prb_iter_next() and prb_iter_data() are too complex spaghetti
> > code. They do basically the same but they do not share
> > any helper function. The error handling is different
> > which is really confusing. See below.
> 
> I don't follow why you think they do basically the same
> thing. prb_iter_next() moves forward to the next entry, then calls
> prb_iter_data() to retrieve the data. prb_iter_data() _is_ the helper
> function.

Ah, I missed the prb_iter_data() call in prb_iter_next(). I have to
admit that I did not have a courage to check them carefully. Both
functions looked like a compact maze of to_entry(), is_valid,
smp_rmb() calls ;-)

I got only the basic idea and started thinking about how
to achieve the same an easier to understand way.

> > Well, I think that we need to start with a more low-level functions.
> > IMHO. we need something to read one entry a safe way. Then it will
> > be much easier to live with races in the rest of the code:
> >
> > /*
> >  * Return valid entry on the given lpos. Data are read
> >  * only when the buffer is is not zero.
> >  */
> > int prb_get_entry(struct struct printk_ringbuffer *rb,
> > 		    unsigned long lpos,
> > 		    struct prb_entry *entry,
> > 		    unsigned int data_buf_size)
> > {
> > 	/*
> > 	 * Pointer to the ring buffer. The data might get lost
> > 	 * at any time.
> > 	 */
> > 	struct prb_entry *weak_entry;
> >
> > 	if (!is_valid(lpos))
> > 		return -EINVAL;
> >
> > 	/* Make sure that data are valid for the given valid lpos. */
> > 	smp_rmb();
> >
> > 	weak_entry = to_entry(lpos);
> > 	entry->seq = weak_entry->seq;
> >
> > 	if (data_buf_size) {
> > 		unsigned int size;
> >
> > 		size = min(data_buf_size, weak_entry->size);
> 
> weak_entry->size is untrusted data here. The following memcpy could grab
> data beyond the data array. (But we can ignore these details for now. I
> realize you are trying to refactor, not focus on these details.)

Great catch! Yes, we would need to check the overflow here.

> > 		memcpy(entry->data, weak_entry->data, size);
> > 		entry->size = size;
> > 	} else {
> > 		entry->size = weak_data->size;
> > 	}
> >
> > 	/* Make sure that the copy is done before we check validity. */
> > 	smp_mb();
> >
> > 	return is_valid(lpos);
> > }
> >
> > Then I would do the support for iterating the following way.
> > First, I would extend the structure:
> >
> > struct prb_iterator {
> > 	struct printk_ringbuffer *rb;
> > 	struct prb_entry *entry;
> > 	unsigned int data_buffer_size;
> > 	unsigned long lpos;
> > };
> >
> > And do something like:
> >
> > void prg_iter_init(struct struct printk_ringbuffer *rb,
> > 		       struct prb_entry *entry,
> > 		       unsigned int data_buffer_size,
> > 		       struct prb_iterator *iter)
> > {
> > 	iter->rb = rb;
> > 	iter->entry = entry;
> > 	iter->data_buffer_size = data_buffer_size;
> > 	lpos = 0UL;
> > }
> >
> > Then we could do iterator support the following way:
> >
> > /* Start iteration with reading the tail entry. */
> > int prb_iter_tail_entry(struct prb_iterator *iter);
> 
> A name like prb_iter_oldest_entry() might simplify things. I really
> don't want the caller to be concerned with heads and tails and which is
> which. That's an implementation detail of the ringbuffer.

Makes sense.

> > {
> > 	unsigned long tail;
> > 	int ret;
> >
> > 	for (;;) {
> > 		tail = atomic_long_read(&rb->tail);
> >
> > 		/* Ring buffer is empty? */
> 
> The ring buffer is only empty at the beginning (when tail == head). Readers
> are non-consuming, so it is never empty again once an entry is committed.

>  		if (unlikely(atomic_long_read(head) == atomic_long_read(tail)))
>  			return -EINVAL;

Yes, this is a check for empty buffer. And yes, it can be done
outside the cycle.

> The check for valid is to make sure the tail we just read hasn't already
> been overtaken by writers. I suppose this could be put into a nested
> loop so that we continue trying again until we get a valid tail.
>
> > 		if (unlikely(!is_valid(tail)))
> > 			return -EINVAL;

Heh, I wanted to add check for the empty buffer (the comment was correct).
But I added is_valid() check instead.

We could remove it. It is hidden in prb_get_entry(). The for-cycle
will get repeated when it fails.

> >
> > 		ret = prb_get_entry(iter->rb, tail,
> > 				    iter->entry, iter->data_buf_size);
> > 		if (!ret) {
> > 			iter->lpos = tail;
> > 			break;
> > 		}
> > 	}
> >
> > 	return 0;
> > }
> >
> > unsigned long next_lpos(unsineg long lpos, struct prb_entry *entry)
> > {
> > 	return lpos + sizeof(struct entry) + entry->size;
> 
> entry->size already includes sizeof(struct prb_entry) plus alignment
> padding. (Again, not important right now.)

I see. I have missed it.

> > }
> >
> > /* Try to get next entry using a valid iterator */
> > int prb_iter_next_entry(struct prb_iterator *iter)
> > {
> > 	iter->lpos = next_lpos(iter->lpos, iter->etnry);
> >
> > 	return prb_get_entry(rb, lpos, entry, data_buf_size;
> > }
> >
> > /* Try to get the next entry. Allow to skip lost messages. */
> > int prb_iter_next_valid_entry(struct prb_iterator *iter)
> > {
> > 	int ret;
> >
> > 	ret = prb_iter_next_entry(iter);
> > 	if (!ret)
> > 		return 0;
> >
> > 	/* Next entry has been lost. Skip to the current tail. */
> > 	return prb_iter_tail_entry(rb, *lpos, entry, data_buf_size);
> 
> You return values are geting mixed up here and you are not
> distinguishing between overtaken by writers and hit the end of the
> ringbuffer, but I think what you are trying to write is that
> prb_iter_next_valid_entry() should either return 0 for success or !0 if
> the end of the ringbuffer was hit.

The -1,0,1 return values were hard to follow. It might get improved
by using -EINVAL,0,-EAGAIN or so. But I hope that the two return
values are even better and will be enough.

First, I proposed two functions to distinguish the two situations:

	prb_iter_next_entry() - fails when the next entry gets
				overtaken or at the end of the buffer
	prb_iter_next_valid_entry() - fails only at the end of the buffer

Second, the lost messages might get counted by comparing seq numbers.
You actually used this in the sample code below.


> > }
> >
> >> +static bool is_valid(struct printk_ringbuffer *rb, unsigned long lpos)
> >> +{
> >> +	unsigned long head, tail;
> >> +
> >> +	tail = atomic_long_read(&rb->tail);
> >> +	head = atomic_long_read(&rb->head);
> >> +	head -= tail;
> >> +	lpos -= tail;
> >> +
> >> +	if (lpos >= head)
> >> +		return false;
> >> +	return true;
> >> +}
> 
> I am trying to understand what you want the reader code should look
> like. Keep in mind that readers can be overtaken at any moment. They
> also need to track entries they have missed. If I understand your idea,
> it is something like this (trying to keep it as simple as possible):
> 
> void print_all_entries(...)
> {
>     char buf[sizeof(struct prb_entry) + DATASIZE + sizeof(long)];
>     struct prb_entry *entry = (struct prb_entry *)&buf[0];
>     struct prb_iterator iter;
>     u64 last_seq;
> 
>     prb_iter_init(rb, entry, DATASIZE, &iter);
>     if (prb_iter_oldest_entry(&iter) != 0)
>         return; /* ringbuffer empty */
> 
>     for (;;) {
>         do_print_entry(entry);
>         last_seq = entry->seq;
>         if (prb_iter_next_valid_entry(&iter) != 0)
>             break; /* ringbuffer empty */
>         if (entry->seq - last_seq != 1)
>             print("lost %d\n", ((entry->seq - last_seq) + 1));
>     }
> }

Yes, this was my idea.

I wonder if we might allow to omit prb_iter_oldest_entry() call.
In fact, prb_iter_next_valid_entry() restarts from the oldest
entry when the expected one gets lost. But it might cause more
harm than good. I need to see it in the various existing use cases.

Anyway, the data_buf_size parameter is supposed to allow reading only
the metadata. This is useful in situations where you just need
to find which entries would fit into the given buffer. For example,
the first loop in syslog_print_all().

> I like the idea of the caller passing in a prb_entry struct. That really
> helps to reduce the parameters. And having the functions
> prb_iter_oldest_entry() and prb_iter_next_valid_entry() internally loop
> until they get a valid result also helps so that the reader doesn't have
> to do that. And if the reader doesn't have to track lost entries (for
> example, /dev/kmsg), then it becomes even less code.

I am glad to read this.

Best Regards,
Petr

^ permalink raw reply

* [PATCH v2 1/9] serial: uapi: add SER_RS485_DELAY_IN_USEC flag to struct serial_rs485
From: Martin Kepplinger @ 2019-02-21 17:17 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel, Martin Kepplinger

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

This extends the user interface for rs485 communication:

We add a new flag, SER_RS485_DELAY_IN_USEC, to struct serial_rs485 that
indicates that delay_rts_before_send and delay_rts_after_send values are
interpreted in microsecond units.

Up until now, the code comment defined these values to hold the delays in
millisecond units. Especially with fast data rates (1Mbaut or more) that
are not too uncommon for RS485, 1ms become quite long. Users need to be
able to set shorter delays than 1 ms in order not to slow down the channel
unnecessarily.

So when delays are needed, but not as long as 1ms, this enables faster
communication channels without changing the baudrate.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---

revision history
----------------
v2: re-send as a proper series after fixing my mailserver
v1: initial implementation idea


So have this totally quirky patch that uses udelay() in our tree
for a looong time now because of the above reasons - and because we are lazy.
This is an attempt to get rid of said patch on our side and fix this properly.

What do you thing about adding a flag in general?

The following patches should integrate this idea in devicetree and drivers.
These changes are NOT tested on hardware but should behave predictably
enough. I use the delays in a driver that doesn't implement them yet at
all. I'll do that after this (or something similar) is merged - it's a 2-liner
then.

Also, a patch to the rs485conf tool, that is sometimes used instead of
ioctl() directly, will be prepared as well.

thanks

                                 martin



 include/uapi/linux/serial.h | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h
index 93eb3c496ff1..c16c950ebca2 100644
--- a/include/uapi/linux/serial.h
+++ b/include/uapi/linux/serial.h
@@ -126,8 +126,15 @@ struct serial_rs485 {
 #define SER_RS485_TERMINATE_BUS		(1 << 5)	/* Enable bus
 							   termination
 							   (if supported) */
-	__u32	delay_rts_before_send;	/* Delay before send (milliseconds) */
-	__u32	delay_rts_after_send;	/* Delay after send (milliseconds) */
+#define SER_RS485_DELAY_IN_USEC		(1 << 6)	/* delay_rts_*_send
+							   values are given in
+							   microseconds */
+	__u32	delay_rts_before_send;	/* Delay before send (milliseconds
+					   by default. microseconds if flag
+					   is set) */
+	__u32	delay_rts_after_send;	/* Delay after send (milliseconds
+					   by default. microseconds if flag
+					   is set) */
 	__u32	padding[5];		/* Memory is cheap, new structs
 					   are a royal PITA .. */
 };
-- 
2.20.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

^ permalink raw reply related

* [PATCH v2 2/9] Documentation: serial-rs485: document SER_RS485_DELAY_IN_USEC flag
From: Martin Kepplinger @ 2019-02-21 17:17 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel, Martin Kepplinger
In-Reply-To: <20190221171758.10322-1-martin.kepplinger@ginzinger.com>

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

Document the new RS485 flag, SER_RS485_DELAY_IN_USEC that specifies that the
rts delay values stored in struct serial_rs485 hold values in microseconds
instead of milliseconds (the default).

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 Documentation/serial/serial-rs485.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/serial/serial-rs485.txt b/Documentation/serial/serial-rs485.txt
index ce0c1a9b8aab..a1e15e9efc2e 100644
--- a/Documentation/serial/serial-rs485.txt
+++ b/Documentation/serial/serial-rs485.txt
@@ -75,6 +75,9 @@
 	/* Set rts delay after send, if needed: */
 	rs485conf.delay_rts_after_send = ...;
 
+	/* Specify the rts delay to be microseconds, not milliseconds */
+	rs485conf.flags |= SER_RS485_DELAY_IN_USEC;
+
 	/* Set this flag if you want to receive data even while sending data */
 	rs485conf.flags |= SER_RS485_RX_DURING_TX;
 
-- 
2.20.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

^ permalink raw reply related

* [PATCH v2 3/9] serial: core: add rs485-rts-delay-us devicetree property for RS485
From: Martin Kepplinger @ 2019-02-21 17:17 UTC (permalink / raw)
  To: gregkh, robh+dt, mark.rutland, jslaby, corbet, richard.genoud,
	nicolas.ferre, alexandre.belloni, ludovic.desroches,
	mcoquelin.stm32, alexandre.torgue, linux-serial, devicetree,
	linux-arm-kernel, linux-stm32
  Cc: linux-kernel, Martin Kepplinger
In-Reply-To: <20190221171758.10322-1-martin.kepplinger@ginzinger.com>

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

struct serial_rs485 now optionally holds the rts delay values in
microseconds. Users can set these delays in their devicetree descriptions,
so this adds the microseconds-option with the "rs485-rts-delay-us" boolean
property.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 Documentation/devicetree/bindings/serial/rs485.txt |  1 +
 drivers/tty/serial/serial_core.c                   | 11 +++++++++++
 2 files changed, 12 insertions(+)

diff --git a/Documentation/devicetree/bindings/serial/rs485.txt b/Documentation/devicetree/bindings/serial/rs485.txt
index b92592dff6dd..77396c62b383 100644
--- a/Documentation/devicetree/bindings/serial/rs485.txt
+++ b/Documentation/devicetree/bindings/serial/rs485.txt
@@ -12,6 +12,7 @@ Optional properties:
   * b is the delay between end of data sent and rts signal in milliseconds
       it corresponds to the delay after sending data and actual release of the line.
   If this property is not specified, <0 0> is assumed.
+- rs485-rts-delay-us: the same as rs485-rts-delay, but in microseconds.
 - rs485-rts-active-low: drive RTS low when sending (default is high).
 - linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485
   feature at boot time. It can be disabled later with proper ioctl.
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 556f50aa1b58..4fb265b2c0fe 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -3097,6 +3097,17 @@ void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf)
 		rs485conf->delay_rts_after_send = 0;
 	}
 
+	ret = device_property_read_u32_array(dev, "rs485-rts-delay-us",
+					     rs485_delay, 2);
+	if (!ret) {
+		rs485conf->delay_rts_before_send = rs485_delay[0];
+		rs485conf->delay_rts_after_send = rs485_delay[1];
+		rs485conf->flags |= SER_RS485_DELAY_IN_USEC;
+	} else {
+		rs485conf->delay_rts_before_send = 0;
+		rs485conf->delay_rts_after_send = 0;
+	}
+
 	/*
 	 * Clear full-duplex and enabled flags, set RTS polarity to active high
 	 * to get to a defined state with the following properties:
-- 
2.20.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]

^ 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