All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai] RTDM driver init: interrupts and context objects
@ 2017-02-24  0:27 andrija
  2017-02-24  9:03 ` Philippe Gerum
  0 siblings, 1 reply; 7+ messages in thread
From: andrija @ 2017-02-24  0:27 UTC (permalink / raw)
  To: xenomai

Hi,

I am using Xenomai 2.6.3 and I'm porting a Linux driver for an Acromag 
PCI DAQ board to RTDM.

Since RTDM in Xenomai 2.6.3 does not support minor device numbers, and 
there are possibly multiple PCI boards which must be accessed by this 
driver, I am following the example given for the 16550 UART driver in 
the Xenomai 2.6.3 source repository. There, we have a rtdm_device 
template with a blank name and inside the init_module() function the 
driver searches for multiple devices, and then assigns them names and 
registers each of them separately (i.e. rtserial0, rtserial1, rtserial2, 
etc.) so that each can be accessed as a separate device via the RTDM 
device table. This driver maintains a static array of rtdm_device, 
keeping there an instance of each detected device. So far so good. I am 
following the same approach in my driver.

However, I see some differences with which I am stuck.

The driver I am porting to RTDM scans for PCI devices in the 
init_module() method, and then, for each device found, performs some 
set-up stuff including - this is the most important thing - setting up 
an IRQ line.

The RTDM UART driver I am using as an example does not do this - it 
performs the IRQ line request (via rtdm_irq_request) in the open() 
method, NOT in the init_module() method. Is there any particular reason 
for this? Would it be incorrect to call rtdm_irq_request for each device 
in init_module() instead of in open(...)?

In order to call rtdm_irq_request, I require the irq handle, which is a 
field of the driver-specific context structure (e.g. in the UART driver 
case, rt_16550_context). I also have such a struct which stores some 
information about my device. Notwithstanding the IRQ setup, some of the 
information I would like to store in my context struct is arrived at 
during the operations in init_module(). However, I cannot see how to 
pass a context struct which I would create in init_module() properly 
when registering a device...? So far, it seems that any data that I 
obtain during init_module() I would have to save in e.g. static arrays, 
and then copy that into the context struct in open(...) where I can 
access the context struct for that particular device. Or do I have 
something wrong?

Any help is greatly appreciated!

Thanks,

Andrija Stupar
Univ. of Toronto


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

* Re: [Xenomai] RTDM driver init: interrupts and context objects
  2017-02-24  0:27 [Xenomai] RTDM driver init: interrupts and context objects andrija
@ 2017-02-24  9:03 ` Philippe Gerum
  2017-03-03  4:10   ` andrija
  0 siblings, 1 reply; 7+ messages in thread
From: Philippe Gerum @ 2017-02-24  9:03 UTC (permalink / raw)
  To: andrija, xenomai

On 02/24/2017 01:27 AM, andrija@stupar.com wrote:
> Hi,
> 
> I am using Xenomai 2.6.3 and I'm porting a Linux driver for an Acromag
> PCI DAQ board to RTDM.
> 
> Since RTDM in Xenomai 2.6.3 does not support minor device numbers, and
> there are possibly multiple PCI boards which must be accessed by this
> driver, I am following the example given for the 16550 UART driver in
> the Xenomai 2.6.3 source repository. There, we have a rtdm_device
> template with a blank name and inside the init_module() function the
> driver searches for multiple devices, and then assigns them names and
> registers each of them separately (i.e. rtserial0, rtserial1, rtserial2,
> etc.) so that each can be accessed as a separate device via the RTDM
> device table. This driver maintains a static array of rtdm_device,
> keeping there an instance of each detected device. So far so good. I am
> following the same approach in my driver.
> 
> However, I see some differences with which I am stuck.
> 
> The driver I am porting to RTDM scans for PCI devices in the
> init_module() method, and then, for each device found, performs some
> set-up stuff including - this is the most important thing - setting up
> an IRQ line.
> 
> The RTDM UART driver I am using as an example does not do this - it
> performs the IRQ line request (via rtdm_irq_request) in the open()
> method, NOT in the init_module() method. Is there any particular reason
> for this? Would it be incorrect to call rtdm_irq_request for each device
> in init_module() instead of in open(...)?
> 

No issue with that. Any call site from a regular kernel context (i.e.
not Xenomai's primary/rt mode) will do.

> In order to call rtdm_irq_request, I require the irq handle, which is a
> field of the driver-specific context structure (e.g. in the UART driver
> case, rt_16550_context). I also have such a struct which stores some
> information about my device. Notwithstanding the IRQ setup, some of the
> information I would like to store in my context struct is arrived at
> during the operations in init_module(). However, I cannot see how to
> pass a context struct which I would create in init_module() properly
> when registering a device...? So far, it seems that any data that I
> obtain during init_module() I would have to save in e.g. static arrays,
> and then copy that into the context struct in open(...) where I can
> access the context struct for that particular device. Or do I have
> something wrong?
> 

A context in the usual sense applies to a particular _connection_ to a
device, i.e. per-fd, not to the device itself. In that sense, the open()
handler setting up a connection may refer to some global data for
retrieving the setup information about the particular device instance
the connection refers to. Since init_module() only knows about device
instances, you need some proxy data structure to expose the device
information to the open() handler.

-- 
Philippe.


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

* Re: [Xenomai] RTDM driver init: interrupts and context objects
  2017-02-24  9:03 ` Philippe Gerum
