
Hi Stefan,
From: Stefan sr@denx.de Sent: mardi 4 septembre 2018 14:08
Hi Patrick,
On 04.09.2018 09:56, Patrick DELAUNAY wrote:
Hi Stefan
From: Stefan sr@denx.de Sent: lundi 3 septembre 2018 16:03
Hi Patrick,
On 03.09.2018 15:35, Patrick DELAUNAY wrote:
Hi Simon and Stefan,
Sorry for my late answer (I just come back from my summer holiday)
From: sjg@google.com sjg@google.com On Behalf Of Simon Glass Sent: mercredi 8 août 2018 11:56
On 3 August 2018 at 05:38, Patrick Delaunay patrick.delaunay@st.com
wrote:
Add test to avoid access to rx buffer when this buffer is empty. In this case directly call getc() function to avoid issue when tstc() is not called.
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com
drivers/serial/serial-uclass.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 321d23e..4121a37 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -228,6 +228,9 @@ static int _serial_getc(struct udevice *dev) struct serial_dev_priv *upriv = dev_get_uclass_priv(dev); char val;
if (upriv->rd_ptr == upriv->wr_ptr)
return __serial_getc(dev);
val = upriv->buf[upriv->rd_ptr++]; upriv->rd_ptr %= CONFIG_SERIAL_RX_BUFFER_SIZE;
-- 2.7.4
Reviewed-by: Simon Glass sjg@chromium.org
BTW I think the code in _serial_tstc() is wrong, or at least sub-optimal:
/* Read all available chars into the RX buffer */ while (__serial_tstc(dev)) { upriv->buf[upriv->wr_ptr++] = __serial_getc(dev); upriv->wr_ptr %= CONFIG_SERIAL_RX_BUFFER_SIZE; }
It should call serial_getc() until it returns -EAGAIN. There should be no need to call __serial_tstc() first,
This part had be added by Stefan Roese in SHA1 3ca7a06afb7cbc867b7861a8b9aada74e5bbb559
But I check again the code, and I think the code is correct....
I really hope so. I did test this implementation quite heavily at that time.
but I agree it is not optimal.
we can directly ops->getc(dev) and no more __serial_getc() or __serial_tstc() : the behavior don't change but the access to serial driver is reduced. When no char is available, ops->getc witll return -EAGAIN
static int _serial_tstc(struct udevice *dev) { struct dm_serial_ops *ops = serial_get_ops(dev); struct serial_dev_priv *upriv = dev_get_uclass_priv(dev); int err;
/* Read all available chars into the RX buffer */ while(1) { err = ops->getc(dev); if (err < 0) break; upriv->buf[upriv->wr_ptr++] = err; upriv->wr_ptr %= CONFIG_SERIAL_RX_BUFFER_SIZE; }
return upriv->rd_ptr != upriv->wr_ptr ? 1 : 0; }
If you are OK I will push a other patchset for these otpimisation.
I'm not 100% sure, if this new implementation is "better". Lets compare the code:
Current version: static int _serial_tstc(struct udevice *dev) { struct serial_dev_priv *upriv = dev_get_uclass_priv(dev);
/* Read all available chars into the RX buffer */ while (__serial_tstc(dev)) { upriv->buf[upriv->wr_ptr++] = __serial_getc(dev); upriv->wr_ptr %= CONFIG_SERIAL_RX_BUFFER_SIZE; }
return upriv->rd_ptr != upriv->wr_ptr ? 1 : 0; }
New version: static int _serial_tstc(struct udevice *dev) { struct dm_serial_ops *ops = serial_get_ops(dev); struct serial_dev_priv *upriv = dev_get_uclass_priv(dev); int err;
/* Read all available chars into the RX buffer */ while(1) { err = ops->getc(dev); if (err < 0) break; upriv->buf[upriv->wr_ptr++] = err; upriv->wr_ptr %= CONFIG_SERIAL_RX_BUFFER_SIZE; }
return upriv->rd_ptr != upriv->wr_ptr ? 1 : 0; }
The new version has more code and will most likely produce a larger binary. You are removing the calls to the __foo() functions - making the call chain a bit smaller. But this will only affect the performance which is most likely negligible in this case.
Yes, perhaps a larger code but no more "pending" ops call of serial driver. I only directly use getc ops => that avoid one access to HW register I think.
Than can improve the execution time, but I agree that seems marginal in most
the case.
I any case, I don't object against any "optimizations" here. But please make sure to test any changes very thorough - please also on platforms with limited RX FIFO sizes.
Unfortunately I have no platform with limited FIFO size, So I don't known how
test it deeply.
And the impact depends also how is implemented the serial driver (gets and
pending ops can use several HW register access and is depending on the access time to the IP).
But if you and Simon think that "optimization" is not needed, you can forget
this proposal because I think also the gain should be very low.
This proposal is only a reaction on the Simon comment (at least sub-optimal)
I would prefer not to change this code without any real need (bug fix etc). As the current code has undergone many tests and has proven stable - at least for me in all my test cases. And I can't test any changes very easily, as the platform setup will take a while for me.
Ok thanks for the feedback, so I forget my "optimization" proposal. But the fist patch to protect the serial rx buffer access is needed (the initial patch reviewed by Simon).
Thanks, Stefan
Regards Patrick