All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
@ 2012-01-12 17:53 Manfred
  2012-01-12 18:44 ` Gilles Chanteperdrix
  2012-01-12 18:52 ` Wolfgang Grandegger
  0 siblings, 2 replies; 20+ messages in thread
From: Manfred @ 2012-01-12 17:53 UTC (permalink / raw)
  To: xenomai

Dear Xenomai-Developers/Users,

I am trying to get xenomai running on an omap3630 device (gumstix overo).
xenomai 2.6.0/kernel: linux-omap3-2.6.38 / i-pipe patch 2.6.38.8-arm-1.18.04

I would like to use the UART devices in a RT-application,
  and I was following the following guidelines:
http://www.xenomai.org/index.php/16550A

I had to do some changes to Kconfig in arch/arm/mach-omap2:Kconfig,
so that the omap_serial driver would not be compiled-in and so that
  I could actually disable the driver with setserial
(and correspondingly had to make some changes here and there because the
  devices are now called /dev/ttySx and not /dev/ttyOx, as in the 
omap_serial driver...)

dmesg then reports:
serial8250.0: ttyS0 at MMIO 0x4806a000 (irq = 72) is a ST16654
serial8250.1: ttyS1 at MMIO 0x4806c000 (irq = 73) is a ST16654
serial8250.2: ttyS2 at MMIO 0x49020000 (irq = 74) is a ST16654
serial8250.3: ttyS3 at MMIO 0x49042000 (irq = 80) is a ST16654

Anyway, finally I was able to the following:
 >setserial /dev/ttyS0 uart none
 >modprobe xeno_16550A mem=0x4806a000 irq=72 baud_base=3000000

(parameters same as here:
http://www.mail-archive.com/xenomai@xenomai.org
)

And then I immediately get the following Error:

--------------------
Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa06a002
Internal error: : 1028 [#1]
last sysfs file:
/sys/devices/platform/mmci-omap-hs.0/mmc_host/mmc0/mmc0:aaaa/...
.../block/mmcblk0/size
Modules linked in:
xeno_16550A(+) ipv6 libertas_sdio libertas option ads7846 cfg80211 usb_wwan
  lib80211 usbserial firmware_class
CPU: 0    Not tainted  (2.6.38 #1)
PC is at init_module+0x170/0x284 [xeno_16550A]
LR is at init_module+0x11c/0x284 [xeno_16550A]
pc : [<bf0f0170>]    lr : [<bf0f011c>]    psr: 60000013
sp : dda0ff28  ip : 4806a000  fp : bf0ece4c
r10: bf0eced0  r9 : bf0ece6c  r8 : bf0ece90
r7 : defeb380  r6 : 00000000  r5 : 00000000  r4 : defeb38c
r3 : 00000000  r2 : fa06a000  r1 : 00000001  r0 : fa06a000
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c5387d  Table: 9e558019  DAC: 00000015
Process insmod (pid: 4467, stack limit = 0xdda0e2f0)
Stack: (0xdda0ff28 to 0xdda10000)
<snip>
[<bf0f0170>] (init_module+0x170/0x284 [xeno_16550A]) from
[<c003a494>] (do_one_initcall+0xc8/0x19c)
[<c003a494>] (do_one_initcall+0xc8/0x19c) from
[<c0096f98>] (sys_init_module+0x94/0x1b4)
[<c0096f98>] (sys_init_module+0x94/0x1b4) from
[<c0040400>] (ret_fast_syscall+0x0/0x30)
Code: 1a000002 e5d23002 f57ff05f ea000003 (e5d23002)
  ---[ end trace 260381790a98f885 ]---
  overo Internal error: : 1028 [#1]
  overo last sysfs file: /sys/devices/platform/mmci-omap-hs.0/mmc_host/mmc0/
  mmc0:aaaa/block/mmcblk0/size
  overo Process insmod (pid: 4467, stack limit = 0xdda0e2f0)
Segmentation fault
----------------------

Has anyone seen something similar?
Is this possibly a bug in the xeno16550A driver module,
or perhaps a bug in the omap3 kernel?

How can I debug this? (is there a way to run gdb on insmod?)

Any help with this issue is highly appreciated.

Regards
Manfred


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-12 17:53 [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod Manfred
@ 2012-01-12 18:44 ` Gilles Chanteperdrix
  2012-01-12 19:36   ` Manfred
  2012-01-12 18:52 ` Wolfgang Grandegger
  1 sibling, 1 reply; 20+ messages in thread
From: Gilles Chanteperdrix @ 2012-01-12 18:44 UTC (permalink / raw)
  To: Manfred; +Cc: xenomai

On 01/12/2012 06:53 PM, Manfred wrote:
> Dear Xenomai-Developers/Users,
> 
> I am trying to get xenomai running on an omap3630 device (gumstix overo).
> xenomai 2.6.0/kernel: linux-omap3-2.6.38 / i-pipe patch 2.6.38.8-arm-1.18.04
> 
> I would like to use the UART devices in a RT-application,
>   and I was following the following guidelines:
> http://www.xenomai.org/index.php/16550A
> 
> I had to do some changes to Kconfig in arch/arm/mach-omap2:Kconfig,
> so that the omap_serial driver would not be compiled-in and so that
>   I could actually disable the driver with setserial
> (and correspondingly had to make some changes here and there because the
>   devices are now called /dev/ttySx and not /dev/ttyOx, as in the 
> omap_serial driver...)
> 
> dmesg then reports:
> serial8250.0: ttyS0 at MMIO 0x4806a000 (irq = 72) is a ST16654
> serial8250.1: ttyS1 at MMIO 0x4806c000 (irq = 73) is a ST16654
> serial8250.2: ttyS2 at MMIO 0x49020000 (irq = 74) is a ST16654
> serial8250.3: ttyS3 at MMIO 0x49042000 (irq = 80) is a ST16654
> 
> Anyway, finally I was able to the following:
>  >setserial /dev/ttyS0 uart none
>  >modprobe xeno_16550A mem=0x4806a000 irq=72 baud_base=3000000
> 
> (parameters same as here:
> http://www.mail-archive.com/xenomai@xenomai.org
> )
> 
> And then I immediately get the following Error:
> 
> -------------------- 
> Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa06a002

The address is not aligned on a 4 bytes boundary, and clearly in the
ioremap/vmalloc range, so, disassemble the module code and check what
happens at bf0f0170 (you have to add the module load address as from
/proc/modules to the addresses obtained when disassembling the .ko
file), if you see an "ldrh" there, then something went wrong with the
mapping of hardware registers. If you see an "ldr", then you get an
unaligned access.

> pc : [<bf0f0170>]    lr : [<bf0f011c>]    psr: 60000013


-- 
					    Gilles.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-12 17:53 [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod Manfred
  2012-01-12 18:44 ` Gilles Chanteperdrix
@ 2012-01-12 18:52 ` Wolfgang Grandegger
  1 sibling, 0 replies; 20+ messages in thread
From: Wolfgang Grandegger @ 2012-01-12 18:52 UTC (permalink / raw)
  To: Manfred; +Cc: xenomai

On 01/12/2012 06:53 PM, Manfred wrote:
> Dear Xenomai-Developers/Users,
> 
> I am trying to get xenomai running on an omap3630 device (gumstix overo).
> xenomai 2.6.0/kernel: linux-omap3-2.6.38 / i-pipe patch
> 2.6.38.8-arm-1.18.04
> 
> I would like to use the UART devices in a RT-application,
>  and I was following the following guidelines:
> http://www.xenomai.org/index.php/16550A
> 
> I had to do some changes to Kconfig in arch/arm/mach-omap2:Kconfig,
> so that the omap_serial driver would not be compiled-in and so that
>  I could actually disable the driver with setserial
> (and correspondingly had to make some changes here and there because the
>  devices are now called /dev/ttySx and not /dev/ttyOx, as in the
> omap_serial driver...)

I wonder why that's all necessary. On x86, just just do "setserial
/dev/ttyS0 uart none" before loading 16550A. Why is the name a problem?

> dmesg then reports:
> serial8250.0: ttyS0 at MMIO 0x4806a000 (irq = 72) is a ST16654
> serial8250.1: ttyS1 at MMIO 0x4806c000 (irq = 73) is a ST16654
> serial8250.2: ttyS2 at MMIO 0x49020000 (irq = 74) is a ST16654
> serial8250.3: ttyS3 at MMIO 0x49042000 (irq = 80) is a ST16654
> 
> Anyway, finally I was able to the following:
>>setserial /dev/ttyS0 uart none
>>modprobe xeno_16550A mem=0x4806a000 irq=72 baud_base=3000000
> 
> (parameters same as here:
> http://www.mail-archive.com/xenomai@xenomai.org
> )
> 
> And then I immediately get the following Error:
> 
> --------------------
> Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa06a002
> Internal error: : 1028 [#1]

Hm, address might be unaligned. Maybe you need a regshift=2... and some
other quirks as well.

Wolfgang.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-12 18:44 ` Gilles Chanteperdrix
@ 2012-01-12 19:36   ` Manfred
  2012-01-12 19:53     ` Gilles Chanteperdrix
  0 siblings, 1 reply; 20+ messages in thread
From: Manfred @ 2012-01-12 19:36 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: xenomai

Ok, so this is my first attempt on trying to debug a kernel module,   so 
please bear with me:
First, I repeated what I did before: 

1.) setserial /dev/ttyS0 uart none 

2.)modprobe xeno_16550A mem=0x4806a000 irq=72 baud_base=3000000 

3.) dmesg->error message with: 

Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa06a002 

Obtain Address-offset Ad1=0xfa06a002 

4.) get address-offset Ad0 from less /proc/modules: 

xeno_16550A 14280 1 - Loading 0xbf104000 

5.) obtain Ad2=Ad1+Ad0 (google says: 0xbf104000 + 0xfa06a002 = 
0x1B916E002)
6.) search for the last octet in the dissassembled kernel-module: 

objdump -d -S 
/lib/modules/2.6.38/kernel/drivers/xenomai/serial/xeno_16550A.ko
  > xeno16550A.diss 

grep -i B916E002 xeno16550A.diss 

7.) --> does not return anything? did I get something wrong?

Thanks for your help.

On 1/12/12 7:44 PM, Gilles Chanteperdrix wrote:
> On 01/12/2012 06:53 PM, Manfred wrote:
>> Dear Xenomai-Developers/Users,
>>
>> I am trying to get xenomai running on an omap3630 device (gumstix overo).
>> xenomai 2.6.0/kernel: linux-omap3-2.6.38 / i-pipe patch 2.6.38.8-arm-1.18.04
>>
>> I would like to use the UART devices in a RT-application,
>>    and I was following the following guidelines:
>> http://www.xenomai.org/index.php/16550A
>>
>> I had to do some changes to Kconfig in arch/arm/mach-omap2:Kconfig,
>> so that the omap_serial driver would not be compiled-in and so that
>>    I could actually disable the driver with setserial
>> (and correspondingly had to make some changes here and there because the
>>    devices are now called /dev/ttySx and not /dev/ttyOx, as in the
>> omap_serial driver...)
>>
>> dmesg then reports:
>> serial8250.0: ttyS0 at MMIO 0x4806a000 (irq = 72) is a ST16654
>> serial8250.1: ttyS1 at MMIO 0x4806c000 (irq = 73) is a ST16654
>> serial8250.2: ttyS2 at MMIO 0x49020000 (irq = 74) is a ST16654
>> serial8250.3: ttyS3 at MMIO 0x49042000 (irq = 80) is a ST16654
>>
>> Anyway, finally I was able to the following:
>>   >setserial /dev/ttyS0 uart none
>>   >modprobe xeno_16550A mem=0x4806a000 irq=72 baud_base=3000000
>>
>> (parameters same as here:
>> http://www.mail-archive.com/xenomai@xenomai.org
>> )
>>
>> And then I immediately get the following Error:
>>
>> --------------------
>> Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa06a002
>
> The address is not aligned on a 4 bytes boundary, and clearly in the
> ioremap/vmalloc range, so, disassemble the module code and check what
> happens at bf0f0170 (you have to add the module load address as from
> /proc/modules to the addresses obtained when disassembling the .ko
> file), if you see an "ldrh" there, then something went wrong with the
> mapping of hardware registers. If you see an "ldr", then you get an
> unaligned access.
>
>> pc : [<bf0f0170>]    lr : [<bf0f011c>]    psr: 60000013
>
>


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-12 19:36   ` Manfred
@ 2012-01-12 19:53     ` Gilles Chanteperdrix
  0 siblings, 0 replies; 20+ messages in thread
From: Gilles Chanteperdrix @ 2012-01-12 19:53 UTC (permalink / raw)
  To: Manfred; +Cc: xenomai

On 01/12/2012 08:36 PM, Manfred wrote:
> Ok, so this is my first attempt on trying to debug a kernel module,   so 
> please bear with me:
> First, I repeated what I did before: 
> 
> 1.) setserial /dev/ttyS0 uart none 
> 
> 2.)modprobe xeno_16550A mem=0x4806a000 irq=72 baud_base=3000000 
> 
> 3.) dmesg->error message with: 
> 
> Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa06a002 
> 
> Obtain Address-offset Ad1=0xfa06a002 
> 
> 4.) get address-offset Ad0 from less /proc/modules: 
> 
> xeno_16550A 14280 1 - Loading 0xbf104000 
> 
> 5.) obtain Ad2=Ad1+Ad0 (google says: 0xbf104000 + 0xfa06a002 = 
> 0x1B916E002)

The adress of the fault instruction is the value of the PC register,
quoting my previous mail:

>> check what happens at bf0f0170

-- 
					    Gilles.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
       [not found] <4F1080E8.6020408@domain.hid>
@ 2012-01-13 19:15 ` Manfred
  2012-01-15 19:35   ` Wolfgang Grandegger
  0 siblings, 1 reply; 20+ messages in thread
From: Manfred @ 2012-01-13 19:15 UTC (permalink / raw)
  To: xenomai

(In reply to Wolfgangs Respond)

Thank you for the explanations.
So I managed to recompile the kernel module with a lot of "printk"

commands. And I could track the problem to the following:
it fails in:[1]
int __init rt_16550_init(void)

When calling these lines:
rt_16550_reg_out(mode, base, IER, 0);
DEBUGPRINT("after reg_out IER \n");
rt_16550_reg_in(mode, base, IIR);
DEBUGPRINT("after reg_in IIR \n");

So it seems to fail the first time when it tries to call:
rt_16550_reg_in(mode, base, IIR);
where
mode=1
rt_16550_reg_in is defined in:
16550A_io.h:161:
static RT_16550_IO_INLINE u8
rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off)
{
	switch (io_mode) {
	case MODE_PIO:
		return inb(base + off);
	default: /* MODE_MMIO */
		return readb((void *)base + off);
	}
}

--> where is MODE_PIO defined?: is it 1 or 0?
(could not find it in any .c or .h file)

So anyway, it either fails in inb(base+off)
or (more probably:) in read(void*)base+off

-->
Is this consistent with your assumption that we need a regshift?
If yes, which function calls need to be fixed?
-->
I tried to look in 8250.c [2]:
regshift seems to be mostly used when using map_8250_in_reg and
map_8250_out_reg:
offset = map_8250_in_reg(p, offset) << p->regshift;
offset = map_8250_in_reg(p, offset) << p->regshift;
but also elsewhere:
2498 static unsigned int serial8250_port_size(struct uart_8250_port *pt)
2499 {
2500         if (pt->port.iotype == UPIO_AU)
2501                 return 0x1000;
2502 #ifdef CONFIG_ARCH_OMAP
2503         if (is_omap_port(pt))
2504                 return 0x16 << pt->port.regshift;
2505 #endif
2506         return 8 << pt->port.regshift;
2507 }
or:
2600 static void serial8250_release_rsa_resource(struct uart_8250_port *up)
2601 {
2602         unsigned long offset = UART_RSA_BASE << up->port.regshift;
2603         unsigned int size = 8 << up->port.regshift;
2604
2605         switch (up->port.iotype) {
2606         case UPIO_HUB6:
2607         case UPIO_PORT:
2608                 release_region(up->port.iobase + offset, size);
2609                 break;
2610         }
2611 }

-->
So can I just change the function in 16550A.c like this?:
rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off, int
regshift)
{
  	switch (io_mode) {
	case MODE_PIO:
		return inb(base + off);
	default: /* MODE_MMIO */
  		/* ADD REGSHIFT for MMIO Mode: */
  		unsigned long paddr=((void*)base+off)<< regshift;
  		return readb((void *)base + off);
	}
}

Thanks for the help.
Please note, this is really my first try on kernel modules and drivers,
So sorry, in case I got it all wrong.

--Manfred


[1]:
http://git.xenomai.org/?p=xenomai-2.6.git;a=blob;f=
ksrc/drivers/serial/16550A.c;h=8c8c86438874f03e4df17e6a2a1c02b9788f57b0;
hb=8f6feff876029244dabc1257cdf13209fbd64fb5
[2]:
http://www.sakoman.com/cgi-bin/gitweb.cgi?p=linux-omap-2.6.git;
a=blob_plain;f=drivers/tty/serial/8250.c;
hb=a6679de82eaa9128566dd5eea291afeb615764ea

 > On 1/13/12 8:37 AM, Wolfgang Grandegger wrote:
 >
 > The regshift is not yet supported. Therefore you need to adapt the
 > 16550A driver, preferably by using a module parameter.
 >
 >> The details of the addresses in omap3630/dm37x can be found here:
 >> http://www.ti.com/litv/pdf/sprugn4n
 >> Chapter 19: UART
 >> page 2950: UART Register Addresses.
 >
 > I looked to the Linux source code:
 >
 > http://lxr.linux.no/#linux+v3.2.1/arch/arm/mach-omap2/serial.c
 >
 > Therein I found the regshift=2. Adding some printk's would tell you
 > quickly what you need to get the serial uart running.
 >
 > Wolfgang.