@ 2017-03-03  4:10   ` andrija
  2017-03-18 16:28     ` Andrija Stupar
  0 siblings, 1 reply; 7+ messages in thread
From: andrija @ 2017-03-03  4:10 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai

Hi Philippe,

Thank you very much for your earlier response. I have figured that part 
of the driver out and opening and requesting an interrupt line works 
well. Also, upon an interrupt, an interrupt service routine is executed 
as expected. However I have one remaining problem I hope you could help 
me out with. For interrupt-driven A/D conversion, the hardware I am 
using works like this: 1) I write to a register to initiate 
interrupt-driven A/D conversion 2) the write call then goes to sleep 
until data is ready 3) an interrupt handler awakens the write call 4) 
the write call returns and 5) the code which made the write call now 
knows that it should read data from an input register.

In the original driver, the code doing steps 1), 2) and 4) looks like 
this:

wqc = 0;       /* indicate waiting */
writew( (int)ldata, (void *)(*adata) );
wait_event_interruptible(ain_queue, wqc);
wqc = 2;       /* indicate complete */
.... return (...) ;

Since interrupts in RTDM work slightly differently and there is no wait 
queue in the RTDM/Xenomai version I am using, I ported the above code to 
RTDM like this:

writew( (int)ldata, (void *)(*adata) );
if (!my_context->data_flag) {
	 my_context->wait_flag = TRUE; /* indicate waiting */
          if (rtdm_event_wait(&my_context->apc8620_wait)) { /* wait */
                        my_context->wait_flag = FALSE;
                        return ( -ERESTARTSYS );
          }
}
/* indicate complete */
my_context->data_flag = FALSE;
my_context->wait_flag = FALSE;
.... return (...) ;

In the original driver, step 3) is the in the interrupt handler function 
and looks like this:

if( wqc == 0)        /* waiting for a blocked start convert AND an 
interrupt from the input board */
{
      wqc = 1;               /* when received, change the condition to 
true... */
       wake_up_interruptible(&ain_queue);	 /* ... and wake the blocked 
write */
}

My port of the above to RTDM is:

if (my_context->wait_flag && !(my_context->data_flag)) {
       	 my_context->data_flag = TRUE;
          my_context->wait_flag = FALSE;
        	 rtdm_event_signal(&my_context->apc8620_wait);
}
return( RTDM_IRQ_HANDLED);

My understanding is that the above two pairs of code snippets (vanilla 
Linux and RTDM) do the same thing, functionally. However they do not. 
The interrupt driven A/D conversion is defined by a timer which can be 
set to some range of values (e.g. 1 second). However it seems that the 
board generates interrupts for other reasons as well.

When I run this using the Linux driver, my write call that initiates 
sleeps for about a second (i.e. the timer period) and then returns, and 
then there is data to read. When I run this running my RTDM driver, my 
write call sleeps much less, it returns almost immediately, and there is 
no data to read.

My question is therefore - have I made some obvious mistake in porting 
the regular interrupts to RTDM interrupts in the code above? Am I using 
RTDM interrupts correctly here? Or is the code I've written expectedly 
behaving differently from the original code?

Thanks for any help.

Best regards,

Andrija Stupar



On 2017-02-24 04:03, Philippe Gerum wrote:

