cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
m3atwad
Voyager
Voyager
2,536 Views
Registered: ‎05-25-2016

Is the UIO driver only for interrupt handling?

Jump to solution

Hello,

I think I have a good image and the uio driver connected to my gpio input (connected to slide switches on the zed board).  I've been reading the forums all day trying to understand the approach to using zed board gpio interrupts.  I've ended up with the impression that the UIO driver is used for just handling interrupts from axi ip.  

In this below example it looks like the mmap() call is used for register reading and writing and the UIO driver (here there is a uio0 device) is only used for reading interrupts by way of the poll?

https://forums.xilinx.com/t5/Embedded-Linux/Custom-Hardware-with-UIO/m-p/805185#M22515

In that link in the section labled "And the C code" someone has posted a working example.  A few questions:

1. Why are they still using mmap and not ONLY the UIO driver to interface with the IP?

2. Where does the poll() function come from?  Is this just a standard C thing?

3. Isn't the poll() function just blocking code execution?  How is this more efficient then polling the registers with a sleep command?

4. Does the UIO driver know what IRQ number corresponds to the PL IP so when you open uio0 the driver figures out what IRQ number to use?  If so does this mean there is no need to know the IRQ number when developing software (C code) when using the UIO driver?

5. I've read in the TRM and other forum posts about the offset of offset for interrupts.  So, my understanding was you subtract 32 from your interrupt number to get the interrupt number value shown in the device tree.  I've also read on these forums that with the latest petalinux IRQ numbers are assigned dynamically and you have to use a _probe() function to get one.  Is there anyone who could elaborate on this?  Maybe the _probe() function is for driver development and with the UIO you can just use the offset?

 

I believe I"ve gotten the build done correctly becuase I have hte following cat /proc/interrupts output

136.jpg

I can see my gpio module and the GIC-0, 61 and Level.  I also see it as uio0 in the /sys/class/uio folder.  So I think I'm all setup to get ISRs working, but am a little confused still.  

 

Also, I see posts about using the UIO driver as a go-by for developing platform drivers.  Where can I find the source for drivers for linux zynq builds to see what is going on behind the scenes and maybe I can answer some of these questions on my own by looking at the source code in the future.

 

 

Thanks!

136.jpg
0 Kudos
1 Solution

Accepted Solutions
rfs613
Scholar
Scholar
2,521 Views
Registered: ‎05-28-2013

@m3atwad wrote:

1. Why are they still using mmap and not ONLY the UIO driver to interface with the IP?

The example includes custom PL logic, with registers defined in the range 0x43c00000 to 0x4c0ffff (eg. size 0x10000). They are using mmap() in order to access these registers.

2. Where does the poll() function come from?  Is this just a standard C thing?

This is a standard unix/Linux function. See http://man7.org/linux/man-pages/man2/poll.2.html

It is a more modern version of the classic select() function, in case that helps.

3. Isn't the poll() function just blocking code execution?  How is this more efficient then polling the registers with a sleep command?