^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-13 19:15 ` Manfred
@ 2012-01-15 19:35   ` Wolfgang Grandegger
  2012-01-18 16:15     ` Fabrice Gasnier
  2012-01-19 19:43     ` Manfred
  0 siblings, 2 replies; 20+ messages in thread
From: Wolfgang Grandegger @ 2012-01-15 19:35 UTC (permalink / raw)
  To: Manfred; +Cc: xenomai

On 01/13/2012 08:15 PM, Manfred wrote:
> (In reply to Wolfgangs Respond)
> 
> Thank you for the explanations.
> So I managed to recompile the kernel module with a lot of "printk"
> 
> commands. And I could track the problem to the following:
> it fails in:[1]
> int __init rt_16550_init(void)
> 
> When calling these lines:
> rt_16550_reg_out(mode, base, IER, 0);
> DEBUGPRINT("after reg_out IER \n");
> rt_16550_reg_in(mode, base, IIR);
> DEBUGPRINT("after reg_in IIR \n");
> 
> So it seems to fail the first time when it tries to call:
> rt_16550_reg_in(mode, base, IIR);
> where
> mode=1
> rt_16550_reg_in is defined in:
> 16550A_io.h:161:
> static RT_16550_IO_INLINE u8
> rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off)
> {
>     switch (io_mode) {
>     case MODE_PIO:
>         return inb(base + off);
>     default: /* MODE_MMIO */
>         return readb((void *)base + off);
>     }
> }
> 
> --> where is MODE_PIO defined?: is it 1 or 0?
> (could not find it in any .c or .h file)

Well, it's in :

http://www.rts.uni-hannover.de/xenomai/lxr/source/ksrc/drivers/serial/16550A_io.h

and depends on some Kconfig options. Also another prinkt can give you
the required information.

> So anyway, it either fails in inb(base+off)
> or (more probably:) in read(void*)base+off

Yes, most likely it's an unaligned access.

> -->
> Is this consistent with your assumption that we need a regshift?

Yes. I was suggesting to put some printks in the Linux serial device
setup code first to see how the registers are accessed.

> If yes, which function calls need to be fixed?
> -->
> I tried to look in 8250.c [2]:
> regshift seems to be mostly used when using map_8250_in_reg and
> map_8250_out_reg:
> offset = map_8250_in_reg(p, offset) << p->regshift;
> offset = map_8250_in_reg(p, offset) << p->regshift;
> but also elsewhere:
> 2498 static unsigned int serial8250_port_size(struct uart_8250_port *pt)
> 2499 {
> 2500         if (pt->port.iotype == UPIO_AU)
> 2501                 return 0x1000;
> 2502 #ifdef CONFIG_ARCH_OMAP
> 2503         if (is_omap_port(pt))
> 2504                 return 0x16 << pt->port.regshift;
> 2505 #endif
> 2506         return 8 << pt->port.regshift;
> 2507 }
> or:
> 2600 static void serial8250_release_rsa_resource(struct uart_8250_port *up)
> 2601 {
> 2602         unsigned long offset = UART_RSA_BASE << up->port.regshift;
> 2603         unsigned int size = 8 << up->port.regshift;
> 2604
> 2605         switch (up->port.iotype) {
> 2606         case UPIO_HUB6:
> 2607         case UPIO_PORT:
> 2608                 release_region(up->port.iobase + offset, size);
> 2609                 break;
> 2610         }
> 2611 }

This is the driver. The devices are setup and configured in

http://lxr.linux.no/#linux+v3.2.1/arch/arm/mach-omap2/serial.c