> No issue with that. Any call site from a regular kernel context (i.e.
> not Xenomai's primary/rt mode) will do.
> 
> A context in the usual sense applies to a particular _connection_ to a
> device, i.e. per-fd, not to the device itself. In that sense, the 
> open()
> handler setting up a connection may refer to some global data for
> retrieving the setup information about the particular device instance
> the connection refers to. Since init_module() only knows about device
> instances, you need some proxy data structure to expose the device
> information to the open() handler.


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

* Re: [Xenomai] RTDM driver init: interrupts and context objects
  2017-03-03  4:10   ` andrija
@ 2017-03-18 16:28     ` Andrija Stupar
  2017-03-19  9:51       ` Philippe Gerum
  0 siblings, 1 reply; 7+ messages in thread
From: Andrija Stupar @ 2017-03-18 16:28 UTC (permalink / raw)
  To: xenomai

Well, I can answer my own question from a couple of weeks ago. Nothing 
was wrong with the way the RTDM interrupts were coded - the port from 
Linux to RTDM was done properly. The problem was a mode switch, falling 
into secondary (non-RT) mode. As I gather from the Xenomai RTDM API 
documentation, rtdm_event_wait(...) can only be called in RT mode. That 
is, if you call it non-RT mode it does nothing. When this call is made 
in non-RT mode, it just falls through (i.e. it does nothing). The actual 
interrupt occurs later and it has nothing to wake up since nothing went 
to sleep.

Once I found the sources of the mode switch in the code calling the 
driver, and fixed them so that I was always running in RT mode, the 
interrupts worked perfectly.


On 03/02/2017 11:10 PM, andrija@stupar.com wrote:
> Hi Philippe,
>
> Thank you very much for your earlier response. I have figured that 
> part of the driver out and opening and requesting an interrupt line 
> works well. Also, upon an interrupt, an interrupt service routine is 
> executed as expected. However I have one remaining problem I hope you 
> could help me out with. For interrupt-driven A/D conversion, the 
> hardware I am using works like this: 1) I write to a register to 
> initiate interrupt-driven A/D conversion 2) the write call then goes 
> to sleep until data is ready 3) an interrupt handler awakens the write 
> call 4) the write call returns and 5) the code which made the write 
> call now knows that it should read data from an input register.
>
> In the original driver, the code doing steps 1), 2) and 4) looks like 
> this:
>
> wqc = 0;       /* indicate waiting */
> writew( (int)ldata, (void *)(*adata) );
> wait_event_interruptible(ain_queue, wqc);
> wqc = 2;       /* indicate complete */
> .... return (...) ;
>
> Since interrupts in RTDM work slightly differently and there is no 
> wait queue in the RTDM/Xenomai version I am using, I ported the above 
> code to RTDM like this:
>
> writew( (int)ldata, (void *)(*adata) );
> if (!my_context->data_flag) {
>      my_context->wait_flag = TRUE; /* indicate waiting */
>          if (rtdm_event_wait(&my_context->apc8620_wait)) { /* wait */
>                        my_context->wait_flag = FALSE;
>                        return ( -ERESTARTSYS );
>          }
> }
> /* indicate complete */
> my_context->data_flag = FALSE;
> my_context->wait_flag = FALSE;
> .... return (...) ;
>
> In the original driver, step 3) is the in the interrupt handler 
> function and looks like this:
>
> if( wqc == 0)        /* waiting for a blocked start convert AND an 
> interrupt from the input board */
> {
>      wqc = 1;               /* when received, change the condition to 
> true... */
>       wake_up_interruptible(&ain_queue);     /* ... and wake the 
> blocked write */
> }
>
> My port of the above to RTDM is:
>
> if (my_context->wait_flag && !(my_context->data_flag)) {
>            my_context->data_flag = TRUE;
>          my_context->wait_flag = FALSE;
>             rtdm_event_signal(&my_context->apc8620_wait);
> }
> return( RTDM_IRQ_HANDLED);
>
> My understanding is that the above two pairs of code snippets (vanilla 
> Linux and RTDM) do the same thing, functionally. However they do not. 
> The interrupt driven A/D conversion is defined by a timer which can be 
> set to some range of values (e.g. 1 second). However it seems that the 
> board generates interrupts for other reasons as well.
>
> When I run this using the Linux driver, my write call that initiates 
> sleeps for about a second (i.e. the timer period) and then returns, 
> and then there is data to read. When I run this running my RTDM 
> driver, my write call sleeps much less, it returns almost immediately, 
> and there is no data to read.
>
> My question is therefore - have I made some obvious mistake in porting 
> the regular interrupts to RTDM interrupts in the code above? Am I 
> using RTDM interrupts correctly here? Or is the code I've written 
> expectedly behaving differently from the original code?
>
> Thanks for any help.
>
> Best regards,
>
> Andrija Stupar
>



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

* Re: [Xenomai] RTDM driver init: interrupts and context objects
  2017-03-18 16:28     ` Andrija Stupar
@ 2017-03-19  9:51       ` Philippe Gerum
  2017-03-19 18:08         ` andrija
  0 siblings, 1 reply; 7+ messages in thread
From: Philippe Gerum @ 2017-03-19  9:51 UTC (permalink / raw)
  To: Andrija Stupar, xenomai

On 03/18/2017 05:28 PM, Andrija Stupar wrote:
> Well, I can answer my own question from a couple of weeks ago. Nothing
> was wrong with the way the RTDM interrupts were coded - the port from
> Linux to RTDM was done properly. The problem was a mode switch, falling
> into secondary (non-RT) mode. As I gather from the Xenomai RTDM API
> documentation, rtdm_event_wait(...) can only be called in RT mode. That
> is, if you call it non-RT mode it does nothing. When this call is made
> in non-RT mode, it just falls through (i.e. it does nothing).

Actually, it does something wrong. You should always enable
CONFIG_XENO_DEBUG_COBALT to detect those spurious call sites.

-- 
Philippe.


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

* Re: [Xenomai] RTDM driver init: interrupts and context objects
  2017-03-19  9:51       ` Philippe Gerum
@ 2017-03-19 18:08         ` andrija
  2017-03-19 18:22           ` Philippe Gerum
  0 siblings, 1 reply; 7+ messages in thread
From: andrija @ 2017-03-19 18:08 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai

Hi Phillipe,

I was under the impression that I cannot, since Cobalt is a feature of 
Xenomai 3.x, and I am using Xenomai 2.6.5, where chasing the mode 
switches is a bit more complicated, as explained on the page 
https://xenomai.org//2014/06/finding-spurious-relaxes/

In any case, the causes of the mode switches that were troubling me were 
obvious, just buried in the code that I have been porting to Xenomai, 
and therefore took a while to find (doubtlessly using the debug flag 
would've been easier, but it did not take me weeks - this is not a 
project I work on full time).

Thanks,

Andrija

On 2017-03-19 05:51, Philippe Gerum wrote:

> 
> Actually, it does something wrong. You should always enable
> CONFIG_XENO_DEBUG_COBALT to detect those spurious call sites.


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

* Re: [Xenomai] RTDM driver init: interrupts and context objects
  2017-03-19 18:08         ` andrija
@ 2017-03-19 18:22           ` Philippe Gerum
  0 siblings, 0 replies; 7+ messages in thread
From: Philippe Gerum @ 2017-03-19 18:22 UTC (permalink / raw)
  To: andrija; +Cc: xenomai

On 03/19/2017 07:08 PM, andrija@stupar.com wrote:
> Hi Phillipe,
> 
> I was under the impression that I cannot, since Cobalt is a feature of
> Xenomai 3.x, and I am using Xenomai 2.6.5, where chasing the mode
> switches is a bit more complicated, as explained on the page
> https://xenomai.org//2014/06/finding-spurious-relaxes/
> 
> In any case, the causes of the mode switches that were troubling me were
> obvious, just buried in the code that I have been porting to Xenomai,

It does not seem a mode switch problem, but merely a calling context
issue. There is no mode switch from kernel space, however Xenomai
switches mode automatically at the syscall boundary, as required to keep
the core system sane regardless of how well/bad an application behaves.
Whether such switch is acceptable latency-wise for such application is a
totally different matter.

> and therefore took a while to find (doubtlessly using the debug flag
> would've been easier, but it did not take me weeks - this is not a
> project I work on full time).
> 

The almost equivalent flag for Xenomai 2.6 is CONFIG_XENO_OPT_DEBUG_NUCLEUS.

-- 
Philippe.


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

end of thread, other threads:[~2017-03-19 18:22 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-24  0:27 [Xenomai] RTDM driver init: interrupts and context objects andrija
2017-02-24  9:03 ` Philippe Gerum
2017-03-03  4:10   ` andrija
2017-03-18 16:28     ` Andrija Stupar
2017-03-19  9:51       ` Philippe Gerum
2017-03-19 18:08         ` andrija
2017-03-19 18:22           ` Philippe Gerum

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.