Hi All,
I tested the patch on my omap3630 and I ran the cross-link test.
It works. I want to thank Fabrice Gasnier from my side.
I have, however, the following suggestions/questions to the patch:
- If I got it right, the errata only affects the RX_fifo (not the
tx_fifo), so I suggest to handle those cases separately and usually call
the normal reg_in, and put the cases were we access RHR in "#ifdef
omap"-clauses
- There is however another errata (or 'quirk') about the mdr1 register
http://www.ti.com/pdfs/wtbu/SWPZ017B_4460_Public_SE.pdf
but I don't think that this register is ever touched by the xeno_16550A
driver. (If we would touch it in the future, one would have to add
#ifdef clauses and use omapsafe_reg_out)
- in the mach-omap2/serial.c in function "serial_out_override" there is
this 10ms timeout-value, which should probably be avoided at any cost
(it will increase the latency). I actually don't see why we should wait
for the transmit_fifo to empty. Why is this necc.? Is there still
another errata about the tx_fifo?
So I suggest to usually call the normal reg_out (formerly
omap_raw_reg_out) and only call the modified one when necc. (now renamed
to omapsafe_reg_out)
I have made the changes along these lines and attached them in a patch.
(this patch is to be applied after the patch from Fabrice Gasnier)
When I compare the timings between the original patch and with my latest
changes (using cross-link and creating load with dohell -s <wlanhost>) I
get about 25% better timings under load. (I only ran each test once for
3min each, though). Without load, there is of course no big change in
the latencies.
@Fabrice: Can you check with cross-link.c on your platform? I get
worst-case timings of 150micros with your patch, and 115micros with my
additional changes. (I think these are round-trip timings, but I am not
sure)
Let me know, what you think.
Regards
Manfred
On 1/19/12 6:09 PM, Fabrice Gasnier wrote:
Finally, I find out that UART was in sleep mode.
According to omap's reference manual, it enters this mode when conditions are
met:
rx line is idle,
tx fifo and shift register are empty,
rx fifo is empty
no interrupts pending
One solution that i've tested successfully is to disable sleep mode in
rt_16550_open().
> TX interrupts are then being triggered as expected.
other quirks, see:
http://lxr.linux.no/#linux+v3.2.1/arch/arm/mach-omap2/serial.c#L742
Thank you for this link! It helps handle the fifo full condition.
However, I noticed a strange value regarding version register. My omap3530
reports 0x46?
Linux serial driver assume this bug is present on revision>= 0x52 ...
But my target freeze when I send more than 16 chars at once (Fifo full without
errata handling).
It works when using errata handling.
You'll find attached a patch that works for me.
Please advise. Maybe we can enhance it and push it?
Thanks!
Regards,
Fabrice
diff --git a/ksrc/drivers/serial/16550A.c b/ksrc/drivers/serial/16550A.c
index 81c7b70..8eb9bdb 100644
--- a/ksrc/drivers/serial/16550A.c
+++ b/ksrc/drivers/serial/16550A.c
@@ -175,7 +175,12 @@ static inline int rt_16550_rx_interrupt(struct
rt_16550_context *ctx,
int c;
do {
+#if defined (CONFIG_ARCH_OMAP3) || \
+defined (CONFIG_ARCH_OMAP4)
+ c = rt_16550_omapsafe_reg_in(mode, base, regshift, RHR);
/* read input char */
+#else
c = rt_16550_reg_in(mode, base, regshift, RHR); /* read input
char */
+#endif
ctx->in_buf[ctx->in_tail] = c;
if (ctx->in_history)
@@ -568,7 +573,12 @@ int rt_16550_close(struct rtdm_dev_context *context,
rt_16550_reg_out(mode, base, regshift, IER, 0);
rt_16550_reg_in(mode, base, regshift, IIR);
rt_16550_reg_in(mode, base, regshift, LSR);
+#if defined (CONFIG_ARCH_OMAP3) || \
+defined (CONFIG_ARCH_OMAP4)
+ rt_16550_omapsafe_reg_in(mode, base, regshift, RHR);
+#else
rt_16550_reg_in(mode, base, regshift, RHR);
+#endif
rt_16550_reg_in(mode, base, regshift, MSR);
in_history = ctx->in_history;
@@ -810,7 +820,12 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
ctx->in_npend = 0;
ctx->status = 0;
fcr |= FCR_FIFO | FCR_RESET_RX;
+#if defined (CONFIG_ARCH_OMAP3) || \
+defined (CONFIG_ARCH_OMAP4)
+ rt_16550_omapsafe_reg_in(mode, base, regshift, RHR);
+#else
rt_16550_reg_in(mode, base, regshift, RHR);
+#endif
}
if ((long)arg & RTDM_PURGE_TX_BUFFER) {
ctx->out_head = 0;
@@ -1204,7 +1219,12 @@ int __init rt_16550_init(void)
rt_16550_reg_out(mode, base, regshift, IER, 0);
rt_16550_reg_in(mode, base, regshift, IIR);
rt_16550_reg_in(mode, base, regshift, LSR);
+#if defined (CONFIG_ARCH_OMAP3) || \
+defined (CONFIG_ARCH_OMAP4)
+ rt_16550_omapsafe_reg_in(mode, base, regshift, RHR);
+#else
rt_16550_reg_in(mode, base, regshift, RHR);
+#endif
rt_16550_reg_in(mode, base, regshift, MSR);
err = rtdm_dev_register(dev);
diff --git a/ksrc/drivers/serial/16550A_io.h b/ksrc/drivers/serial/16550A_io.h
index c42bdba..9a04383 100644
--- a/ksrc/drivers/serial/16550A_io.h
+++ b/ksrc/drivers/serial/16550A_io.h
@@ -189,7 +189,7 @@ rt_16550_init_io_ctx(int dev_id, struct rt_16550_context
*ctx)
defined (CONFIG_ARCH_OMAP4)
static RT_16550_IO_INLINE u8
-rt_16550_omap_raw_reg_in(io_mode_t io_mode, unsigned long base, unsigned char
rshift, int off)
+rt_16550_reg_in(io_mode_t io_mode, unsigned long base, unsigned char rshift,
int off)
{
off <<= rshift; /* regshift */
switch (io_mode) {
@@ -201,7 +201,7 @@ rt_16550_omap_raw_reg_in(io_mode_t io_mode, unsigned long
base, unsigned char rs
}
static RT_16550_IO_INLINE void
-rt_16550_omap_raw_reg_out(io_mode_t io_mode, unsigned long base, unsigned char
rshift, int off, u8 val)
+rt_16550_reg_out(io_mode_t io_mode, unsigned long base, unsigned char rshift,
int off, u8 val)
{
off <<= rshift; /* regshift */
switch (io_mode) {
@@ -225,7 +225,7 @@ rt_16550_errata(io_mode_t io_mode, unsigned long base,
unsigned char rshift)
*/
if (cpu_is_omap44xx() /* FIXME: || cpu_is_ti816x() */)
errata |= UART_ERRATA_FIFO_FULL_ABORT;
- else if ((rev = rt_16550_omap_raw_reg_in(io_mode, base, rshift,
OMAP_MVR)) >= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV)
+ else if ((rev = rt_16550_reg_in(io_mode, base, rshift, OMAP_MVR)) >=
UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV)
errata |= UART_ERRATA_FIFO_FULL_ABORT;
return errata;
@@ -236,49 +236,49 @@ rt_16550_disable_sleep(io_mode_t io_mode, unsigned long
base, unsigned char rshi
{
unsigned char lcr, efr, ier;
- lcr = rt_16550_omap_raw_reg_in(io_mode, base, rshift, LCR);
- rt_16550_omap_raw_reg_out(io_mode, base, rshift, LCR, LCR_CONF_MODE_B);
- efr = rt_16550_omap_raw_reg_in(io_mode, base, rshift, EFR);
- rt_16550_omap_raw_reg_out(io_mode, base, rshift, EFR, EFR_ECB);
- rt_16550_omap_raw_reg_out(io_mode, base, rshift, LCR, 0x0); /*
Operational mode */
- ier = rt_16550_omap_raw_reg_in(io_mode, base, rshift, IER);
+ lcr = rt_16550_reg_in(io_mode, base, rshift, LCR);
+ rt_16550_reg_out(io_mode, base, rshift, LCR, LCR_CONF_MODE_B);
+ efr = rt_16550_reg_in(io_mode, base, rshift, EFR);
+ rt_16550_reg_out(io_mode, base, rshift, EFR, EFR_ECB);
+ rt_16550_reg_out(io_mode, base, rshift, LCR, 0x0); /* Operational mode
*/
+ ier = rt_16550_reg_in(io_mode, base, rshift, IER);
ier &= ~IERX_SLEEP; /* disable sleep */
- rt_16550_omap_raw_reg_out(io_mode, base, rshift, IER, ier);
- rt_16550_omap_raw_reg_out(io_mode, base, rshift, LCR, LCR_CONF_MODE_B);
- rt_16550_omap_raw_reg_out(io_mode, base, rshift, EFR, efr);
- rt_16550_omap_raw_reg_out(io_mode, base, rshift, LCR, lcr);
+ rt_16550_reg_out(io_mode, base, rshift, IER, ier);
+ rt_16550_reg_out(io_mode, base, rshift, LCR, LCR_CONF_MODE_B);
+ rt_16550_reg_out(io_mode, base, rshift, EFR, efr);
+ rt_16550_reg_out(io_mode, base, rshift, LCR, lcr);
}
static RT_16550_IO_INLINE u8
-rt_16550_reg_in(io_mode_t io_mode, unsigned long base, unsigned char rshift,
int off)
+rt_16550_omapsafe_reg_in(io_mode_t io_mode, unsigned long base, unsigned char
rshift, int off)
{
if (rt_16550_errata(io_mode, base, rshift)) {
if (RHR == off) {
unsigned char lsr;
- lsr = rt_16550_omap_raw_reg_in(io_mode, base, rshift,
LSR);
+ lsr = rt_16550_reg_in(io_mode, base, rshift, LSR);
if (!(lsr & RTSER_LSR_DATA)) /* Receiver data ready */
return 0; /* FIXME: -EPERM should be returned
as error */
}
}
- return rt_16550_omap_raw_reg_in(io_mode, base, rshift, off);
+ return rt_16550_reg_in(io_mode, base, rshift, off);
}
static RT_16550_IO_INLINE void
-rt_16550_reg_out(io_mode_t io_mode, unsigned long base, unsigned char rshift,
int off, u8 val)
+rt_16550_omapsafe_reg_out(io_mode_t io_mode, unsigned long base, unsigned char
rshift, int off, u8 val)
{
if (rt_16550_errata(io_mode, base, rshift)) {
unsigned char lsr;
unsigned int tmout=10000;
- lsr = rt_16550_omap_raw_reg_in(io_mode, base, rshift, LSR);
+ lsr = rt_16550_reg_in(io_mode, base, rshift, LSR);
while (!(lsr & RTSER_LSR_THR_EMTPY)) {
/* Wait up to 10ms for the character(s) to be sent. */
if(--tmout == 0)
break;
rtdm_task_sleep(1000);
- lsr = rt_16550_omap_raw_reg_in(io_mode, base, rshift,
LSR);
+ lsr = rt_16550_reg_in(io_mode, base, rshift, LSR);
}
}
- rt_16550_omap_raw_reg_out(io_mode, base, rshift, off, val);
+ rt_16550_reg_out(io_mode, base, rshift, off, val);
}
#else
_______________________________________________
Xenomai-help mailing list
[email protected]
https://mail.gna.org/listinfo/xenomai-help