IIRC. Check what regshift is used for your hardware (by putting further
printk's).

> -->
> So can I just change the function in 16550A.c like this?:
> rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off, int
> regshift)
> {
>      switch (io_mode) {
>     case MODE_PIO:
>         return inb(base + off);
>     default: /* MODE_MMIO */
>          /* ADD REGSHIFT for MMIO Mode: */
>          unsigned long paddr=((void*)base+off)<< regshift;
>          return readb((void *)base + off);

You need to shift just the *offset* at the beginning of the function:

	off <<= regshift;

You also need to adjust the region for request_region() or ioremap().

> }
> 
> Thanks for the help.
> Please note, this is really my first try on kernel modules and drivers,
> So sorry, in case I got it all wrong.

No problem, you are welcome.

Wolfgang.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-15 19:35   ` Wolfgang Grandegger
@ 2012-01-18 16:15     ` Fabrice Gasnier
  2012-01-18 16:32       ` Wolfgang Grandegger
  2012-01-19 19:43     ` Manfred
  1 sibling, 1 reply; 20+ messages in thread
From: Fabrice Gasnier @ 2012-01-18 16:15 UTC (permalink / raw)
  To: xenomai

Dear all,

On 15/01/2012 20:35, Wolfgang Grandegger wrote:
>> -->
>> > So can I just change the function in 16550A.c like this?:
>> > rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off, int
>> > regshift)
>> > {
>> >      switch (io_mode) {
>> >     case MODE_PIO:
>> >         return inb(base + off);
>> >     default: /* MODE_MMIO */
>> >          /* ADD REGSHIFT for MMIO Mode: */
>> >          unsigned long paddr=((void*)base+off)<< regshift;
>> >          return readb((void *)base + off);
> You need to shift just the *offset* at the beginning of the function:
> 
> 	off <<= regshift;
> 
> You also need to adjust the region for request_region() or ioremap().
> 


I've done similar modifications and try to run it on an omap3530 (PHYCARD-L) board.
I'm able to receive data correctly. But tx data gives a strange behavior.
Writting a little example that basically do rt_dev_write(fd, data_string, data_len) reports no error but no data is being output.

Another example that basically echo received chars:
while (1){
	rt_dev_read(fd, rx_buf, 1);
	rt_dev_write(fd, rx_buf, 1);
	printf("%c", rx_buf[0]);
}
This one displays data when received but transmit is more random.
When a first character has been received, it is only transmitted back when a second one is received.
But second char is transmitted back immediately, without waiting for a third one ...

Further investigation indicates that when writing, tx interrupt is not asserted as expected (rt_16550_write):
/* unmask tx interrupt */
ctx->ier_status |= IER_TX;
rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
		 ctx->base_addr, IER,
		 ctx->ier_status,
		 ctx->regshift);

>From my understanding this should trigger an irq for data to be put in rt_16550_tx_interrupt().
It seems this is not always the case. Moreover, TX interrupt seem to be triggered by a new RX interrupt.

Would you have an explanation for such a behavior?
I'm not sure how to solve this.

Thanks in advance for your help.
Regards,
Fabrice 


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-18 16:15     ` Fabrice Gasnier
@ 2012-01-18 16:32       ` Wolfgang Grandegger
  2012-01-19 17:09         ` Fabrice Gasnier
  0 siblings, 1 reply; 20+ messages in thread
From: Wolfgang Grandegger @ 2012-01-18 16:32 UTC (permalink / raw)
  To: Fabrice Gasnier; +Cc: xenomai

On 01/18/2012 05:15 PM, Fabrice Gasnier wrote:
> Dear all,
> 
> On 15/01/2012 20:35, Wolfgang Grandegger wrote:
>>> -->
>>>> So can I just change the function in 16550A.c like this?:
>>>> rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off, int
>>>> regshift)
>>>> {
>>>>      switch (io_mode) {
>>>>     case MODE_PIO:
>>>>         return inb(base + off);
>>>>     default: /* MODE_MMIO */
>>>>          /* ADD REGSHIFT for MMIO Mode: */
>>>>          unsigned long paddr=((void*)base+off)<< regshift;
>>>>          return readb((void *)base + off);
>> You need to shift just the *offset* at the beginning of the function:
>>
>> 	off <<= regshift;
>>
>> You also need to adjust the region for request_region() or ioremap().
>>
> 
> 
> I've done similar modifications and try to run it on an omap3530 (PHYCARD-L) board.
> I'm able to receive data correctly. But tx data gives a strange behavior.
> Writting a little example that basically do rt_dev_write(fd, data_string, data_len) reports no error but no data is being output.
> 
> Another example that basically echo received chars:
> while (1){
> 	rt_dev_read(fd, rx_buf, 1);
> 	rt_dev_write(fd, rx_buf, 1);
> 	printf("%c", rx_buf[0]);
> }
> This one displays data when received but transmit is more random.
> When a first character has been received, it is only transmitted back when a second one is received.
> But second char is transmitted back immediately, without waiting for a third one ...
> 
> Further investigation indicates that when writing, tx interrupt is not asserted as expected (rt_16550_write):
> /* unmask tx interrupt */
> ctx->ier_status |= IER_TX;
> rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
> 		 ctx->base_addr, IER,
> 		 ctx->ier_status,
> 		 ctx->regshift);
> 
>>From my understanding this should trigger an irq for data to be put in rt_16550_tx_interrupt().
> It seems this is not always the case. Moreover, TX interrupt seem to be triggered by a new RX interrupt.

The TX interrupt will be enabled as long as there are chars to send,
IIRC. The isr the puts the chars into the FIFO and triggers the xfer.

> 
> Would you have an explanation for such a behavior?
> I'm not sure how to solve this.

Depending on the hardware/uart revision, you may need to take care of
other quirks, see:

http://lxr.linux.no/#linux+v3.2.1/arch/arm/mach-omap2/serial.c#L742

Wolfgang.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-18 16:32       ` Wolfgang Grandegger
@ 2012-01-19 17:09         ` Fabrice Gasnier
  2012-01-20 12:03           ` Manfred
  2012-01-20 18:03           ` Wolfgang Grandegger
  0 siblings, 2 replies; 20+ messages in thread
From: Fabrice Gasnier @ 2012-01-19 17:09 UTC (permalink / raw)
  To: Wolfgang Grandegger; +Cc: xenomai

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

On 18/01/2012 17:32, Wolfgang Grandegger wrote:
>> Further investigation indicates that when writing, tx interrupt is not asserted as expected (rt_16550_write):
>> > /* unmask tx interrupt */
>> > ctx->ier_status |= IER_TX;
>> > rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
>> > 		 ctx->base_addr, IER,
>> > 		 ctx->ier_status,
>> > 		 ctx->regshift);
>> > 
>> >>From my understanding this should trigger an irq for data to be put in rt_16550_tx_interrupt().
>> > It seems this is not always the case. Moreover, TX interrupt seem to be triggered by a new RX interrupt.
> The TX interrupt will be enabled as long as there are chars to send,
> IIRC. The isr the puts the chars into the FIFO and triggers the xfer.
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.
> 
>> > 
>> > Would you have an explanation for such a behavior?
>> > I'm not sure how to solve this.
> Depending on the hardware/uart revision, you may need to take care of
> 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.
> 
> Wolfgang.
> 

You'll find attached a patch that works for me.
Please advise. Maybe we can enhance it and push it?

Thanks!
Regards,

Fabrice

[-- Attachment #2: 0001-add-omap3-and-omap4-uart-support-to-xeno_16550A.patch --]
[-- Type: text/x-patch, Size: 21642 bytes --]

>From 7245af5003d4fa79823b85d982e975a0c9dc363d Mon Sep 17 00:00:00 2001
From: Fabrice Gasnier <fabrice.gasnier@domain.hid>
Date: Thu, 19 Jan 2012 17:58:58 +0100
Subject: [PATCH] add omap3 and omap4 uart support to xeno_16550A

Add regshift module parameter.
Add omap specific "fifo full" errata handling from linux-3.2 omap-serial

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@domain.hid>
---
 ksrc/drivers/serial/16550A.c    |  130 +++++++++++++++++++++++++------------
 ksrc/drivers/serial/16550A_io.h |  136 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 219 insertions(+), 47 deletions(-)

diff --git a/ksrc/drivers/serial/16550A.c b/ksrc/drivers/serial/16550A.c
index 3672539..81c7b70 100644
--- a/ksrc/drivers/serial/16550A.c
+++ b/ksrc/drivers/serial/16550A.c
@@ -70,6 +70,23 @@
 #define LSR			5	/* Line Status Register */
 #define MSR			6	/* Modem Status Register */
 
+#if defined (CONFIG_ARCH_OMAP3) || \
+	defined (CONFIG_ARCH_OMAP4)
+#define OMAP_SCR	0x10	/* Supplementary control register */
+#define OMAP_MVR	0x14	/* Module Version Register */
+#define OMAP_SYSC	0x15	/* System configuration register */
+#define OMAP_WER	0x17	/* Wake-up enable register */
+#define REGION_MAX	OMAP_WER	/* end of io/memory region */
+
+#define LCR_CONF_MODE_A		LCR_DLAB	/* Configutation mode A */
+#define LCR_CONF_MODE_B		0xBF		/* Configutation mode B */
+#define EFR					2			/* Enhanced feature register (when LCR_CONF_MODE_B) */
+#define EFR_ECB				0x10 		/* Enhanced control bit */
+#define IERX_SLEEP			0x10 		/* Enable sleep mode */
+#else
+#define REGION_MAX			MSR			/* end of io/memory region   */
+#endif
+
 struct rt_16550_context {
 	struct rtser_config config;	/* current device configuration */
 
@@ -80,6 +97,8 @@ struct rt_16550_context {
 #ifdef CONFIG_XENO_DRIVERS_16550A_ANY
 	int io_mode;			/* hardware IO-access mode */
 #endif
+	unsigned char regshift;		/* register shift */
+
 	int tx_fifo;			/* cached global tx_fifo[<device>] */
 
 	int in_head;			/* RX ring buffer, head pointer */
@@ -149,13 +168,14 @@ static inline int rt_16550_rx_interrupt(struct rt_16550_context *ctx,
 					uint64_t * timestamp)
 {
 	unsigned long base = ctx->base_addr;
+	unsigned char regshift = ctx->regshift;
 	int mode = rt_16550_io_mode_from_ctx(ctx);
 	int rbytes = 0;
 	int lsr = 0;
 	int c;
 
 	do {
-		c = rt_16550_reg_in(mode, base, RHR);	/* read input char */
+		c = rt_16550_reg_in(mode, base, regshift, RHR);	/* read input char */
 
 		ctx->in_buf[ctx->in_tail] = c;
 		if (ctx->in_history)
@@ -169,7 +189,7 @@ static inline int rt_16550_rx_interrupt(struct rt_16550_context *ctx,
 
 		rbytes++;
 		lsr &= ~RTSER_LSR_DATA;
-		lsr |= (rt_16550_reg_in(mode, base, LSR) &
+		lsr |= (rt_16550_reg_in(mode, base, regshift, LSR) &
 			(RTSER_LSR_DATA | RTSER_LSR_OVERRUN_ERR |
 			 RTSER_LSR_PARITY_ERR | RTSER_LSR_FRAMING_ERR |
 			 RTSER_LSR_BREAK_IND));
@@ -196,6 +216,7 @@ static inline void rt_16550_tx_interrupt(struct rt_16550_context *ctx)
 	int c;
 	int count;
 	unsigned long base = ctx->base_addr;
+	unsigned char regshift = ctx->regshift;
 	int mode = rt_16550_io_mode_from_ctx(ctx);
 
 /*	if (uart->modem & MSR_CTS)*/
@@ -204,7 +225,7 @@ static inline void rt_16550_tx_interrupt(struct rt_16550_context *ctx)
 		     (count > 0) && (ctx->out_npend > 0);
 		     count--, ctx->out_npend--) {
 			c = ctx->out_buf[ctx->out_head++];
-			rt_16550_reg_out(mode, base, THR, c);
+			rt_16550_reg_out(mode, base, regshift, THR, c);
 			ctx->out_head &= (OUT_BUFFER_SIZE - 1);
 		}
 	}
@@ -213,9 +234,10 @@ static inline void rt_16550_tx_interrupt(struct rt_16550_context *ctx)
 static inline void rt_16550_stat_interrupt(struct rt_16550_context *ctx)
 {
 	unsigned long base = ctx->base_addr;
+	unsigned char regshift = ctx->regshift;
 	int mode = rt_16550_io_mode_from_ctx(ctx);
 
-	ctx->status |= (rt_16550_reg_in(mode, base, LSR) &
+	ctx->status |= (rt_16550_reg_in(mode, base, regshift, LSR) &
 			(RTSER_LSR_OVERRUN_ERR | RTSER_LSR_PARITY_ERR |
 			 RTSER_LSR_FRAMING_ERR | RTSER_LSR_BREAK_IND));
 }
@@ -224,6 +246,7 @@ static int rt_16550_interrupt(rtdm_irq_t * irq_context)
 {
 	struct rt_16550_context *ctx;
 	unsigned long base;
+	unsigned char regshift;
 	int mode;
 	int iir;
 	uint64_t timestamp = rtdm_clock_read();
@@ -234,12 +257,13 @@ static int rt_16550_interrupt(rtdm_irq_t * irq_context)
 
 	ctx = rtdm_irq_get_arg(irq_context, struct rt_16550_context);
 	base = ctx->base_addr;
+	regshift = ctx->regshift;
 	mode = rt_16550_io_mode_from_ctx(ctx);
 
 	rtdm_lock_get(&ctx->lock);
 
 	while (1) {
-		iir = rt_16550_reg_in(mode, base, IIR) & IIR_MASK;
+		iir = rt_16550_reg_in(mode, base, regshift, IIR) & IIR_MASK;
 		if (testbits(iir, IIR_PIRQ))
 			break;
 
@@ -251,7 +275,7 @@ static int rt_16550_interrupt(rtdm_irq_t * irq_context)
 		else if (iir == IIR_TX)
 			rt_16550_tx_interrupt(ctx);
 		else if (iir == IIR_MODEM) {
-			modem = rt_16550_reg_in(mode, base, MSR);
+			modem = rt_16550_reg_in(mode, base, regshift, MSR);
 			if (modem & (modem << 4))
 				events |= RTSER_EVENT_MODEMHI;
 			if ((modem ^ 0xF0) & (modem << 4))
@@ -292,7 +316,7 @@ static int rt_16550_interrupt(rtdm_irq_t * irq_context)
 	}
 
 	/* update interrupt mask */
-	rt_16550_reg_out(mode, base, IER, ctx->ier_status);
+	rt_16550_reg_out(mode, base, regshift, IER, ctx->ier_status);
 
 	rtdm_lock_put(&ctx->lock);
 
@@ -305,6 +329,7 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 {
 	rtdm_lockctx_t lock_ctx;
 	unsigned long base = ctx->base_addr;
+	unsigned char regshift = ctx->regshift;
 	int mode = rt_16550_io_mode_from_ctx(ctx);
 	int err = 0;
 
@@ -320,9 +345,9 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 		ctx->config.baud_rate = config->baud_rate;
 		baud_div = (baud_base[dev_id] + (ctx->config.baud_rate>>1)) /
 			ctx->config.baud_rate;
-		rt_16550_reg_out(mode, base, LCR, LCR_DLAB);
-		rt_16550_reg_out(mode, base, DLL, baud_div & 0xff);
-		rt_16550_reg_out(mode, base, DLM, baud_div >> 8);
+		rt_16550_reg_out(mode, base, regshift, LCR, LCR_DLAB);
+		rt_16550_reg_out(mode, base, regshift, DLL, baud_div & 0xff);
+		rt_16550_reg_out(mode, base, regshift, DLM, baud_div >> 8);
 	}
 
 	if (testbits(config->config_mask, RTSER_SET_PARITY))
@@ -336,7 +361,7 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 					  RTSER_SET_DATA_BITS |
 					  RTSER_SET_STOP_BITS |
 					  RTSER_SET_BAUD)) {
-		rt_16550_reg_out(mode, base, LCR,
+		rt_16550_reg_out(mode, base, regshift, LCR,
 				 (ctx->config.parity << 3) |
 				 (ctx->config.stop_bits << 2) |
 				 ctx->config.data_bits);
@@ -346,9 +371,9 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 
 	if (testbits(config->config_mask, RTSER_SET_FIFO_DEPTH)) {
 		ctx->config.fifo_depth = config->fifo_depth & FIFO_MASK;
-		rt_16550_reg_out(mode, base, FCR,
+		rt_16550_reg_out(mode, base, regshift, FCR,
 				 FCR_FIFO | FCR_RESET_RX | FCR_RESET_TX);
-		rt_16550_reg_out(mode, base, FCR,
+		rt_16550_reg_out(mode, base, regshift, FCR,
 				 FCR_FIFO | ctx->config.fifo_depth);
 	}
 
@@ -405,7 +430,7 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 		else
 			/* disable modem status interrupt */
 			ctx->ier_status &= ~IER_MODEM;
-		rt_16550_reg_out(mode, base, IER, ctx->ier_status);
+		rt_16550_reg_out(mode, base, regshift, IER, ctx->ier_status);
 
 		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
 	}
@@ -425,7 +450,7 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 			    RTSER_MCR_DTR | RTSER_MCR_RTS | RTSER_MCR_OUT2;
 			break;
 		}
-		rt_16550_reg_out(mode, base, MCR, ctx->mcr_status);
+		rt_16550_reg_out(mode, base, regshift, MCR, ctx->mcr_status);
 
 		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
 	}
@@ -449,6 +474,10 @@ int rt_16550_open(struct rtdm_dev_context *context,
 	int err;
 	uint64_t *dummy;
 	rtdm_lockctx_t lock_ctx;
+#if defined (CONFIG_ARCH_OMAP3) || \
+	defined (CONFIG_ARCH_OMAP4)
+	int ier;
+#endif
 
 	ctx = (struct rt_16550_context *)context->dev_private;
 
@@ -487,19 +516,28 @@ int rt_16550_open(struct rtdm_dev_context *context,
 	if (err) {
 		/* reset DTR and RTS */
 		rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx), ctx->base_addr,
-				 MCR, 0);
+				 ctx->regshift, MCR, 0);
 
 		rt_16550_cleanup_ctx(ctx);
 
 		return err;
 	}
 
+#if defined (CONFIG_ARCH_OMAP3) || \
+	defined (CONFIG_ARCH_OMAP4)
+	ier = rt_16550_reg_in(rt_16550_io_mode_from_ctx(ctx),
+			ctx->base_addr, ctx->regshift, IER);
+	if (ier & IERX_SLEEP)
+		rt_16550_disable_sleep(rt_16550_io_mode_from_ctx(ctx), ctx->base_addr,
+				ctx->regshift);
+#endif
+
 	rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);
 
 	/* enable interrupts */
 	ctx->ier_status = IER_RX;
-	rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx), ctx->base_addr, IER,
-			 IER_RX);
+	rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx), ctx->base_addr,
+			 ctx->regshift, IER, IER_RX);
 
 	rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
 
@@ -511,25 +549,27 @@ int rt_16550_close(struct rtdm_dev_context *context,
 {
 	struct rt_16550_context *ctx;
 	unsigned long base;
+	unsigned char regshift;
 	int mode;
 	uint64_t *in_history;
 	rtdm_lockctx_t lock_ctx;
 
 	ctx = (struct rt_16550_context *)context->dev_private;
 	base = ctx->base_addr;
+	regshift = ctx->regshift;
 	mode = rt_16550_io_mode_from_ctx(ctx);
 
 	rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);
 
 	/* reset DTR and RTS */
-	rt_16550_reg_out(mode, base, MCR, 0);
+	rt_16550_reg_out(mode, base, regshift, MCR, 0);
 
 	/* mask all UART interrupts and clear pending ones. */
-	rt_16550_reg_out(mode, base, IER, 0);
-	rt_16550_reg_in(mode, base, IIR);
-	rt_16550_reg_in(mode, base, LSR);
-	rt_16550_reg_in(mode, base, RHR);
-	rt_16550_reg_in(mode, base, MSR);
+	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);
+	rt_16550_reg_in(mode, base, regshift, RHR);
+	rt_16550_reg_in(mode, base, regshift, MSR);
 
 	in_history = ctx->in_history;
 	ctx->in_history = NULL;
@@ -553,10 +593,12 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 	struct rt_16550_context *ctx;
 	int err = 0;
 	unsigned long base;
+	unsigned char regshift;
 	int mode;
 
 	ctx = (struct rt_16550_context *)context->dev_private;
 	base = ctx->base_addr;
+	regshift = ctx->regshift;
 	mode = rt_16550_io_mode_from_ctx(ctx);
 
 	switch (request) {
@@ -638,9 +680,9 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 			struct rtser_status status_buf;
 
 			status_buf.line_status =
-			    rt_16550_reg_in(mode, base, LSR) | status;
+			    rt_16550_reg_in(mode, base, regshift, LSR) | status;
 			status_buf.modem_status =
-			    rt_16550_reg_in(mode, base, MSR);
+			    rt_16550_reg_in(mode, base, regshift, MSR);
 
 			err =
 			    rtdm_safe_copy_to_user(user_info, arg,
@@ -649,9 +691,9 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 							  rtser_status));
 		} else {
 			((struct rtser_status *)arg)->line_status =
-			    rt_16550_reg_in(mode, base, LSR) | status;
+			    rt_16550_reg_in(mode, base, regshift, LSR) | status;
 			((struct rtser_status *)arg)->modem_status =
-			    rt_16550_reg_in(mode, base, MSR);
+			    rt_16550_reg_in(mode, base, regshift, MSR);
 		}
 		break;
 	}
@@ -672,7 +714,7 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 
 		rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);
 		ctx->mcr_status = new_mcr;
-		rt_16550_reg_out(mode, base, MCR, new_mcr);
+		rt_16550_reg_out(mode, base, regshift, MCR, new_mcr);
 		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
 		break;
 	}
@@ -698,7 +740,7 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 			if (testbits(ctx->config.event_mask,
 				     RTSER_EVENT_ERRPEND)) {
 				ctx->ier_status |= IER_STAT;
-				rt_16550_reg_out(mode, base, IER,
+				rt_16550_reg_out(mode, base, regshift, IER,
 						 ctx->ier_status);
 			}
 
@@ -752,7 +794,7 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 		    (ctx->config.parity << 3) | (ctx->config.stop_bits << 2) |
 		    ctx->config.data_bits;
 
-		rt_16550_reg_out(mode, base, LCR, lcr);
+		rt_16550_reg_out(mode, base, regshift, LCR, lcr);
 
 		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
 		break;
@@ -768,7 +810,7 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 			ctx->in_npend = 0;
 			ctx->status = 0;
 			fcr |= FCR_FIFO | FCR_RESET_RX;
-			rt_16550_reg_in(mode, base, RHR);
+			rt_16550_reg_in(mode, base, regshift, RHR);
 		}
 		if ((long)arg & RTDM_PURGE_TX_BUFFER) {
 			ctx->out_head = 0;
@@ -777,8 +819,8 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 			fcr |= FCR_FIFO | FCR_RESET_TX;
 		}
 		if (fcr) {
-			rt_16550_reg_out(mode, base, FCR, fcr);
-			rt_16550_reg_out(mode, base, FCR,
+			rt_16550_reg_out(mode, base, regshift, FCR, fcr);
+			rt_16550_reg_out(mode, base, regshift, FCR,
 					 FCR_FIFO | ctx->config.fifo_depth);
 		}
 		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
@@ -831,8 +873,8 @@ ssize_t rt_16550_read(struct rtdm_dev_context * context,
 		if (!testbits(ctx->ier_status, IER_STAT)) {
 			ctx->ier_status |= IER_STAT;
 			rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
-					 ctx->base_addr, IER,
-					 ctx->ier_status);
+					 ctx->base_addr, ctx->regshift,
+					 IER, ctx->ier_status);
 		}
 
 		if (ctx->status) {
@@ -1046,8 +1088,8 @@ ssize_t rt_16550_write(struct rtdm_dev_context * context,
 			/* unmask tx interrupt */
 			ctx->ier_status |= IER_TX;
 			rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
-					 ctx->base_addr, IER,
-					 ctx->ier_status);
+					 ctx->base_addr, ctx->regshift,
+					 IER, ctx->ier_status);
 
 			rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
 			continue;
@@ -1117,6 +1159,7 @@ int __init rt_16550_init(void)
 {
 	struct rtdm_device *dev;
 	unsigned long base;
+	unsigned char regshift;
 	int mode;
 	int err;
 	int i;
@@ -1157,11 +1200,12 @@ int __init rt_16550_init(void)
 		/* Mask all UART interrupts and clear pending ones. */
 		base = rt_16550_base_addr(i);
 		mode = rt_16550_io_mode(i);
-		rt_16550_reg_out(mode, base, IER, 0);
-		rt_16550_reg_in(mode, base, IIR);
-		rt_16550_reg_in(mode, base, LSR);
-		rt_16550_reg_in(mode, base, RHR);
-		rt_16550_reg_in(mode, base, MSR);
+		regshift = rt_16550_regshift(i);
+		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);
+		rt_16550_reg_in(mode, base, regshift, RHR);
+		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 92d21a5..c42bdba 100644
--- a/ksrc/drivers/serial/16550A_io.h
+++ b/ksrc/drivers/serial/16550A_io.h
@@ -31,15 +31,25 @@ MODULE_PARM_DESC(io, "I/O port addresses of the serial devices");
     defined(CONFIG_XENO_DRIVERS_16550A_ANY)
 static unsigned long mem[MAX_DEVICES];
 static void *mapped_io[MAX_DEVICES];
+static unsigned char regshift[MAX_DEVICES];
 compat_module_param_array(mem, ulong, MAX_DEVICES, 0400);
+compat_module_param_array(regshift, byte, MAX_DEVICES, 0400);
 MODULE_PARM_DESC(mem, "I/O memory addresses of the serial devices");
+MODULE_PARM_DESC(regshift, "register shift (ex: on some omap, use regshift=2)");
 #endif /* CONFIG_XENO_DRIVERS_16550A_MMIO || CONFIG_XENO_DRIVERS_16550A_ANY */
 
+#if defined (CONFIG_ARCH_OMAP3) || \
+	defined (CONFIG_ARCH_OMAP4)
+#define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV     0x46
+#define UART_ERRATA_FIFO_FULL_ABORT     		(0x1 << 0)
+#endif
+
 #ifdef CONFIG_XENO_DRIVERS_16550A_PIO
 
 #define RT_16550_IO_INLINE inline
 
 extern void *mapped_io[]; /* dummy */
+static unsigned char regshift[]; /* dummy */
 
 static inline unsigned long rt_16550_addr_param(int dev_id)
 {
@@ -61,6 +71,11 @@ static inline io_mode_t rt_16550_io_mode(int dev_id)
 	return MODE_PIO;
 }
 
+static inline unsigned char rt_16550_regshift(int dev_id)
+{
+	return 0;
+}
+
 static inline io_mode_t
 rt_16550_io_mode_from_ctx(struct rt_16550_context *ctx)
 {
@@ -99,6 +114,11 @@ static inline io_mode_t rt_16550_io_mode(int dev_id)
 	return MODE_MMIO;
 }
 
+static inline unsigned char rt_16550_regshift(int dev_id)
+{
+	return (unsigned char)regshift[dev_id];
+}
+
 static inline io_mode_t
 rt_16550_io_mode_from_ctx(struct rt_16550_context *ctx)
 {
@@ -109,6 +129,7 @@ static inline void
 rt_16550_init_io_ctx(int dev_id, struct rt_16550_context *ctx)
 {
 	ctx->base_addr = (unsigned long)mapped_io[dev_id];
+	ctx->regshift = (unsigned char)regshift[dev_id];
 }
 
 #elif defined(CONFIG_XENO_DRIVERS_16550A_ANY)
@@ -135,6 +156,11 @@ static inline io_mode_t rt_16550_io_mode(int dev_id)
 	return (io[dev_id]) ? MODE_PIO : MODE_MMIO;
 }
 
+static inline unsigned char rt_16550_regshift(int dev_id)
+{
+	return (io[dev_id]) ? 0 : (unsigned char)regshift[dev_id];
+}
+
 static inline io_mode_t
 rt_16550_io_mode_from_ctx(struct rt_16550_context *ctx)
 {
@@ -151,15 +177,115 @@ rt_16550_init_io_ctx(int dev_id, struct rt_16550_context *ctx)
 		ctx->base_addr = (unsigned long)mapped_io[dev_id];
 		ctx->io_mode   = MODE_MMIO;
 	}
+	ctx->regshift = (unsigned char)regshift[dev_id];
 }
 
 #else
 # error Unsupported I/O access method
 #endif
 
+
+#if defined (CONFIG_ARCH_OMAP3) || \
+	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)
+{
+	off <<= rshift;	/* regshift */
+	switch (io_mode) {
+	case MODE_PIO:
+		return inb(base + off);
+	default: /* MODE_MMIO */
+		return readb((void *)base + off);
+	}
+}
+
+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)
+{
+	off <<= rshift;	/* regshift */
+	switch (io_mode) {
+	case MODE_PIO:
+		outb(val, base + off);
+		break;
+	case MODE_MMIO:
+		writeb(val, (void *)base + off);
+		break;
+	}
+}
+
+static RT_16550_IO_INLINE int
+rt_16550_errata(io_mode_t io_mode, unsigned long base, unsigned char rshift)
+{
+	int errata = 0, rev;
+	/*
+	 * omap44xx, ti816x: Never read empty UART fifo
+	 * omap3xxx: Never read empty UART fifo on UARTs
+	 * with IP rev >=0x46
+	 */
+	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)
+		errata |= UART_ERRATA_FIFO_FULL_ABORT;
+
+	return errata;
+}
+
+static RT_16550_IO_INLINE void
+rt_16550_disable_sleep(io_mode_t io_mode, unsigned long base, unsigned char rshift)
+{
+	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);
+	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);
+}
+
+static RT_16550_IO_INLINE u8
+rt_16550_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);
+			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);
+}
+
+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)
+{
+	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);
+		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);
+		}
+	}
+	rt_16550_omap_raw_reg_out(io_mode, base, rshift, off, val);
+}
+
+#else
 static RT_16550_IO_INLINE u8
-rt_16550_reg_in(io_mode_t io_mode, unsigned long base, 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) {
 	case MODE_PIO:
 		return inb(base + off);
@@ -169,8 +295,9 @@ rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off)
 }
 
 static RT_16550_IO_INLINE void
-rt_16550_reg_out(io_mode_t io_mode, unsigned long base, 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) {
 	case MODE_PIO:
 		outb(val, base + off);
@@ -180,16 +307,17 @@ rt_16550_reg_out(io_mode_t io_mode, unsigned long base, int off, u8 val)
 		break;
 	}
 }
+#endif //CONFIG_ARCH_OMAP3/4
 
 static int rt_16550_init_io(int dev_id, char* name)
 {
 	switch (rt_16550_io_mode(dev_id)) {
 	case MODE_PIO:
-		if (!request_region(rt_16550_addr_param(dev_id), 8, name))
+		if (!request_region(rt_16550_addr_param(dev_id), REGION_MAX, name))
 			return -EBUSY;
 		break;
 	case MODE_MMIO:
-		mapped_io[dev_id] = ioremap(rt_16550_addr_param(dev_id), 8);
+		mapped_io[dev_id] = ioremap(rt_16550_addr_param(dev_id), REGION_MAX << regshift[dev_id]);
 		if (!mapped_io[dev_id])
 			return -EBUSY;
 		break;
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-15 19:35   ` Wolfgang Grandegger
  2012-01-18 16:15     ` Fabrice Gasnier
@ 2012-01-19 19:43     ` Manfred
  1 sibling, 0 replies; 20+ messages in thread
From: Manfred @ 2012-01-19 19:43 UTC (permalink / raw)
  To: Wolfgang Grandegger; +Cc: xenomai

I finally managed to get the module compiling,
running and inserting.

The main problems (so far) were basically:
- Need a regshift for the offset
- Need a regshift when calling ioremap
AND (and this a bit tricky, because it is omap3630-specific):
- Make sure that we never read an empty rx_fifo:
if (testbits(rt_16550_reg_in(mode, base, LSR,MYREGSHIFT),RHR_EMPTY))
In front of any read with a RHR (Receive Holding Buffer)
rt_16550_reg_in(mode, base, RHR,MYREGSHIFT)

So far so good. However, if I make a crosslink example
(I connect the pins on my expansion board like this: uart1_tx<->uart2_rx,
uart1_rx<->uart2_tx), I always get a time-out:
---------------------------
main : write-file opened
main : write-config written
main : read-file opened
main : read-config written
main : write-task created
main : read-task created
main : starting write-task
main : starting read-task
  Nr |   write->irq    |    irq->read    |   write->read   |
-----------------------------------------------------------
read_task: error on RTSER_RTIOC_WAIT_EVENT, Connection timed out
read_task: error on RTSER_RTIOC_WAIT_EVENT, Connection timed out
read_task: error on RTSER_RTIOC_WAIT_EVENT, Connection timed out
read_task: error on RTSER_RTIOC_WAIT_EVENT, Connection timed out
---------------------------

I tried to track where the message comes from:
"rt_16550_read(..)" seems to bail-out with a return value of
ETIMEDOUT
but this seems to be defined in the rtdm-files ...
so I did not want to dig further, before asking here.

Do I need to also wire the cts, and rts cables to make it work?
(That would be really bad, because I don't have access to them
(not enough pin-outs))

When I have the standard driver (serial8250) loaded, I can
communicate with socat between the two interfaces.

Any Ideas?
I am not sure if this might be related to the IRQ problems
that Fabrice has mentioned in a recent post.

Thanks for the help.

For completeness: here the diffs:
(MYREGSHIFT is a macro at the moment, I have not decided yet how to 
store them)


diff -u ./serial/16550A.c ./serial/16550A.c
--- ./serial//16550A.c	2012-01-19 20:27:30.688571574 +0100
+++ ./serial//16550A.c	2012-01-19 20:25:21.229675524 +0100
@@ -16,6 +16,7 @@
   * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   */

+
  #include <linux/version.h>
  #include <linux/module.h>
  #include <linux/ioport.h>
@@ -24,6 +25,17 @@
  #include <rtdm/rtserial.h>
  #include <rtdm/rtdm_driver.h>

+#define WHERESTR  "[file %s, line %d]: %s "
+#define WHEREARG  __FILE__, __LINE__
+
+//On OMAP3630: we need to check if Receiver FIFO is empty
+//A read on empty FIFO register is undefined (crashes)
+#define RHR_EMPTY		0x01
+
+
+#define MYREGSHIFT 2
+
+
  #define RT_16550_DRIVER_NAME	"xeno_16550A"

  #define MAX_DEVICES		8
@@ -107,7 +119,9 @@
  	int mcr_status;			/* MCR cache */
  	int status;			/* cache for LSR + soft-states */
  	int saved_errors;		/* error cache for RTIOC_GET_STATUS */
-};
+	int regshift;			/* Register shift for pointers
+					(e.g. regshift=2 on omap3630) */
+};
+//__attribute__ ((aligned (32)));

  static const struct rtser_config default_config = {
  	0xFFFF, RTSER_DEF_BAUD, RTSER_DEF_PARITY, RTSER_DEF_BITS,
@@ -124,16 +138,21 @@
  };
  static unsigned int baud_base[MAX_DEVICES];
  static int tx_fifo[MAX_DEVICES];