Yes, it will put the program to sleep (won't be scheduled to run) until one of the "watched" file descriptors indicates it is ready. In the case of UIO, this will happen when the interrupt fires. So this is an efficient way for a program to wait for the interrupt, because the task sleeps until the hardware IRQ occurs.

In constrast, polling the registers directly would be very inefficient. It would potentially tie up a CPU (depending on how often you poll).

4. Does the UIO driver know what IRQ number corresponds to the PL IP so when you open uio0 the driver figures out what IRQ number to use?  If so does this mean there is no need to know the IRQ number when developing software (C code) when using the UIO driver?

The UIO driver is generic, it does not know anything about the PL IP.

Rather, you have to tell it which interrupt (and controller) via the device tree. In the example you linked, it is like so:

		custom_ip_0: custom_ip@43c00000 {
			compatible = "generic-uio";
			interrupt-parent = <&intc>;
			interrupts = <0 29 1>;

5. I've read in the TRM and other forum posts about the offset of offset for interrupts.  So, my understanding was you subtract 32 from your interrupt number to get the interrupt number value shown in the device tree.  I've also read on these forums that with the latest petalinux IRQ numbers are assigned dynamically and you have to use a _probe() function to get one.  Is there anyone who could elaborate on this?  Maybe the _probe() function is for driver development and with the UIO you can just use the offset?

The subject of interrupt numbering could be a whole thread on its own. At one point, yes it was a simple "subtract 32" for Zynq. But over time, the linux kernel numbering has changed, so the best answer now is "it depends". It is architecture specific, and kernel-version and kernel-configuration specific. There are other forum posts about this issue.

I can see my gpio module and the GIC-0, 61 and Level.  I also see it as uio0 in the /sys/class/uio folder.  So I think I'm all setup to get ISRs working, but am a little confused still.  

Perhaps, but do you also have the custom PL code that this example relies on? Otherwise you will probably find that the IRQ will never fire. And if you try to access the registers at 0x43c00000 you may find that the board will hang.

Also, I see posts about using the UIO driver as a go-by for developing platform drivers.  Where can I find the source for drivers for linux zynq builds to see what is going on behind the scenes and maybe I can answer some of these questions on my own by looking at the source code in the future.


You could look at pretty much any driver in the linux kernel - I would start with simple ones such as RTC. Source code for the linux kernel used by Xilinx is at https://github.com/Xilinx/linux-xlnx (and of course, there is a copy in your petalinux somewhere).

There are lots of resources for linux drivers, including the book "Linux Device Drivers".

Platform devices documentation: https://www.kernel.org/doc/html/latest/driver-api/driver-model/platform.html

UIO documentation: https://www.kernel.org/doc/html/latest/driver-api/uio-howto.html

[edit: fix paragraph spacing]

View solution in original post

2 Replies
rfs613
Scholar
Scholar
2,522 Views
Registered: ‎05-28-2013

@m3atwad wrote:

1. Why are they still using mmap and not ONLY the UIO driver to interface with the IP?

The example includes custom PL logic, with registers defined in the range 0x43c00000 to 0x4c0ffff (eg. size 0x10000). They are using mmap() in order to access these registers.

2. Where does the poll() function come from?  Is this just a standard C thing?

This is a standard unix/Linux function. See http://man7.org/linux/man-pages/man2/poll.2.html

It is a more modern version of the classic select() function, in case that helps.

3. Isn't the poll() function just blocking code execution?  How is this more efficient then polling the registers with a sleep command?

Yes, it will put the program to sleep (won't be scheduled to run) until one of the "watched" file descriptors indicates it is ready. In the case of UIO, this will happen when the interrupt fires. So this is an efficient way for a program to wait for the interrupt, because the task sleeps until the hardware IRQ occurs.

In constrast, polling the registers directly would be very inefficient. It would potentially tie up a CPU (depending on how often you poll).

4. Does the UIO driver know what IRQ number corresponds to the PL IP so when you open uio0 the driver figures out what IRQ number to use?  If so does this mean there is no need to know the IRQ number when developing software (C code) when using the UIO driver?

The UIO driver is generic, it does not know anything about the PL IP.

Rather, you have to tell it which interrupt (and controller) via the device tree. In the example you linked, it is like so:

		custom_ip_0: custom_ip@43c00000 {
			compatible = "generic-uio";
			interrupt-parent = <&intc>;
			interrupts = <0 29 1>;

5. I've read in the TRM and other forum posts about the offset of offset for interrupts.  So, my understanding was you subtract 32 from your interrupt number to get the interrupt number value shown in the device tree.  I've also read on these forums that with the latest petalinux IRQ numbers are assigned dynamically and you have to use a _probe() function to get one.  Is there anyone who could elaborate on this?  Maybe the _probe() function is for driver development and with the UIO you can just use the offset?

The subject of interrupt numbering could be a whole thread on its own. At one point, yes it was a simple "subtract 32" for Zynq. But over time, the linux kernel numbering has changed, so the best answer now is "it depends". It is architecture specific, and kernel-version and kernel-configuration specific. There are other forum posts about this issue.

I can see my gpio module and the GIC-0, 61 and Level.  I also see it as uio0 in the /sys/class/uio folder.  So I think I'm all setup to get ISRs working, but am a little confused still.  

Perhaps, but do you also have the custom PL code that this example relies on? Otherwise you will probably find that the IRQ will never fire. And if you try to access the registers at 0x43c00000 you may find that the board will hang.

Also, I see posts about using the UIO driver as a go-by for developing platform drivers.  Where can I find the source for drivers for linux zynq builds to see what is going on behind the scenes and maybe I can answer some of these questions on my own by looking at the source code in the future.


You could look at pretty much any driver in the linux kernel - I would start with simple ones such as RTC. Source code for the linux kernel used by Xilinx is at https://github.com/Xilinx/linux-xlnx (and of course, there is a copy in your petalinux somewhere).

There are lots of resources for linux drivers, including the book "Linux Device Drivers".

Platform devices documentation: https://www.kernel.org/doc/html/latest/driver-api/driver-model/platform.html

UIO documentation: https://www.kernel.org/doc/html/latest/driver-api/uio-howto.html

[edit: fix paragraph spacing]

View solution in original post

m3atwad
Voyager
Voyager
2,459 Views
Registered: ‎05-25-2016

@rfs613 thank you so much for the reply!  This was a fantastic response to my questions.  I actually managed to get a uio interrupt driven  test program running using pthreads.  Very exciting and your reply was very helpful!  Thanks!

0 Kudos