+static int regshift[MAX_DEVICES];
+
  static unsigned int start_index;

  compat_module_param_array(irq, uint, MAX_DEVICES, 0400);
  compat_module_param_array(baud_base, uint, MAX_DEVICES, 0400);
  compat_module_param_array(tx_fifo, int, MAX_DEVICES, 0400);
+compat_module_param_array(regshift, int, MAX_DEVICES, 0400);

  MODULE_PARM_DESC(irq, "IRQ numbers of the serial devices");
  MODULE_PARM_DESC(baud_base, "Maximum baud rate of the serial device "
  		 "(internal clock rate / 16)");
  MODULE_PARM_DESC(tx_fifo, "Transmitter FIFO size");
+MODULE_PARM_DESC(regshift, "Register Shift (e.g. for omap3630:2)");
+

  module_param(start_index, uint, 0400);
  MODULE_PARM_DESC(start_index, "First device instance number to be used");
@@ -154,27 +173,38 @@
  	int lsr = 0;
  	int c;

-	do {
-		c = rt_16550_reg_in(mode, base, RHR);	/* read input char */
-
-		ctx->in_buf[ctx->in_tail] = c;
-		if (ctx->in_history)
-			ctx->in_history[ctx->in_tail] = *timestamp;
-		ctx->in_tail = (ctx->in_tail + 1) & (IN_BUFFER_SIZE - 1);
-
-		if (++ctx->in_npend > IN_BUFFER_SIZE) {
-			lsr |= RTSER_SOFT_OVERRUN_ERR;
-			ctx->in_npend--;
-		}
-
-		rbytes++;
-		lsr &= ~RTSER_LSR_DATA;
-		lsr |= (rt_16550_reg_in(mode, base, LSR) &
-			(RTSER_LSR_DATA | RTSER_LSR_OVERRUN_ERR |
-			 RTSER_LSR_PARITY_ERR | RTSER_LSR_FRAMING_ERR |
-			 RTSER_LSR_BREAK_IND));
-	} while (testbits(lsr, RTSER_LSR_DATA));
-
+//if (testbits(rt_16550_reg_in(mode, base, LSR,MYREGSHIFT),RHR_EMPTY))
+      /* only read when RX FIFO not empty. */
+//	{
+	do {
+			
+	if (testbits(rt_16550_reg_in(mode, base, LSR,MYREGSHIFT),RHR_EMPTY))
+	{
+     	  c = rt_16550_reg_in(mode, base, RHR,MYREGSHIFT);/* read input 
char */
+	}
+	else
+	{
+	  c=0; //What should we return on empty fifo read?
+	}
+			
+			ctx->in_buf[ctx->in_tail] = c;
+			if (ctx->in_history)
+			ctx->in_history[ctx->in_tail] = *timestamp;
+		ctx->in_tail = (ctx->in_tail + 1) & (IN_BUFFER_SIZE - 1);
+			
+			if (++ctx->in_npend > IN_BUFFER_SIZE) {
+				lsr |= RTSER_SOFT_OVERRUN_ERR;
+				ctx->in_npend--;
+			}
+			
+	rbytes++;
+	lsr &= ~RTSER_LSR_DATA;
+	lsr |= (rt_16550_reg_in(mode, base, LSR,MYREGSHIFT) &
+			(RTSER_LSR_DATA | RTSER_LSR_OVERRUN_ERR |
+			 RTSER_LSR_PARITY_ERR | RTSER_LSR_FRAMING_ERR |
+					 RTSER_LSR_BREAK_IND));
+		} while (testbits(lsr, RTSER_LSR_DATA));
+//	}
+	
  	/* save new errors */
  	ctx->status |= lsr;

@@ -185,7 +215,7 @@
  	    (uart->config.handshake & RT_UART_RTSCTS) != 0 &&
  	    (uart->modem & MCR_RTS) != 0) {
  		uart->modem &= ~MCR_RTS;
-		rt_16550_reg_out(mode, base, MCR, uart->modem);
+		rt_16550_reg_out(mode, base, MCR, uart->modem,MYREGSHIFT);
  	}*/

  	return rbytes;
@@ -204,7 +234,7 @@
  		     (count > 0) && (ctx->out_npend > 0);
  		     count--, ctx->out_npend--) {
  			c = ctx->out_buf[ctx->out_head++];
-			rt_16550_reg_out(mode, base, THR, c);
+			rt_16550_reg_out(mode, base, THR, c,MYREGSHIFT);
  			ctx->out_head &= (OUT_BUFFER_SIZE - 1);
  		}
  	}
@@ -215,7 +245,7 @@
  	unsigned long base = ctx->base_addr;
  	int mode = rt_16550_io_mode_from_ctx(ctx);

-	ctx->status |= (rt_16550_reg_in(mode, base, LSR) &
+	ctx->status |= (rt_16550_reg_in(mode, base, LSR,MYREGSHIFT) &
  			(RTSER_LSR_OVERRUN_ERR | RTSER_LSR_PARITY_ERR |
  			 RTSER_LSR_FRAMING_ERR | RTSER_LSR_BREAK_IND));
  }
@@ -239,7 +269,7 @@
  	rtdm_lock_get(&ctx->lock);

  	while (1) {
-		iir = rt_16550_reg_in(mode, base, IIR) & IIR_MASK;
+		iir = rt_16550_reg_in(mode, base, IIR,MYREGSHIFT) & IIR_MASK;
  		if (testbits(iir, IIR_PIRQ))
  			break;

@@ -251,7 +281,7 @@
  		else if (iir == IIR_TX)
  			rt_16550_tx_interrupt(ctx);
  		else if (iir == IIR_MODEM) {
-			modem = rt_16550_reg_in(mode, base, MSR);
+			modem = rt_16550_reg_in(mode, base, MSR,MYREGSHIFT);
  			if (modem & (modem << 4))
  				events |= RTSER_EVENT_MODEMHI;
  			if ((modem ^ 0xF0) & (modem << 4))
@@ -292,7 +322,7 @@
  	}

  	/* update interrupt mask */
-	rt_16550_reg_out(mode, base, IER, ctx->ier_status);
+	rt_16550_reg_out(mode, base, IER, ctx->ier_status,MYREGSHIFT);

  	rtdm_lock_put(&ctx->lock);

@@ -320,9 +350,9 @@
  		ctx->config.baud_rate = config->baud_rate;
  		baud_div = (baud_base[dev_id] + (ctx->config.baud_rate>>1)) /
  			ctx->config.baud_rate;
-		rt_16550_reg_out(mode, base, LCR, LCR_DLAB);
-		rt_16550_reg_out(mode, base, DLL, baud_div & 0xff);
-		rt_16550_reg_out(mode, base, DLM, baud_div >> 8);
+		rt_16550_reg_out(mode, base, LCR, LCR_DLAB,MYREGSHIFT);
+		rt_16550_reg_out(mode, base, DLL, baud_div & 0xff,MYREGSHIFT);
+		rt_16550_reg_out(mode, base, DLM, baud_div >> 8,MYREGSHIFT);
  	}

  	if (testbits(config->config_mask, RTSER_SET_PARITY))
@@ -339,7 +369,7 @@
  		rt_16550_reg_out(mode, base, LCR,
  				 (ctx->config.parity << 3) |
  				 (ctx->config.stop_bits << 2) |
-				 ctx->config.data_bits);
+				 ctx->config.data_bits,MYREGSHIFT);
  		ctx->status = 0;
  		ctx->ioc_events &= ~RTSER_EVENT_ERRPEND;
  	}
@@ -347,9 +377,11 @@
  	if (testbits(config->config_mask, RTSER_SET_FIFO_DEPTH)) {
  		ctx->config.fifo_depth = config->fifo_depth & FIFO_MASK;
  		rt_16550_reg_out(mode, base, FCR,
-				 FCR_FIFO | FCR_RESET_RX | FCR_RESET_TX);
+				 FCR_FIFO | FCR_RESET_RX | FCR_RESET_TX,
+						 MYREGSHIFT);
  		rt_16550_reg_out(mode, base, FCR,
-				 FCR_FIFO | ctx->config.fifo_depth);
+				 FCR_FIFO | ctx->config.fifo_depth,
+						 MYREGSHIFT);
  	}

  	rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
@@ -405,7 +437,7 @@
  		else
  			/* disable modem status interrupt */
  			ctx->ier_status &= ~IER_MODEM;
-		rt_16550_reg_out(mode, base, IER, ctx->ier_status);
+		rt_16550_reg_out(mode, base, IER, ctx->ier_status,MYREGSHIFT);

  		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
  	}
@@ -425,7 +457,7 @@
  			    RTSER_MCR_DTR | RTSER_MCR_RTS | RTSER_MCR_OUT2;
  			break;
  		}
-		rt_16550_reg_out(mode, base, MCR, ctx->mcr_status);
+		rt_16550_reg_out(mode, base, MCR, ctx->mcr_status,MYREGSHIFT);

  		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
  	}
@@ -487,7 +519,7 @@
  	if (err) {
  		/* reset DTR and RTS */
  		rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx), ctx->base_addr,
-				 MCR, 0);
+				 MCR, 0,MYREGSHIFT);

  		rt_16550_cleanup_ctx(ctx);

@@ -499,7 +531,7 @@
  	/* enable interrupts */
  	ctx->ier_status = IER_RX;
  	rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx), ctx->base_addr, IER,
-			 IER_RX);
+			 IER_RX,MYREGSHIFT);

  	rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);

@@ -522,14 +554,16 @@
  	rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);

  	/* reset DTR and RTS */
-	rt_16550_reg_out(mode, base, MCR, 0);
+	rt_16550_reg_out(mode, base, MCR, 0,MYREGSHIFT);

  	/* mask all UART interrupts and clear pending ones. */
-	rt_16550_reg_out(mode, base, IER, 0);
-	rt_16550_reg_in(mode, base, IIR);
-	rt_16550_reg_in(mode, base, LSR);
-	rt_16550_reg_in(mode, base, RHR);
-	rt_16550_reg_in(mode, base, MSR);
+	rt_16550_reg_out(mode, base, IER, 0,MYREGSHIFT);
+	rt_16550_reg_in(mode, base, IIR,MYREGSHIFT);
+	rt_16550_reg_in(mode, base, LSR,MYREGSHIFT);
+       /* only read when RX FIFO not empty. */
+	if (testbits(rt_16550_reg_in(mode, base, LSR,MYREGSHIFT),RHR_EMPTY))
+		rt_16550_reg_in(mode, base, RHR,MYREGSHIFT);
+	
+	rt_16550_reg_in(mode, base, MSR,MYREGSHIFT);

  	in_history = ctx->in_history;
  	ctx->in_history = NULL;
@@ -638,9 +672,9 @@
  			struct rtser_status status_buf;

  			status_buf.line_status =
-			  rt_16550_reg_in(mode, base, LSR) | status;
+			  rt_16550_reg_in(mode, base, LSR,MYREGSHIFT) | status;
  			status_buf.modem_status =
-			    rt_16550_reg_in(mode, base, MSR);
+			    rt_16550_reg_in(mode, base, MSR,MYREGSHIFT);

  			err =
  			    rtdm_safe_copy_to_user(user_info, arg,
@@ -649,9 +683,9 @@
  							  rtser_status));
  		} else {
  			((struct rtser_status *)arg)->line_status =
-			  rt_16550_reg_in(mode, base, LSR) | status;
+			  rt_16550_reg_in(mode, base, LSR,MYREGSHIFT) | status;
  			((struct rtser_status *)arg)->modem_status =
-			    rt_16550_reg_in(mode, base, MSR);
+			    rt_16550_reg_in(mode, base, MSR,MYREGSHIFT);
  		}
  		break;
  	}
@@ -672,7 +706,7 @@

  		rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);
  		ctx->mcr_status = new_mcr;
-		rt_16550_reg_out(mode, base, MCR, new_mcr);
+		rt_16550_reg_out(mode, base, MCR, new_mcr,MYREGSHIFT);
  		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
  		break;
  	}
@@ -699,7 +733,7 @@
  				     RTSER_EVENT_ERRPEND)) {
  				ctx->ier_status |= IER_STAT;
  				rt_16550_reg_out(mode, base, IER,
-						 ctx->ier_status);
+						 ctx->ier_status,MYREGSHIFT);
  			}

  			rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
@@ -752,7 +786,7 @@
  		    (ctx->config.parity << 3) | (ctx->config.stop_bits << 2) |
  		    ctx->config.data_bits;

-		rt_16550_reg_out(mode, base, LCR, lcr);
+		rt_16550_reg_out(mode, base, LCR, lcr,MYREGSHIFT);

  		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
  		break;
@@ -768,7 +802,8 @@
  	ctx->in_npend = 0;
  	ctx->status = 0;
  	fcr |= FCR_FIFO | FCR_RESET_RX;
-	rt_16550_reg_in(mode, base, RHR);
+       /* only read when RX FIFO not empty. */
+	if (testbits(rt_16550_reg_in(mode, base, LSR,MYREGSHIFT),RHR_EMPTY))
+		rt_16550_reg_in(mode, base, RHR,MYREGSHIFT);
  	
  		if ((long)arg & RTDM_PURGE_TX_BUFFER) {
  			ctx->out_head = 0;
@@ -777,9 +812,10 @@
  			fcr |= FCR_FIFO | FCR_RESET_TX;
  		}
  		if (fcr) {
-			rt_16550_reg_out(mode, base, FCR, fcr);
+			rt_16550_reg_out(mode, base, FCR, fcr,MYREGSHIFT);
  			rt_16550_reg_out(mode, base, FCR,
-					 FCR_FIFO | ctx->config.fifo_depth);
+					 FCR_FIFO | ctx->config.fifo_depth,
+							 MYREGSHIFT);
  		}
  		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
  		break;
@@ -832,7 +868,7 @@
  			ctx->ier_status |= IER_STAT;
  			rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
  					 ctx->base_addr, IER,
-					 ctx->ier_status);
+					 ctx->ier_status,MYREGSHIFT);
  		}

  		if (ctx->status) {
@@ -1047,7 +1083,7 @@
  			ctx->ier_status |= IER_TX;
  			rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
  					 ctx->base_addr, IER,
-					 ctx->ier_status);
+					 ctx->ier_status,MYREGSHIFT);

  			rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
  			continue;
@@ -1120,9 +1156,15 @@
  	int mode;
  	int err;
  	int i;
+	void*  tmpAddr;
+	u8 rdtmp;
+
+

+	
  	rt_16550_pnp_init();
  	rt_16550_pci_init();
+	

  	for (i = 0; i < MAX_DEVICES; i++) {
  		if (!rt_16550_addr_param(i))
@@ -1143,25 +1185,33 @@
  		dev->device_id = i;

  		dev->proc_name = dev->device_name;
-
  		err = rt_16550_init_io(i, dev->device_name);
  		if (err)
+		{
  			goto kfree_out;
+		}

  		if (baud_base[i] == 0)
  			baud_base[i] = DEFAULT_BAUD_BASE;

  		if (tx_fifo[i] == 0)
  			tx_fifo[i] = DEFAULT_TX_FIFO;
+		
+		
+		   i,(void*)io[i],(void*)rt_16550_base_addr(i),(void*)mem[i]);

  		/* Mask all UART interrupts and clear pending ones. */
  		base = rt_16550_base_addr(i);
  		mode = rt_16550_io_mode(i);
-		rt_16550_reg_out(mode, base, IER, 0);
-		rt_16550_reg_in(mode, base, IIR);
-		rt_16550_reg_in(mode, base, LSR);
-		rt_16550_reg_in(mode, base, RHR);
-		rt_16550_reg_in(mode, base, MSR);
+		tmpAddr=(void *)base+(IER << 2);
+		rt_16550_reg_out(mode, base, IER, 0,MYREGSHIFT);
+		rt_16550_reg_in(mode, base, IIR,MYREGSHIFT);
+		rdtmp=rt_16550_reg_in(mode, base, LSR,MYREGSHIFT);
+		//reading empty is BAD on omap3630!
+		if(testbits(rdtmp,RHR_EMPTY))
+			rt_16550_reg_in(mode, base, RHR,MYREGSHIFT);
+		
+		rt_16550_reg_in(mode, base, MSR,MYREGSHIFT);

  		err = rtdm_dev_register(dev);

@@ -1169,6 +1219,8 @@
  			goto release_io_out;

  		device[i] = dev;
+		
+		
  	}

  	return 0;
Only in xenomai-2.6.0/ksrc/drivers/serial/: 16550A.c.debug
Only in xenomai-2.6.0/ksrc/drivers/serial/: 16550A.c.orig
diff -u //16550A_io.h xenomai-2.6.0/ksrc/drivers/serial//16550A_io.h
--- //16550A_io.h	2012-01-19 20:27:30.688571574 +0100
+++ xenomai-2.6.0/ksrc/drivers/serial//16550A_io.h
2012-01-19 20:23:55.347754673 +0100
@@ -20,6 +20,7 @@

  typedef enum { MODE_PIO, MODE_MMIO } io_mode_t;

+
  #if defined(CONFIG_XENO_DRIVERS_16550A_PIO) || \
      defined(CONFIG_XENO_DRIVERS_16550A_ANY)
  static unsigned long io[MAX_DEVICES];
@@ -158,25 +159,31 @@
  #endif

  static RT_16550_IO_INLINE u8
-rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off)
+rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off,int rshift)
  {
+	void __iomem * addr=(void*)base;
  	switch (io_mode) {
  	case MODE_PIO:
-		return inb(base + off);
+		return inb(base + (off<<rshift));
  	default: /* MODE_MMIO */
-		return readb((void *)base + off);
+		addr+=(off<<rshift);
+        //printk(KERN_INFO "reading: at %p \n",(void*)addr);
+		return ioread8(addr);
  	}
  }

  static RT_16550_IO_INLINE void
-rt_16550_reg_out(io_mode_t io_mode, unsigned long base, int off, u8 val)
+rt_16550_reg_out(io_mode_t io_mode, unsigned long base, int off, u8 val,
+ int rshift)
  {
+	void __iomem * addr=(void*)base;
  	switch (io_mode) {
  	case MODE_PIO:
-		outb(val, base + off);
+		outb(val, base + (off<<rshift));
  		break;
  	case MODE_MMIO:
-		writeb(val, (void *)base + off);
+		addr+=(off<<rshift);
+	//printk(KERN_INFO "writing: at %p, val %i \n",(void*)addr,val);
+		iowrite8(val,(void*)addr);
  		break;
  	}
  }
@@ -185,11 +192,12 @@
  {
  	switch (rt_16550_io_mode(dev_id)) {
  	case MODE_PIO:
-		if (!request_region(rt_16550_addr_param(dev_id), 8, name))
+	/*MANFRED QUESTION: Does PIO request_region also need reshift?*/
+	if (!request_region(rt_16550_addr_param(dev_id), 8<<regshift[dev_id],
+         name))
  			return -EBUSY;
  		break;
  	case MODE_MMIO:
-		mapped_io[dev_id] = ioremap(rt_16550_addr_param(dev_id), 8);
+		mapped_io[dev_id] = ioremap(rt_16550_addr_param(dev_id),
+                                           8<<regshift[dev_id]);
  		if (!mapped_io[dev_id])
  			return -EBUSY;
  		break;
@@ -201,7 +209,8 @@
  {
  	switch (rt_16550_io_mode(dev_id)) {
  	case MODE_PIO:
-		release_region(io[dev_id], 8);
+	/*MANFRED QUESTION: Does PIO request_region also need regshift?*/
+		release_region(io[dev_id], 8<<regshift[dev_id]);
  		break;
  	case MODE_MMIO:
  		iounmap(mapped_io[dev_id]);



On 1/15/12 8:35 PM, Wolfgang Grandegger wrote:
> On 01/13/2012 08:15 PM, Manfred wrote:
>> (In reply to Wolfgangs Respond)
>>
>> Thank you for the explanations.
>> So I managed to recompile the kernel module with a lot of "printk"
>>
>> commands. And I could track the problem to the following:
>> it fails in:[1]
>> int __init rt_16550_init(void)
>>
>> When calling these lines:
>> rt_16550_reg_out(mode, base, IER, 0);
>> DEBUGPRINT("after reg_out IER \n");
>> rt_16550_reg_in(mode, base, IIR);
>> DEBUGPRINT("after reg_in IIR \n");
>>
>> So it seems to fail the first time when it tries to call:
>> rt_16550_reg_in(mode, base, IIR);
>> where
>> mode=1
>> rt_16550_reg_in is defined in:
>> 16550A_io.h:161:
>> static RT_16550_IO_INLINE u8
>> rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off)
>> {
>>      switch (io_mode) {
>>      case MODE_PIO:
>>          return inb(base + off);
>>      default: /* MODE_MMIO */
>>          return readb((void *)base + off);
>>      }
>> }
>>
>> -->  where is MODE_PIO defined?: is it 1 or 0?
>> (could not find it in any .c or .h file)
>
> Well, it's in :
>
> http://www.rts.uni-hannover.de/xenomai/lxr/source/ksrc/drivers/serial/
> 16550A_io.h
>
> and depends on some Kconfig options. Also another prinkt can give you
> the required information.
>
>> So anyway, it either fails in inb(base+off)
>> or (more probably:) in read(void*)base+off
>
> Yes, most likely it's an unaligned access.
>
>> -->
>> Is this consistent with your assumption that we need a regshift?
>
> Yes. I was suggesting to put some printks in the Linux serial device
> setup code first to see how the registers are accessed.
>
>> If yes, which function calls need to be fixed?
>> -->
>> I tried to look in 8250.c [2]:
>> regshift seems to be mostly used when using map_8250_in_reg and
>> map_8250_out_reg:
>> offset = map_8250_in_reg(p, offset)<<  p->regshift;
>> offset = map_8250_in_reg(p, offset)<<  p->regshift;
>> but also elsewhere:
>> 2498 static unsigned int serial8250_port_size(struct uart_8250_port *pt)
>> 2499 {
>> 2500         if (pt->port.iotype == UPIO_AU)
>> 2501                 return 0x1000;
>> 2502 #ifdef CONFIG_ARCH_OMAP
>> 2503         if (is_omap_port(pt))
>> 2504                 return 0x16<<  pt->port.regshift;
>> 2505 #endif
>> 2506         return 8<<  pt->port.regshift;
>> 2507 }
>> or:
>> 2600 static void serial8250_release_rsa_resource(struct
uart_8250_port *up)
>> 2601 {
>> 2602         unsigned long offset = UART_RSA_BASE<<  up->port.regshift;
>> 2603         unsigned int size = 8<<  up->port.regshift;
>> 2604
>> 2605         switch (up->port.iotype) {
>> 2606         case UPIO_HUB6:
>> 2607         case UPIO_PORT:
>> 2608                 release_region(up->port.iobase + offset, size);
>> 2609                 break;
>> 2610         }
>> 2611 }
>
> This is the driver. The devices are setup and configured in
>
> http://lxr.linux.no/#linux+v3.2.1/arch/arm/mach-omap2/serial.c
>
> IIRC. Check what regshift is used for your hardware (by putting further
> printk's).
>
>> -->
>> So can I just change the function in 16550A.c like this?:
>> rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off, int
>> regshift)
>> {
>>       switch (io_mode) {
>>      case MODE_PIO:
>>          return inb(base + off);
>>      default: /* MODE_MMIO */
>>           /* ADD REGSHIFT for MMIO Mode: */
>>           unsigned long paddr=((void*)base+off)<<  regshift;
>>           return readb((void *)base + off);
>
> You need to shift just the *offset* at the beginning of the function:
>
> 	off<<= regshift;
>
> You also need to adjust the region for request_region() or ioremap().
>
>> }
>>
>> Thanks for the help.
>> Please note, this is really my first try on kernel modules and drivers,
>> So sorry, in case I got it all wrong.
>
> No problem, you are welcome.
>
> Wolfgang.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-19 17:09         ` Fabrice Gasnier
@ 2012-01-20 12:03           ` Manfred
  2012-01-20 14:41             ` Fabrice Gasnier
  2012-01-20 18:03           ` Wolfgang Grandegger
  1 sibling, 1 reply; 20+ messages in thread
From: Manfred @ 2012-01-20 12:03 UTC (permalink / raw)
  To: Fabrice Gasnier; +Cc: xenomai

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

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

[-- Attachment #2: 0001b-omap3andomap4-uart-xeno_16550A-updates.patch --]
[-- Type: text/plain, Size: 6376 bytes --]

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

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-20 12:03           ` Manfred
@ 2012-01-20 14:41             ` Fabrice Gasnier
  2012-01-20 15:58               ` Felipe Brandão Cavalcanti
  2012-01-22 19:04               ` Manfred
  0 siblings, 2 replies; 20+ messages in thread
From: Fabrice Gasnier @ 2012-01-20 14:41 UTC (permalink / raw)
  To: Manfred; +Cc: xenomai

Dear all, Manfred,

Please find interleaved answers/questions.

On 20/01/2012 13:03, Manfred wrote:
> 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.
you're welcome.
> 
> 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
It also cares about tx fifo full condition: in rt_16550_reg_out():
lsr = rt_16550_omap_raw_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);
}

> - 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?
I think you're right it adds latencies, but what can we do about this?
e.g. I've made some testing without such a handling: trying to write "lots of" bytes (I assume more than fifo size) freezes target. It has to be handled somehow. Maybe it's wrong to do this way?
Maybe it would be better to write up to fifo full and then return...
- an error ?
- or just the number of written bytes with no error?
This way responsibility would be let to the caller (writting to much bytes will cause a lantency in the end, no ?)
I'm not sure of expected behavior on other platforms such as x86 ?

> 
> 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)
I shall try these, but I own a PhyCARD-L that only has one serial port... Cannot run cross-link.
> 
> 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


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-20 14:41             ` Fabrice Gasnier
@ 2012-01-20 15:58               ` Felipe Brandão Cavalcanti
  2012-01-22 19:04               ` Manfred
  1 sibling, 0 replies; 20+ messages in thread
From: Felipe Brandão Cavalcanti @ 2012-01-20 15:58 UTC (permalink / raw)
  To: Fabrice Gasnier; +Cc: xenomai

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

Dear All,

Any chance you guys could make a Gumstix Overo image with Xenomai and the
RTDM drivers working? I was actually going to start working on this very
issue (RTDM drivers for the OMAP) next week, but you seem to have had a
head start on that.

Many thanks!
       -Felipe Brandão Cavalcanti
       LARA - Automation and Robotics Laboratory
       Department of Electrical Engineering
       UnB - University of Brasília, Brazil
       http://www.lara.unb.br/~fbcavalcanti/

On Fri, Jan 20, 2012 at 12:41 PM, Fabrice Gasnier <
fabrice.gasnier@domain.hid> wrote:

> Dear all, Manfred,
>
> Please find interleaved answers/questions.
>
> On 20/01/2012 13:03, Manfred wrote:
> > 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.
> you're welcome.
> >
> > 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
> It also cares about tx fifo full condition: in rt_16550_reg_out():
> lsr = rt_16550_omap_raw_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);
> }
>
> > - 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?
> I think you're right it adds latencies, but what can we do about this?
> e.g. I've made some testing without such a handling: trying to write "lots
> of" bytes (I assume more than fifo size) freezes target. It has to be
> handled somehow. Maybe it's wrong to do this way?
> Maybe it would be better to write up to fifo full and then return...
> - an error ?
> - or just the number of written bytes with no error?
> This way responsibility would be let to the caller (writting to much bytes
> will cause a lantency in the end, no ?)
> I'm not sure of expected behavior on other platforms such as x86 ?
>
> >
> > 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)
> I shall try these, but I own a PhyCARD-L that only has one serial port...
> Cannot run cross-link.
> >
> > 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
>
> _______________________________________________
> Xenomai-help mailing list
> Xenomai-help@domain.hid
> https://mail.gna.org/listinfo/xenomai-help
>

[-- Attachment #2: Type: text/html, Size: 6507 bytes --]

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-19 17:09         ` Fabrice Gasnier
  2012-01-20 12:03           ` Manfred
@ 2012-01-20 18:03           ` Wolfgang Grandegger
  2012-01-20 18:46             ` Gilles Chanteperdrix
  1 sibling, 1 reply; 20+ messages in thread
From: Wolfgang Grandegger @ 2012-01-20 18:03 UTC (permalink / raw)
  To: Fabrice Gasnier; +Cc: xenomai

Hi Fabrice and Manfred,

On 01/19/2012 06:09 PM, Fabrice Gasnier wrote:
> On 18/01/2012 17:32, Wolfgang Grandegger wrote:
>>> Further investigation indicates that when writing, tx interrupt is not asserted as expected (rt_16550_write):
>>>> /* unmask tx interrupt */
>>>> ctx->ier_status |= IER_TX;
>>>> rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
>>>> 		 ctx->base_addr, IER,
>>>> 		 ctx->ier_status,
>>>> 		 ctx->regshift);
>>>>
>>>> >From my understanding this should trigger an irq for data to be put in rt_16550_tx_interrupt().
>>>> It seems this is not always the case. Moreover, TX interrupt seem to be triggered by a new RX interrupt.
>> The TX interrupt will be enabled as long as there are chars to send,
>> IIRC. The isr the puts the chars into the FIFO and triggers the xfer.
> 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.
>>
>>>>
>>>> Would you have an explanation for such a behavior?
>>>> I'm not sure how to solve this.
>> Depending on the hardware/uart revision, you may need to take care of
>> 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.

It seems the 16550-compatible UARTs on the OMAP processor are special
and also buggy requiring more or less heavy workarounds, unfortunately.
I can't comment on that as I do not have experience with OMAP processors.

> You'll find attached a patch that works for me.
> Please advise. Maybe we can enhance it and push it?

To handle hardware-specific initialization I/O properly, I think we need
first a more flexible interface using callback functions. The existing
interface with

	base = ctx->base_addr;
	mode = rt_16550_io_mode_from_ctx(ctx);
	regshift = ctx->regshift;
	rt_16550_reg_in(mode, base, regshift, offset)",

#ifdef's and switch statements in the I/O functions is really horrible.
A more elegant solution would make integration of the OMAP specialities
much easier.

Wolfgang.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-20 18:03           ` Wolfgang Grandegger
@ 2012-01-20 18:46             ` Gilles Chanteperdrix
  2012-01-20 19:04               ` Wolfgang Grandegger
  0 siblings, 1 reply; 20+ messages in thread
From: Gilles Chanteperdrix @ 2012-01-20 18:46 UTC (permalink / raw)
  To: Wolfgang Grandegger; +Cc: xenomai

On 01/20/2012 07:03 PM, Wolfgang Grandegger wrote:
> Hi Fabrice and Manfred,
> 
> On 01/19/2012 06:09 PM, Fabrice Gasnier wrote:
>> On 18/01/2012 17:32, Wolfgang Grandegger wrote:
>>>> Further investigation indicates that when writing, tx interrupt is not asserted as expected (rt_16550_write):
>>>>> /* unmask tx interrupt */
>>>>> ctx->ier_status |= IER_TX;
>>>>> rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
>>>>> 		 ctx->base_addr, IER,
>>>>> 		 ctx->ier_status,
>>>>> 		 ctx->regshift);
>>>>>
>>>>> >From my understanding this should trigger an irq for data to be put in rt_16550_tx_interrupt().
>>>>> It seems this is not always the case. Moreover, TX interrupt seem to be triggered by a new RX interrupt.
>>> The TX interrupt will be enabled as long as there are chars to send,
>>> IIRC. The isr the puts the chars into the FIFO and triggers the xfer.
>> 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.
>>>
>>>>>
>>>>> Would you have an explanation for such a behavior?
>>>>> I'm not sure how to solve this.
>>> Depending on the hardware/uart revision, you may need to take care of
>>> 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.
> 
> It seems the 16550-compatible UARTs on the OMAP processor are special
> and also buggy requiring more or less heavy workarounds, unfortunately.
> I can't comment on that as I do not have experience with OMAP processors.
> 
>> You'll find attached a patch that works for me.
>> Please advise. Maybe we can enhance it and push it?
> 
> To handle hardware-specific initialization I/O properly, I think we need
> first a more flexible interface using callback functions. The existing
> interface with
> 
> 	base = ctx->base_addr;
> 	mode = rt_16550_io_mode_from_ctx(ctx);
> 	regshift = ctx->regshift;
> 	rt_16550_reg_in(mode, base, regshift, offset)",
> 
> #ifdef's and switch statements in the I/O functions is really horrible.
> A more elegant solution would make integration of the OMAP specialities
> much easier.

I will wait for Wolfgang's ack before merging anything, then.

-- 
                                                                Gilles.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-20 18:46             ` Gilles Chanteperdrix
@ 2012-01-20 19:04               ` Wolfgang Grandegger
  2012-01-26 10:20                 ` Fabrice Gasnier
  0 siblings, 1 reply; 20+ messages in thread
From: Wolfgang Grandegger @ 2012-01-20 19:04 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: xenomai

On 01/20/2012 07:46 PM, Gilles Chanteperdrix wrote:
> On 01/20/2012 07:03 PM, Wolfgang Grandegger wrote:
>> Hi Fabrice and Manfred,
>>
>> On 01/19/2012 06:09 PM, Fabrice Gasnier wrote:
>>> On 18/01/2012 17:32, Wolfgang Grandegger wrote:
>>>>> Further investigation indicates that when writing, tx interrupt is not asserted as expected (rt_16550_write):
>>>>>> /* unmask tx interrupt */
>>>>>> ctx->ier_status |= IER_TX;
>>>>>> rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
>>>>>> 		 ctx->base_addr, IER,
>>>>>> 		 ctx->ier_status,
>>>>>> 		 ctx->regshift);
>>>>>>
>>>>>> >From my understanding this should trigger an irq for data to be put in rt_16550_tx_interrupt().
>>>>>> It seems this is not always the case. Moreover, TX interrupt seem to be triggered by a new RX interrupt.
>>>> The TX interrupt will be enabled as long as there are chars to send,
>>>> IIRC. The isr the puts the chars into the FIFO and triggers the xfer.
>>> 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.
>>>>
>>>>>>
>>>>>> Would you have an explanation for such a behavior?
>>>>>> I'm not sure how to solve this.
>>>> Depending on the hardware/uart revision, you may need to take care of
>>>> 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.
>>
>> It seems the 16550-compatible UARTs on the OMAP processor are special
>> and also buggy requiring more or less heavy workarounds, unfortunately.
>> I can't comment on that as I do not have experience with OMAP processors.
>>
>>> You'll find attached a patch that works for me.
>>> Please advise. Maybe we can enhance it and push it?
>>
>> To handle hardware-specific initialization I/O properly, I think we need
>> first a more flexible interface using callback functions. The existing
>> interface with
>>
>> 	base = ctx->base_addr;
>> 	mode = rt_16550_io_mode_from_ctx(ctx);
>> 	regshift = ctx->regshift;
>> 	rt_16550_reg_in(mode, base, regshift, offset)",
>>
>> #ifdef's and switch statements in the I/O functions is really horrible.
>> A more elegant solution would make integration of the OMAP specialities
>> much easier.
> 
> I will wait for Wolfgang's ack before merging anything, then.

Well, I'm actually not the maintainer. Jan?

Wolfgang.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-20 14:41             ` Fabrice Gasnier
  2012-01-20 15:58               ` Felipe Brandão Cavalcanti
@ 2012-01-22 19:04               ` Manfred
  2012-02-23 19:00                 ` Felipe Brandão Cavalcanti
  1 sibling, 1 reply; 20+ messages in thread
From: Manfred @ 2012-01-22 19:04 UTC (permalink / raw)
  To: Fabrice Gasnier; +Cc: xenomai


On 1/20/12 3:41 PM, Fabrice Gasnier wrote:
> Dear all, Manfred,
>
> Please find interleaved answers/questions.
>
> On 20/01/2012 13:03, Manfred wrote:
>> 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.
> you're welcome.
>>
>> 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
> It also cares about tx fifo full condition: in rt_16550_reg_out():
> lsr = rt_16550_omap_raw_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);
> }
>


Ok, I could reproduce the tx fifo full condition (I could not find the 
precise errata, but it is indeed mentioned in the omap-serial.c )
Nevertheless, I would prefer any solution that avoids timeouts and keeps 
the if-statements to a minimum in these performance-critical parts.

For the tx_fifo full errata I would suggest the following:
(The idea is to read the current tx_fifo_level before writing, and make 
sure we don't fill it)
--------

static inline void rt_16550_tx_interrupt(struct rt_16550_context *ctx)
{
	int c;
	int count;
	unsigned long base = ctx->base_addr;
	unsigned char regshift = ctx->regshift;
	int mode = rt_16550_io_mode_from_ctx(ctx);

	unsigned char tx_fifo_level=0;
#if defined (CONFIG_ARCH_OMAP3) || \
defined (CONFIG_ARCH_OMAP4)
	/*Make sure we don't overrun the txfifo*/
      tx_fifo_level=rt_16550_reg_in(io_mode,base,rshift,TXFIFO_LVL_REG);
#endif

/*	if (uart->modem & MSR_CTS)*/
	{
		for (count = ctx->tx_fifo-tx_fifo_level;
		     (count > 0) && (ctx->out_npend > 0);
		     count--, ctx->out_npend--) {
			c = ctx->out_buf[ctx->out_head++];
			rt_16550_reg_out(mode, base, regshift, THR, c);
			ctx->out_head &= (OUT_BUFFER_SIZE - 1);
		}
	}
}
-------

I tested the code with long writes on my platform (250 bytes) (fifo is 
64) at 9600Baud (slow on purpose) with the periodic task at 10Hz 
(standard) and it seems to work.

I have however some more issues (which appear also with your original 
patch):
- when I try to push the cross-link.c example to the limit , by 
increasing the frequency of the periodic tasks to 500Hz (was 10Hz). I 
get corrupt data after some 1000 iterations. (The timestamp suddenly 
jumps from 70000 to a very high value). If I interrupt the code then and 
want to start it again, the machine freezes (If I first unload and 
reload the kernel module, the machine does not freeze). So my guess is, 
that the write function is being interrupted by a read-interrupt before 
finishing the write. But somehow this seems not to be catched by the 
corresponding error-handler (number of bytes written <size)

- Is there a debug-tool for xenomai to see where the code has been 
interrupted, or which interrupts have been handled recently. Or can I 
prevent the write-routine from being interrupted?

- Has anyone tried to push the cross-link example on a different 
platform to the limit, and seen similar effects?

- I would also like to enable parity bits on the serial link, but if I 
set the config_flags (for write and read device) like this:
.parity            = RTSER_ODD_PARITY,
cross-link hangs before the first read ... and freezes the machine..
Has anyone tried using Parity bits with xeno_16550A ? Do I have to 
change other flags to make it work?

Regards,
Manfred






^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-20 19:04               ` Wolfgang Grandegger
@ 2012-01-26 10:20                 ` Fabrice Gasnier
  0 siblings, 0 replies; 20+ messages in thread
From: Fabrice Gasnier @ 2012-01-26 10:20 UTC (permalink / raw)
  To: Wolfgang Grandegger; +Cc: xenomai

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

Hi all,
I've been busy trying to clarify few things discussed here.
Please find attached a re-worked patch and comments interleaved here after.
Thank you very much for your help!
Regards,

Fabrice

On 20/01/2012 20:04, Wolfgang Grandegger wrote:
> On 01/20/2012 07:46 PM, Gilles Chanteperdrix wrote:
>> On 01/20/2012 07:03 PM, Wolfgang Grandegger wrote:
>>> Hi Fabrice and Manfred,
>>>
>>> On 01/19/2012 06:09 PM, Fabrice Gasnier wrote:
>>>> On 18/01/2012 17:32, Wolfgang Grandegger wrote:
>>>>>> Further investigation indicates that when writing, tx interrupt is not asserted as expected (rt_16550_write):
>>>>>>> /* unmask tx interrupt */
>>>>>>> ctx->ier_status |= IER_TX;
>>>>>>> rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
>>>>>>> 		 ctx->base_addr, IER,
>>>>>>> 		 ctx->ier_status,
>>>>>>> 		 ctx->regshift);
>>>>>>>
>>>>>>> >From my understanding this should trigger an irq for data to be put in rt_16550_tx_interrupt().
>>>>>>> It seems this is not always the case. Moreover, TX interrupt seem to be triggered by a new RX interrupt.
>>>>> The TX interrupt will be enabled as long as there are chars to send,
>>>>> IIRC. The isr the puts the chars into the FIFO and triggers the xfer.
>>>> 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.
Disable sleep seems definitely required (at least on my omap target):
int rt_16550_open( ... ) {
...
	/* disable sleep mode */
	rt_16550_disable_sleep(ctx);
...
}
>>>>>
>>>>>>>
>>>>>>> Would you have an explanation for such a behavior?
>>>>>>> I'm not sure how to solve this.
>>>>> Depending on the hardware/uart revision, you may need to take care of
>>>>> 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).
I finally found out the cause was not as I thought it was.
I'm running a small test program that write data to serial and exits after closing the device using rt_dev_close.
I figured out that closing dev immediately after write makes the driver not to flush all data!
When closing the device, interrupts are disabled without waiting for fifo to empty.
I also made some testing on another (x86) platform to be sure: behavior is identical.
Next time I open the port, target freeze (omap only).
So, I added a small routine to wait for data being sent when closing:

int rt_16550_close(...) {
...
	/* wait for fifo tx to be empty */
	rt_16550_wait_tx_end(ctx);
...
}

>>>> It works when using errata handling.

Further analysis of both xeno_16550A and omap-serial driver lead me to believe there is no need to use errata handling to write to TX fifo:
from omap-serial http://lxr.linux.no/#linux+v3.2.1/arch/arm/mach-omap2/serial.c#L620
 624        status = __serial_read_reg(up, UART_LSR);
 625        while (!(status & UART_LSR_THRE)) {
 626                /* Wait up to 10ms for the character(s) to be sent. */
 627                if (--tmout == 0)
 628                        break;
 629                udelay(1);
 630                status = __serial_read_reg(up, UART_LSR);
 631        }

from 16550A.c:
static inline void rt_16550_tx_interrupt(struct rt_16550_context *ctx)
...
for (count = ctx->tx_fifo;
	 (count > 0) && (ctx->out_npend > 0);
	 count--, ctx->out_npend--) {
	c = ctx->out_buf[ctx->out_head++];
	rt_16550_reg_out(mode, base, THR, c);
	ctx->out_head &= (OUT_BUFFER_SIZE - 1);
}

THR is only written in rt_16550_tx_interrupt. It's only triggered when tx fifo is empty.
So, I think there is no need to use linux driver method.
Moreover, I believe this makes the driver to push data byte-per-byte, instead of using fifo.
I removed it from my fisrt patch.

However, I cannot test this on an omap that should be impacted by errata as my uart revision is 0x46 ( < 0x52 ).
All of this is ok on my side.

@Manfred: maybe you can help, make some more tests ?
>>>
>>> It seems the 16550-compatible UARTs on the OMAP processor are special
>>> and also buggy requiring more or less heavy workarounds, unfortunately.
>>> I can't comment on that as I do not have experience with OMAP processors.
>>>
>>>> You'll find attached a patch that works for me.
>>>> Please advise. Maybe we can enhance it and push it?
>>>
>>> To handle hardware-specific initialization I/O properly, I think we need
>>> first a more flexible interface using callback functions. The existing
>>> interface with
>>>
>>> 	base = ctx->base_addr;
>>> 	mode = rt_16550_io_mode_from_ctx(ctx);
>>> 	regshift = ctx->regshift;
>>> 	rt_16550_reg_in(mode, base, regshift, offset)",
I reworked my patch to follow this guideline:

struct rt_16550_context {
...
	u8 (*rt_16550_reg_in)(struct rt_16550_context *, int);
	void (*rt_16550_reg_out)(struct rt_16550_context *, int, u8);
...
}
#define rt_16550_serial_in(ctx, offset) \
			(ctx->rt_16550_reg_in(ctx, offset))
#define rt_16550_serial_out(ctx, offset, value) \
			(ctx->rt_16550_reg_out(ctx, offset, value))
This is very close to :
http://lxr.linux.no/#linux+v3.2.1/drivers/tty/serial/8250.c#L519

>>>
>>> #ifdef's and switch statements in the I/O functions is really horrible.
>>> A more elegant solution would make integration of the OMAP specialities
>>> much easier.
Removed from all routines in 16550.c but these are still required in 16550_io.h
>>
>> I will wait for Wolfgang's ack before merging anything, then.
> 
> Well, I'm actually not the maintainer. Jan?
> 
> Wolfgang.
> 
> 
> 

[-- Attachment #2: 0001-Add-xeno_16550A-omap-support.patch --]
[-- Type: text/x-patch, Size: 23038 bytes --]

>From bdb16585ee67e746c0f747dfb93a3d8193103594 Mon Sep 17 00:00:00 2001
From: Fabrice Gasnier <fabrice.gasnier@domain.hid>
Date: Thu, 26 Jan 2012 10:13:08 +0100
Subject: [PATCH] Add xeno_16550A omap support
 Add regshift module parameter.
 Add omap specific "fifo full" errata handling from linux-3.2 omap-serial
 Fix closing when tx fifo isn't empty
 Disable sleep mode on omap uart


Signed-off-by: Fabrice Gasnier <fabrice.gasnier@domain.hid>
---
 ksrc/drivers/serial/16550A.c    |  148 +++++++++++++++++---------------
 ksrc/drivers/serial/16550A_io.h |  184 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 253 insertions(+), 79 deletions(-)

diff --git a/ksrc/drivers/serial/16550A.c b/ksrc/drivers/serial/16550A.c
index 3672539..945929e 100644
--- a/ksrc/drivers/serial/16550A.c
+++ b/ksrc/drivers/serial/16550A.c
@@ -70,6 +70,23 @@
 #define LSR			5	/* Line Status Register */
 #define MSR			6	/* Modem Status Register */
 
+#if defined (CONFIG_ARCH_OMAP3) || \
+	defined (CONFIG_ARCH_OMAP4)
+#define OMAP_SCR	0x10	/* Supplementary control register */
+#define OMAP_MVR	0x14	/* Module Version Register */
+#define OMAP_SYSC	0x15	/* System configuration register */
+#define OMAP_WER	0x17	/* Wake-up enable register */
+#define REGION_MAX	OMAP_WER	/* end of io/memory region */
+
+#define LCR_CONF_MODE_A		LCR_DLAB	/* Configutation mode A */
+#define LCR_CONF_MODE_B		0xBF		/* Configutation mode B */
+#define EFR            		2			/* Enhanced feature register (when LCR_CONF_MODE_B) */
+#define EFR_ECB        		0x10 		/* Enhanced control bit */
+#define IERX_SLEEP     		0x10 		/* Enable sleep mode */
+#else
+#define REGION_MAX			MSR			/* end of io/memory region   */
+#endif
+
 struct rt_16550_context {
 	struct rtser_config config;	/* current device configuration */
 
@@ -80,6 +97,8 @@ struct rt_16550_context {
 #ifdef CONFIG_XENO_DRIVERS_16550A_ANY
 	int io_mode;			/* hardware IO-access mode */
 #endif
+	unsigned char regshift;		/* register shift */
+
 	int tx_fifo;			/* cached global tx_fifo[<device>] */
 
 	int in_head;			/* RX ring buffer, head pointer */
@@ -107,8 +126,16 @@ struct rt_16550_context {
 	int mcr_status;			/* MCR cache */
 	int status;			/* cache for LSR + soft-states */
 	int saved_errors;		/* error cache for RTIOC_GET_STATUS */
+
+	u8 (*rt_16550_reg_in)(struct rt_16550_context *, int);
+	void (*rt_16550_reg_out)(struct rt_16550_context *, int, u8);
 };
 
+#define rt_16550_serial_in(ctx, offset) \
+			(ctx->rt_16550_reg_in(ctx, offset))
+#define rt_16550_serial_out(ctx, offset, value) \
+			(ctx->rt_16550_reg_out(ctx, offset, value))
+
 static const struct rtser_config default_config = {
 	0xFFFF, RTSER_DEF_BAUD, RTSER_DEF_PARITY, RTSER_DEF_BITS,
 	RTSER_DEF_STOPB, RTSER_DEF_HAND, RTSER_DEF_FIFO_DEPTH, 0,
@@ -148,14 +175,12 @@ MODULE_AUTHOR("jan.kiszka@domain.hid");
 static inline int rt_16550_rx_interrupt(struct rt_16550_context *ctx,
 					uint64_t * timestamp)
 {
-	unsigned long base = ctx->base_addr;
-	int mode = rt_16550_io_mode_from_ctx(ctx);
 	int rbytes = 0;
 	int lsr = 0;
 	int c;
 
 	do {
-		c = rt_16550_reg_in(mode, base, RHR);	/* read input char */
+		c = rt_16550_serial_in(ctx, RHR);	/* read input char */
 
 		ctx->in_buf[ctx->in_tail] = c;
 		if (ctx->in_history)
@@ -169,7 +194,7 @@ static inline int rt_16550_rx_interrupt(struct rt_16550_context *ctx,
 
 		rbytes++;
 		lsr &= ~RTSER_LSR_DATA;
-		lsr |= (rt_16550_reg_in(mode, base, LSR) &
+		lsr |= (rt_16550_serial_in(ctx, LSR) &
 			(RTSER_LSR_DATA | RTSER_LSR_OVERRUN_ERR |
 			 RTSER_LSR_PARITY_ERR | RTSER_LSR_FRAMING_ERR |
 			 RTSER_LSR_BREAK_IND));
@@ -195,8 +220,6 @@ static inline void rt_16550_tx_interrupt(struct rt_16550_context *ctx)
 {
 	int c;
 	int count;
-	unsigned long base = ctx->base_addr;
-	int mode = rt_16550_io_mode_from_ctx(ctx);
 
 /*	if (uart->modem & MSR_CTS)*/
 	{
@@ -204,7 +227,7 @@ static inline void rt_16550_tx_interrupt(struct rt_16550_context *ctx)
 		     (count > 0) && (ctx->out_npend > 0);
 		     count--, ctx->out_npend--) {
 			c = ctx->out_buf[ctx->out_head++];
-			rt_16550_reg_out(mode, base, THR, c);
+			rt_16550_serial_out(ctx, THR, c);
 			ctx->out_head &= (OUT_BUFFER_SIZE - 1);
 		}
 	}
@@ -212,10 +235,7 @@ static inline void rt_16550_tx_interrupt(struct rt_16550_context *ctx)
 
 static inline void rt_16550_stat_interrupt(struct rt_16550_context *ctx)
 {
-	unsigned long base = ctx->base_addr;
-	int mode = rt_16550_io_mode_from_ctx(ctx);
-
-	ctx->status |= (rt_16550_reg_in(mode, base, LSR) &
+	ctx->status |= (rt_16550_serial_in(ctx, LSR) &
 			(RTSER_LSR_OVERRUN_ERR | RTSER_LSR_PARITY_ERR |
 			 RTSER_LSR_FRAMING_ERR | RTSER_LSR_BREAK_IND));
 }
@@ -223,8 +243,6 @@ static inline void rt_16550_stat_interrupt(struct rt_16550_context *ctx)
 static int rt_16550_interrupt(rtdm_irq_t * irq_context)
 {
 	struct rt_16550_context *ctx;
-	unsigned long base;
-	int mode;
 	int iir;
 	uint64_t timestamp = rtdm_clock_read();
 	int rbytes = 0;
@@ -233,13 +251,11 @@ static int rt_16550_interrupt(rtdm_irq_t * irq_context)
 	int ret = RTDM_IRQ_NONE;
 
 	ctx = rtdm_irq_get_arg(irq_context, struct rt_16550_context);
-	base = ctx->base_addr;
-	mode = rt_16550_io_mode_from_ctx(ctx);
 
 	rtdm_lock_get(&ctx->lock);
 
 	while (1) {
-		iir = rt_16550_reg_in(mode, base, IIR) & IIR_MASK;
+		iir = rt_16550_serial_in(ctx, IIR) & IIR_MASK;
 		if (testbits(iir, IIR_PIRQ))
 			break;
 
@@ -251,7 +267,7 @@ static int rt_16550_interrupt(rtdm_irq_t * irq_context)
 		else if (iir == IIR_TX)
 			rt_16550_tx_interrupt(ctx);
 		else if (iir == IIR_MODEM) {
-			modem = rt_16550_reg_in(mode, base, MSR);
+			modem = rt_16550_serial_in(ctx, MSR);
 			if (modem & (modem << 4))
 				events |= RTSER_EVENT_MODEMHI;
 			if ((modem ^ 0xF0) & (modem << 4))
@@ -292,7 +308,7 @@ static int rt_16550_interrupt(rtdm_irq_t * irq_context)
 	}
 
 	/* update interrupt mask */
-	rt_16550_reg_out(mode, base, IER, ctx->ier_status);
+	rt_16550_serial_out(ctx, IER, ctx->ier_status);
 
 	rtdm_lock_put(&ctx->lock);
 
@@ -304,8 +320,6 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 			       uint64_t **in_history_ptr)
 {
 	rtdm_lockctx_t lock_ctx;
-	unsigned long base = ctx->base_addr;
-	int mode = rt_16550_io_mode_from_ctx(ctx);
 	int err = 0;
 
 	/* make line configuration atomic and IRQ-safe */
@@ -320,9 +334,9 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 		ctx->config.baud_rate = config->baud_rate;
 		baud_div = (baud_base[dev_id] + (ctx->config.baud_rate>>1)) /
 			ctx->config.baud_rate;
-		rt_16550_reg_out(mode, base, LCR, LCR_DLAB);
-		rt_16550_reg_out(mode, base, DLL, baud_div & 0xff);
-		rt_16550_reg_out(mode, base, DLM, baud_div >> 8);
+		rt_16550_serial_out(ctx, LCR, LCR_DLAB);
+		rt_16550_serial_out(ctx, DLL, baud_div & 0xff);
+		rt_16550_serial_out(ctx, DLM, baud_div >> 8);
 	}
 
 	if (testbits(config->config_mask, RTSER_SET_PARITY))
@@ -336,7 +350,7 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 					  RTSER_SET_DATA_BITS |
 					  RTSER_SET_STOP_BITS |
 					  RTSER_SET_BAUD)) {
-		rt_16550_reg_out(mode, base, LCR,
+		rt_16550_serial_out(ctx, LCR,
 				 (ctx->config.parity << 3) |
 				 (ctx->config.stop_bits << 2) |
 				 ctx->config.data_bits);
@@ -346,9 +360,9 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 
 	if (testbits(config->config_mask, RTSER_SET_FIFO_DEPTH)) {
 		ctx->config.fifo_depth = config->fifo_depth & FIFO_MASK;
-		rt_16550_reg_out(mode, base, FCR,
+		rt_16550_serial_out(ctx, FCR,
 				 FCR_FIFO | FCR_RESET_RX | FCR_RESET_TX);
-		rt_16550_reg_out(mode, base, FCR,
+		rt_16550_serial_out(ctx, FCR,
 				 FCR_FIFO | ctx->config.fifo_depth);
 	}
 
@@ -405,7 +419,7 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 		else
 			/* disable modem status interrupt */
 			ctx->ier_status &= ~IER_MODEM;
-		rt_16550_reg_out(mode, base, IER, ctx->ier_status);
+		rt_16550_serial_out(ctx, IER, ctx->ier_status);
 
 		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
 	}
@@ -425,7 +439,7 @@ static int rt_16550_set_config(struct rt_16550_context *ctx,
 			    RTSER_MCR_DTR | RTSER_MCR_RTS | RTSER_MCR_OUT2;
 			break;
 		}
-		rt_16550_reg_out(mode, base, MCR, ctx->mcr_status);
+		rt_16550_serial_out(ctx, MCR, ctx->mcr_status);
 
 		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
 	}
@@ -486,20 +500,21 @@ int rt_16550_open(struct rtdm_dev_context *context,
 			       context->device->proc_name, ctx);
 	if (err) {
 		/* reset DTR and RTS */
-		rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx), ctx->base_addr,
-				 MCR, 0);
+		rt_16550_serial_out(ctx, MCR, 0);
 
 		rt_16550_cleanup_ctx(ctx);
 
 		return err;
 	}
 
+	/* disable sleep mode */
+	rt_16550_disable_sleep(ctx);
+
 	rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);
 
 	/* enable interrupts */
 	ctx->ier_status = IER_RX;
-	rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx), ctx->base_addr, IER,
-			 IER_RX);
+	rt_16550_serial_out(ctx, IER, IER_RX);
 
 	rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
 
@@ -510,26 +525,25 @@ int rt_16550_close(struct rtdm_dev_context *context,
 		   rtdm_user_info_t * user_info)
 {
 	struct rt_16550_context *ctx;
-	unsigned long base;
-	int mode;
 	uint64_t *in_history;
 	rtdm_lockctx_t lock_ctx;
 
 	ctx = (struct rt_16550_context *)context->dev_private;
-	base = ctx->base_addr;
-	mode = rt_16550_io_mode_from_ctx(ctx);
+
+	/* wait for fifo tx to be empty */
+	rt_16550_wait_tx_end(ctx);
 
 	rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);
 
 	/* reset DTR and RTS */
-	rt_16550_reg_out(mode, base, MCR, 0);
+	rt_16550_serial_out(ctx, MCR, 0);
 
 	/* mask all UART interrupts and clear pending ones. */
-	rt_16550_reg_out(mode, base, IER, 0);
-	rt_16550_reg_in(mode, base, IIR);
-	rt_16550_reg_in(mode, base, LSR);
-	rt_16550_reg_in(mode, base, RHR);
-	rt_16550_reg_in(mode, base, MSR);
+	rt_16550_serial_out(ctx, IER, 0);
+	rt_16550_serial_in(ctx, IIR);
+	rt_16550_serial_in(ctx, LSR);
+	rt_16550_serial_in(ctx, RHR);
+	rt_16550_serial_in(ctx, MSR);
 
 	in_history = ctx->in_history;
 	ctx->in_history = NULL;
@@ -552,12 +566,8 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 	rtdm_lockctx_t lock_ctx;
 	struct rt_16550_context *ctx;
 	int err = 0;
-	unsigned long base;
-	int mode;
 
 	ctx = (struct rt_16550_context *)context->dev_private;
-	base = ctx->base_addr;
-	mode = rt_16550_io_mode_from_ctx(ctx);
 
 	switch (request) {
 	case RTSER_RTIOC_GET_CONFIG:
@@ -638,9 +648,9 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 			struct rtser_status status_buf;
 
 			status_buf.line_status =
-			    rt_16550_reg_in(mode, base, LSR) | status;
+			    rt_16550_serial_in(ctx, LSR) | status;
 			status_buf.modem_status =
-			    rt_16550_reg_in(mode, base, MSR);
+			    rt_16550_serial_in(ctx, MSR);
 
 			err =
 			    rtdm_safe_copy_to_user(user_info, arg,
@@ -649,9 +659,9 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 							  rtser_status));
 		} else {
 			((struct rtser_status *)arg)->line_status =
-			    rt_16550_reg_in(mode, base, LSR) | status;
+			    rt_16550_serial_in(ctx, LSR) | status;
 			((struct rtser_status *)arg)->modem_status =
-			    rt_16550_reg_in(mode, base, MSR);
+			    rt_16550_serial_in(ctx, MSR);
 		}
 		break;
 	}
@@ -672,7 +682,7 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 
 		rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);
 		ctx->mcr_status = new_mcr;
-		rt_16550_reg_out(mode, base, MCR, new_mcr);
+		rt_16550_serial_out(ctx, MCR, new_mcr);
 		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
 		break;
 	}
@@ -698,7 +708,7 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 			if (testbits(ctx->config.event_mask,
 				     RTSER_EVENT_ERRPEND)) {
 				ctx->ier_status |= IER_STAT;
-				rt_16550_reg_out(mode, base, IER,
+				rt_16550_serial_out(ctx, IER,
 						 ctx->ier_status);
 			}
 
@@ -752,7 +762,7 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 		    (ctx->config.parity << 3) | (ctx->config.stop_bits << 2) |
 		    ctx->config.data_bits;
 
-		rt_16550_reg_out(mode, base, LCR, lcr);
+		rt_16550_serial_out(ctx, LCR, lcr);
 
 		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
 		break;
@@ -768,7 +778,7 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 			ctx->in_npend = 0;
 			ctx->status = 0;
 			fcr |= FCR_FIFO | FCR_RESET_RX;
-			rt_16550_reg_in(mode, base, RHR);
+			rt_16550_serial_in(ctx, RHR);
 		}
 		if ((long)arg & RTDM_PURGE_TX_BUFFER) {
 			ctx->out_head = 0;
@@ -777,8 +787,8 @@ int rt_16550_ioctl(struct rtdm_dev_context *context,
 			fcr |= FCR_FIFO | FCR_RESET_TX;
 		}
 		if (fcr) {
-			rt_16550_reg_out(mode, base, FCR, fcr);
-			rt_16550_reg_out(mode, base, FCR,
+			rt_16550_serial_out(ctx, FCR, fcr);
+			rt_16550_serial_out(ctx, FCR,
 					 FCR_FIFO | ctx->config.fifo_depth);
 		}
 		rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
@@ -830,8 +840,7 @@ ssize_t rt_16550_read(struct rtdm_dev_context * context,
 		/* switch on error interrupt - the user is ready to listen */
 		if (!testbits(ctx->ier_status, IER_STAT)) {
 			ctx->ier_status |= IER_STAT;
-			rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
-					 ctx->base_addr, IER,
+			rt_16550_serial_out(ctx, IER,
 					 ctx->ier_status);
 		}
 
@@ -1045,8 +1054,7 @@ ssize_t rt_16550_write(struct rtdm_dev_context * context,
 
 			/* unmask tx interrupt */
 			ctx->ier_status |= IER_TX;
-			rt_16550_reg_out(rt_16550_io_mode_from_ctx(ctx),
-					 ctx->base_addr, IER,
+			rt_16550_serial_out(ctx, IER,
 					 ctx->ier_status);
 
 			rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
@@ -1116,8 +1124,7 @@ void rt_16550_exit(void);
 int __init rt_16550_init(void)
 {
 	struct rtdm_device *dev;
-	unsigned long base;
-	int mode;
+	struct rt_16550_context ctx;
 	int err;
 	int i;
 
@@ -1155,13 +1162,16 @@ int __init rt_16550_init(void)
 			tx_fifo[i] = DEFAULT_TX_FIFO;
 
 		/* Mask all UART interrupts and clear pending ones. */
-		base = rt_16550_base_addr(i);
-		mode = rt_16550_io_mode(i);
-		rt_16550_reg_out(mode, base, IER, 0);
-		rt_16550_reg_in(mode, base, IIR);
-		rt_16550_reg_in(mode, base, LSR);
-		rt_16550_reg_in(mode, base, RHR);
-		rt_16550_reg_in(mode, base, MSR);
+		ctx.base_addr = rt_16550_base_addr(i);
+#ifdef CONFIG_XENO_DRIVERS_16550A_ANY
+		ctx.mode = rt_16550_io_mode(i);
+#endif
+		ctx.regshift = rt_16550_regshift(i);
+		rt_16550_reg_out(&ctx, IER, 0);
+		rt_16550_reg_in(&ctx, IIR);
+		rt_16550_reg_in(&ctx, LSR);
+		rt_16550_reg_in(&ctx, RHR);
+		rt_16550_reg_in(&ctx, MSR);
 
 		err = rtdm_dev_register(dev);
 
diff --git a/ksrc/drivers/serial/16550A_io.h b/ksrc/drivers/serial/16550A_io.h
index 92d21a5..ff55f46 100644
--- a/ksrc/drivers/serial/16550A_io.h
+++ b/ksrc/drivers/serial/16550A_io.h
@@ -31,15 +31,34 @@ MODULE_PARM_DESC(io, "I/O port addresses of the serial devices");
     defined(CONFIG_XENO_DRIVERS_16550A_ANY)
 static unsigned long mem[MAX_DEVICES];
 static void *mapped_io[MAX_DEVICES];
+static unsigned char regshift[MAX_DEVICES];
 compat_module_param_array(mem, ulong, MAX_DEVICES, 0400);
+compat_module_param_array(regshift, byte, MAX_DEVICES, 0400);
 MODULE_PARM_DESC(mem, "I/O memory addresses of the serial devices");
+MODULE_PARM_DESC(regshift, "register shift (ex: on some omap, use regshift=2)");
 #endif /* CONFIG_XENO_DRIVERS_16550A_MMIO || CONFIG_XENO_DRIVERS_16550A_ANY */
 
+#if defined (CONFIG_ARCH_OMAP3) || \
+	defined (CONFIG_ARCH_OMAP4)
+#define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV     0x52
+#define UART_ERRATA_FIFO_FULL_ABORT     		(0x1 << 0)
+#endif
+
 #ifdef CONFIG_XENO_DRIVERS_16550A_PIO
 
 #define RT_16550_IO_INLINE inline
 
 extern void *mapped_io[]; /* dummy */
+static unsigned char regshift[]; /* dummy */
+
+/* prototypes */
+static RT_16550_IO_INLINE int
+rt_16550_handle_errata(struct rt_16550_context *ctx);
+static RT_16550_IO_INLINE u8
+rt_16550_reg_in(struct rt_16550_context *ctx, int off);
+static RT_16550_IO_INLINE void
+rt_16550_reg_out(struct rt_16550_context *ctx, int off, u8 val);
+
 
 static inline unsigned long rt_16550_addr_param(int dev_id)
 {
@@ -61,6 +80,11 @@ static inline io_mode_t rt_16550_io_mode(int dev_id)
 	return MODE_PIO;
 }
 
+static inline unsigned char rt_16550_regshift(int dev_id)
+{
+	return 0;
+}
+
 static inline io_mode_t
 rt_16550_io_mode_from_ctx(struct rt_16550_context *ctx)
 {
@@ -71,6 +95,9 @@ static inline void
 rt_16550_init_io_ctx(int dev_id, struct rt_16550_context *ctx)
 {
 	ctx->base_addr = io[dev_id];
+	ctx->rt_16550_reg_in = rt_16550_reg_in;
+	ctx->rt_16550_reg_out = rt_16550_reg_out;
+	rt_16550_handle_errata(ctx);
 }
 
 #elif defined(CONFIG_XENO_DRIVERS_16550A_MMIO)
@@ -79,6 +106,14 @@ rt_16550_init_io_ctx(int dev_id, struct rt_16550_context *ctx)
 
 extern unsigned long io[]; /* dummy */
 
+/* prototypes */
+static RT_16550_IO_INLINE int
+rt_16550_handle_errata(struct rt_16550_context *ctx);
+static RT_16550_IO_INLINE u8
+rt_16550_reg_in(struct rt_16550_context *ctx, int off);
+static RT_16550_IO_INLINE void
+rt_16550_reg_out(struct rt_16550_context *ctx, int off, u8 val);
+
 static inline unsigned long rt_16550_addr_param(int dev_id)
 {
 	return mem[dev_id];
@@ -99,6 +134,11 @@ static inline io_mode_t rt_16550_io_mode(int dev_id)
 	return MODE_MMIO;
 }
 
+static inline unsigned char rt_16550_regshift(int dev_id)
+{
+	return (unsigned char)regshift[dev_id];
+}
+
 static inline io_mode_t
 rt_16550_io_mode_from_ctx(struct rt_16550_context *ctx)
 {
@@ -109,12 +149,24 @@ static inline void
 rt_16550_init_io_ctx(int dev_id, struct rt_16550_context *ctx)
 {
 	ctx->base_addr = (unsigned long)mapped_io[dev_id];
+	ctx->regshift = (unsigned char)regshift[dev_id];
+	ctx->rt_16550_reg_in = rt_16550_reg_in;
+	ctx->rt_16550_reg_out = rt_16550_reg_out;
+	rt_16550_handle_errata(ctx);
 }
 
 #elif defined(CONFIG_XENO_DRIVERS_16550A_ANY)
 
 #define RT_16550_IO_INLINE /* uninline */
 
+/* prototypes */
+static RT_16550_IO_INLINE int
+rt_16550_handle_errata(struct rt_16550_context *ctx);
+static RT_16550_IO_INLINE u8
+rt_16550_reg_in(struct rt_16550_context *ctx, int off);
+static RT_16550_IO_INLINE void
+rt_16550_reg_out(struct rt_16550_context *ctx, int off, u8 val);
+
 static inline unsigned long rt_16550_addr_param(int dev_id)
 {
 	return (io[dev_id]) ? io[dev_id] : mem[dev_id];
@@ -135,6 +187,11 @@ static inline io_mode_t rt_16550_io_mode(int dev_id)
 	return (io[dev_id]) ? MODE_PIO : MODE_MMIO;
 }
 
+static inline unsigned char rt_16550_regshift(int dev_id)
+{
+	return (io[dev_id]) ? 0 : (unsigned char)regshift[dev_id];
+}
+
 static inline io_mode_t
 rt_16550_io_mode_from_ctx(struct rt_16550_context *ctx)
 {
@@ -151,6 +208,11 @@ rt_16550_init_io_ctx(int dev_id, struct rt_16550_context *ctx)
 		ctx->base_addr = (unsigned long)mapped_io[dev_id];
 		ctx->io_mode   = MODE_MMIO;
 	}
+	ctx->regshift = (unsigned char)regshift[dev_id];
+	ctx->rt_16550_reg_in = rt_16550_reg_in;
+	ctx->rt_16550_reg_out = rt_16550_reg_out;
+	/* handle errata */
+	rt_16550_handle_errata (ctx);
 }
 
 #else
@@ -158,25 +220,27 @@ rt_16550_init_io_ctx(int dev_id, struct rt_16550_context *ctx)
 #endif
 
 static RT_16550_IO_INLINE u8
-rt_16550_reg_in(io_mode_t io_mode, unsigned long base, int off)
+rt_16550_reg_in(struct rt_16550_context *ctx, int off)
 {
-	switch (io_mode) {
+	off <<= ctx->regshift;
+	switch (rt_16550_io_mode_from_ctx(ctx)) {
 	case MODE_PIO:
-		return inb(base + off);
+		return inb(ctx->base_addr + off);
 	default: /* MODE_MMIO */
-		return readb((void *)base + off);
+		return readb((void *)ctx->base_addr + off);
 	}
 }
 
 static RT_16550_IO_INLINE void
-rt_16550_reg_out(io_mode_t io_mode, unsigned long base, int off, u8 val)
+rt_16550_reg_out(struct rt_16550_context *ctx, int off, u8 val)
 {
-	switch (io_mode) {
+	off <<= ctx->regshift;		/* regshift */
+	switch (rt_16550_io_mode_from_ctx(ctx)) {
 	case MODE_PIO:
-		outb(val, base + off);
+		outb(val, ctx->base_addr + off);
 		break;
 	case MODE_MMIO:
-		writeb(val, (void *)base + off);
+		writeb(val, (void *)ctx->base_addr + off);
 		break;
 	}
 }
@@ -185,11 +249,11 @@ static int rt_16550_init_io(int dev_id, char* name)
 {
 	switch (rt_16550_io_mode(dev_id)) {
 	case MODE_PIO:
-		if (!request_region(rt_16550_addr_param(dev_id), 8, name))
+		if (!request_region(rt_16550_addr_param(dev_id), REGION_MAX, name))
 			return -EBUSY;
 		break;
 	case MODE_MMIO:
-		mapped_io[dev_id] = ioremap(rt_16550_addr_param(dev_id), 8);
+		mapped_io[dev_id] = ioremap(rt_16550_addr_param(dev_id), REGION_MAX << regshift[dev_id]);
 		if (!mapped_io[dev_id])
 			return -EBUSY;
 		break;
@@ -208,3 +272,103 @@ static void rt_16550_release_io(int dev_id)
 		break;
 	}
 }
+
+static RT_16550_IO_INLINE void
+rt_16550_wait_tx_end(struct rt_16550_context *ctx)
+{
+	unsigned char lsr;
+	unsigned char nbits;
+	unsigned int tmout;
+
+	nbits = 5 + ctx->config.data_bits; // 5..8 data bits
+	nbits += 1 + ctx->config.stop_bits + 3; // 1..2 stop bits
+	nbits += 2; // start + parity;
+	nbits += 2; // overhead (round up, so tmout > tx duration);
+
+	tmout = (nbits * ctx->out_npend * 1000000) / ctx->config.baud_rate;
+
+	lsr = rt_16550_reg_in(ctx, LSR);
+	while (ctx->out_npend) {
+		/* Wait for the character(s) to be sent. */
+		if(--tmout == 0)
+			break;
+		rtdm_task_busy_sleep(1000);
+		lsr = rt_16550_reg_in(ctx, LSR);
+	}
+	return;
+}
+
+#if defined (CONFIG_ARCH_OMAP3) || \
+	defined (CONFIG_ARCH_OMAP4)
+
+static RT_16550_IO_INLINE u8
+rt_16550_omapsafe_reg_in(struct rt_16550_context *ctx, int off)
+{
+	if (RHR == off) {
+		unsigned char lsr;
+		lsr = rt_16550_reg_in(ctx, LSR);
+		if (!(lsr & RTSER_LSR_DATA)) /* Receiver data ready */
+			return 0; /* FIXME: -EPERM should be returned as error */
+	}
+	return rt_16550_reg_in(ctx, off);
+}
+
+static RT_16550_IO_INLINE void
+rt_16550_disable_sleep(struct rt_16550_context *ctx)
+{
+	unsigned char lcr, efr, ier;
+
+	ier = rt_16550_reg_in(ctx, IER);
+	if (ier & IERX_SLEEP)
+	{
+		lcr = rt_16550_reg_in(ctx, LCR);
+		rt_16550_reg_out(ctx, LCR, LCR_CONF_MODE_B);
+		efr = rt_16550_reg_in(ctx, EFR);
+		rt_16550_reg_out(ctx, EFR, EFR_ECB);
+		rt_16550_reg_out(ctx, LCR, 0x0); /* Operational mode */
+
+		ier = rt_16550_reg_in(ctx, IER);
+		ier &= ~IERX_SLEEP;	/* disable sleep */
+
+		rt_16550_reg_out(ctx, IER, ier);
+		rt_16550_reg_out(ctx, LCR, LCR_CONF_MODE_B);
+		rt_16550_reg_out(ctx, EFR, efr);
+		rt_16550_reg_out(ctx, LCR, lcr);
+	}
+}
+
+static RT_16550_IO_INLINE int
+rt_16550_handle_errata(struct rt_16550_context *ctx)
+{
+	int errata = 0, rev;
+	/*
+	 * omap44xx, ti816x: Never read empty UART fifo
+	 * omap3xxx: Never read empty UART fifo on UARTs
+	 * with IP rev >=0x52
+	 */
+	if (cpu_is_omap44xx() /* FIXME: || cpu_is_ti816x() */)
+		errata |= UART_ERRATA_FIFO_FULL_ABORT;
+	else if ((rev = rt_16550_reg_in(ctx, OMAP_MVR))
+			>= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV)
+		errata |= UART_ERRATA_FIFO_FULL_ABORT;
+
+	if (errata)
+		ctx->rt_16550_reg_in = rt_16550_omapsafe_reg_in;
+
+	return errata;
+}
+#else
+
+static RT_16550_IO_INLINE void
+rt_16550_disable_sleep(struct rt_16550_context *ctx)
+{
+	return;
+}
+
+static RT_16550_IO_INLINE int
+rt_16550_handle_errata(struct rt_16550_context *ctx)
+{
+	return 0;
+}
+
+#endif //CONFIG_ARCH_OMAP3/4
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod
  2012-01-22 19:04               ` Manfred
@ 2012-02-23 19:00                 ` Felipe Brandão Cavalcanti
  0 siblings, 0 replies; 20+ messages in thread
From: Felipe Brandão Cavalcanti @ 2012-02-23 19:00 UTC (permalink / raw)
  To: Manfred; +Cc: xenomai

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

Dear all,

On Sun, Jan 22, 2012 at 5:04 PM, Manfred <manfred@domain.hid> wrote:

>
> On 1/20/12 3:41 PM, Fabrice Gasnier wrote:
>
>> Dear all, Manfred,
>>
>> Please find interleaved answers/questions.
>>
>> On 20/01/2012 13:03, Manfred wrote:
>>
>>> 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.
>>>
>> you're welcome.
>>
>>>
>>>
With some help from Manfred, I also got cross-link to run on my OMAP3530
(latest patch from Fabrice, Jan. 26). Running Xenomai 2.6.0 on a 2.6.38
kernel in a Gumstix Overo Air and Water boards.


>  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
>
>> It also cares about tx fifo full condition: in rt_16550_reg_out():
>> lsr = rt_16550_omap_raw_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);
>> }
>>
>>
>
> Ok, I could reproduce the tx fifo full condition (I could not find the
> precise errata, but it is indeed mentioned in the omap-serial.c )
> Nevertheless, I would prefer any solution that avoids timeouts and keeps
> the if-statements to a minimum in these performance-critical parts.
>
> For the tx_fifo full errata I would suggest the following:
> (The idea is to read the current tx_fifo_level before writing, and make
> sure we don't fill it)
> --------
>
> static inline void rt_16550_tx_interrupt(struct rt_16550_context *ctx)
> {
>        int c;
>        int count;
>
>        unsigned long base = ctx->base_addr;
>        unsigned char regshift = ctx->regshift;
>        int mode = rt_16550_io_mode_from_ctx(ctx)**;
>
>        unsigned char tx_fifo_level=0;
> #if defined (CONFIG_ARCH_OMAP3) || \
> defined (CONFIG_ARCH_OMAP4)
>        /*Make sure we don't overrun the txfifo*/
>     tx_fifo_level=rt_16550_reg_in(**io_mode,base,rshift,TXFIFO_**LVL_REG);
> #endif
>
> /*      if (uart->modem & MSR_CTS)*/
>        {
>                for (count = ctx->tx_fifo-tx_fifo_level;
>
>                     (count > 0) && (ctx->out_npend > 0);
>                     count--, ctx->out_npend--) {
>                        c = ctx->out_buf[ctx->out_head++];
>                        rt_16550_reg_out(mode, base, regshift, THR, c);
>
>                        ctx->out_head &= (OUT_BUFFER_SIZE - 1);
>                }
>        }
> }
> -------
>
> I tested the code with long writes on my platform (250 bytes) (fifo is 64)
> at 9600Baud (slow on purpose) with the periodic task at 10Hz (standard) and
> it seems to work.


Works well here as well, but mine crashed after 9500 or so iterations. No
abnormal behavior before the crash.


>

I have however some more issues (which appear also with your original
> patch):
> - when I try to push the cross-link.c example to the limit , by increasing
> the frequency of the periodic tasks to 500Hz (was 10Hz). I get corrupt data
> after some 1000 iterations. (The timestamp suddenly jumps from 70000 to a
> very high value). If I interrupt the code then and want to start it again,
> the machine freezes (If I first unload and reload the kernel module, the
> machine does not freeze). So my guess is, that the write function is being
> interrupted by a read-interrupt before finishing the write. But somehow
> this seems not to be catched by the corresponding error-handler (number of
> bytes written <size)
>

I have the exact same behavior on my setup, even with the new patch. Tested
at 1kHz, 115200 baud.


>
> - Is there a debug-tool for xenomai to see where the code has been
> interrupted, or which interrupts have been handled recently. Or can I
> prevent the write-routine from being interrupted?
>
> - Has anyone tried to push the cross-link example on a different platform
> to the limit, and seen similar effects?
>
> - I would also like to enable parity bits on the serial link, but if I set
> the config_flags (for write and read device) like this:
> .parity            = RTSER_ODD_PARITY,
> cross-link hangs before the first read ... and freezes the machine..
> Has anyone tried using Parity bits with xeno_16550A ? Do I have to change
> other flags to make it work?
>
> Regards,
> Manfred
>
>
Hope this can help we figure out the issue! I can try to run more tests if
they are needed.

Many thanks,

       -Felipe Brandão Cavalcanti
       LARA - Automation and Robotics Laboratory
       Department of Electrical Engineering
       UnB - University of Brasília, Brazil
       http://www.lara.unb.br/~fbcavalcanti/


>
>
>
>
> ______________________________**_________________
> Xenomai-help mailing list
> Xenomai-help@domain.hid
> https://mail.gna.org/listinfo/**xenomai-help<https://mail.gna.org/listinfo/xenomai-help>
>

[-- Attachment #2: Type: text/html, Size: 7591 bytes --]

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2012-02-23 19:00 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-12 17:53 [Xenomai-help] Omap3630, rtserial, xeno_16550A: crash on insmod Manfred
2012-01-12 18:44 ` Gilles Chanteperdrix
2012-01-12 19:36   ` Manfred
2012-01-12 19:53     ` Gilles Chanteperdrix
2012-01-12 18:52 ` Wolfgang Grandegger
     [not found] <4F1080E8.6020408@domain.hid>
2012-01-13 19:15 ` Manfred
2012-01-15 19:35   ` Wolfgang Grandegger
2012-01-18 16:15     ` Fabrice Gasnier
2012-01-18 16:32       ` Wolfgang Grandegger
2012-01-19 17:09         ` Fabrice Gasnier
2012-01-20 12:03           ` Manfred
2012-01-20 14:41             ` Fabrice Gasnier
2012-01-20 15:58               ` Felipe Brandão Cavalcanti
2012-01-22 19:04               ` Manfred
2012-02-23 19:00                 ` Felipe Brandão Cavalcanti
2012-01-20 18:03           ` Wolfgang Grandegger
2012-01-20 18:46             ` Gilles Chanteperdrix
2012-01-20 19:04               ` Wolfgang Grandegger
2012-01-26 10:20                 ` Fabrice Gasnier
2012-01-19 19:43     ` Manfred

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.