Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Quick and Easy Device Drivers for Embedded Linux Using UIO

8,480 views

Published on

Make life easy for yourself by using the Userpace IO (UIO) framework to write device drivers for custom hardware

Published in: Technology

Quick and Easy Device Drivers for Embedded Linux Using UIO

  1. 1. Quick and Easy Device Drivers for Embedded Linux Using UIO Chris Simmonds Embedded World 2017 Quick and Easy Device Drivers for Embedded Linux Using UIO 1 Copyright © 2011-2017, 2net Ltd
  2. 2. License These slides are available under a Creative Commons Attribution-ShareAlike 3.0 license. You can read the full text of the license here http://creativecommons.org/licenses/by-sa/3.0/legalcode You are free to • copy, distribute, display, and perform the work • make derivative works • make commercial use of the work Under the following conditions • Attribution: you must give the original author credit • Share Alike: if you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one (i.e. include this page exactly as it is) • For any reuse or distribution, you must make clear to others the license terms of this work Quick and Easy Device Drivers for Embedded Linux Using UIO 2 Copyright © 2011-2017, 2net Ltd
  3. 3. About Chris Simmonds • Consultant and trainer • Author of Mastering Embedded Linux Programming • Working with embedded Linux since 1999 • Android since 2009 • Speaker at many conferences and workshops "Looking after the Inner Penguin" blog at http://2net.co.uk/ https://uk.linkedin.com/in/chrisdsimmonds/ https://google.com/+chrissimmonds Quick and Easy Device Drivers for Embedded Linux Using UIO 3 Copyright © 2011-2017, 2net Ltd
  4. 4. Overview • Conventional Linux drivers • The UIO framework • An example UIO driver • Scheduling and interrupt latencies Quick and Easy Device Drivers for Embedded Linux Using UIO 4 Copyright © 2011-2017, 2net Ltd
  5. 5. Conventional device driver model User space System call handler Generic services Device drivers Hardware Application C library interrupts Kernel space Quick and Easy Device Drivers for Embedded Linux Using UIO 5 Copyright © 2011-2017, 2net Ltd
  6. 6. Userspace drivers • Writing kernel device drivers can be difficult • Luckily, there are generic drivers that that allow you to write most of the code in userspace • For example • USB (via libusb) • GPIO • I2C Reference www.slideshare.net/chrissimmonds/userspace-drivers2016 Quick and Easy Device Drivers for Embedded Linux Using UIO 6 Copyright © 2011-2017, 2net Ltd
  7. 7. UIO drivers • Userspace I/O (UIO) is a framework for userspace drivers that do not fit into the standard patterns • Typical use-cases include interfaces to FPGAs and custom PCI functions • UIO may be appropriate for your hardware interface if: • it has registers and/or buffers that are memory mapped • it generates interrupts Quick and Easy Device Drivers for Embedded Linux Using UIO 7 Copyright © 2011-2017, 2net Ltd
  8. 8. The UIO way IRQ mmap interrupt handler Register bank /dev/uio0 mmap() read() Hardware Kernel Application Register bank Quick and Easy Device Drivers for Embedded Linux Using UIO 8 Copyright © 2011-2017, 2net Ltd
  9. 9. Kernel and userspace components • UIO drivers are in two parts • A simple kernel stub driver, which creates device node /dev/uioX • A user-space driver that implements the majority of the code • Device node /dev/uioX links the two together Quick and Easy Device Drivers for Embedded Linux Using UIO 9 Copyright © 2011-2017, 2net Ltd
  10. 10. The UIO kernel driver • Kernel driver needs to • point to one (or more) memory regions • assign the interrupt number (IRQ) • implement interrupt handler • register as a UIO driver Quick and Easy Device Drivers for Embedded Linux Using UIO 10 Copyright © 2011-2017, 2net Ltd
  11. 11. Example driver This device has 8 KiB (0x2000) of memory-mapped registers at 0x4804C000 and is attached to hardware interrupt IRQ 85 static int demo_probe(struct platform_device *pdev) { info.name = "demo"; info.version = "1.0"; info.mem[0].addr = 0x4804C000; info.mem[0].size = 0x2000; info.mem[0].memtype = UIO_MEM_PHYS; info.irq = 85; info.irq_flags = 0; info.handler = demo_handler; return uio_register_device(&pdev->dev, &info); } Quick and Easy Device Drivers for Embedded Linux Using UIO 11 Copyright © 2011-2017, 2net Ltd
  12. 12. Kernel interrupt handler • Usually very simple • For example, disable interrupt source, which will be enabled again in userspace drivers/uio/uio_aec.c: static irqreturn_t aectc_irq(int irq, struct uio_info *dev_info) { void __iomem *int_flag = dev_info->priv + INTA_DRVR_ADDR; unsigned char status = ioread8(int_flag); if ((status & INTA_ENABLED_FLAG) && (status & INTA_FLAG)) { /* application writes 0x00 to 0x2F to get next interrupt */ status = ioread8(dev_info->priv + MAILBOX); return IRQ_HANDLED; } return IRQ_NONE; } Quick and Easy Device Drivers for Embedded Linux Using UIO 12 Copyright © 2011-2017, 2net Ltd
  13. 13. The user-space driver • Each UIO driver represented by device node /dev/uioX • X = 0 for first, 1 for second, etc. • User space application uses it to mmap the memory and receive notification of interrupts Quick and Easy Device Drivers for Embedded Linux Using UIO 13 Copyright © 2011-2017, 2net Ltd
  14. 14. Mapping memory • mmap(2) maps memory associated with a file descriptor • Example: map 0x2000 bytes from file /dev/uio0: int main(int argc, char **argv) { int f; char *ptr; f = open("/dev/uio0", O_RDWR); if (f == -1) { return 1; } ptr = mmap(0, 0x2000, PROT_READ | PROT_WRITE, MAP_SHARED, f, 0); if (ptr == MAP_FAILED) { return 1; } ptr points to the base of the register bank. UIO framework maps the memory without processor cache, so writes and reads force memory cycles on the system bus Quick and Easy Device Drivers for Embedded Linux Using UIO 14 Copyright © 2011-2017, 2net Ltd
  15. 15. Handling interrupts • Wait for interrupt by reading from /dev/uioX • The read() blocks until the next interrupt arrives • Data returned by read contains the count of interrupts since the UIO kernel driver was started • Can detect missed interrupts by comparing with previous interrupt count Quick and Easy Device Drivers for Embedded Linux Using UIO 15 Copyright © 2011-2017, 2net Ltd
  16. 16. Interrupt example 1 • Simple example, using blocking read call static void wait_for_int(int f) { int n; unsigned int irc_count; printf("Waitingn"); n = read(f, &irc_count, sizeof(irc_count)); if (n == -1) { printf("read errorn"); return; } printf("irc_count = %dn", irc_count); } Quick and Easy Device Drivers for Embedded Linux Using UIO 16 Copyright © 2011-2017, 2net Ltd
  17. 17. Blocking behaviour • Blocking in read() means that the application cannot do any work between interrupts • Solution 1: use poll() or select() to wait with a timeout • possibly on several data sources at once • Solution 2: use a thread to wait Quick and Easy Device Drivers for Embedded Linux Using UIO 17 Copyright © 2011-2017, 2net Ltd
  18. 18. Interrupt example 2 • Using poll(2) static void wait_for_int_poll(int f) { struct pollfd poll_fds [1]; int ret; unsigned int irc_count; printf("Waitingn"); poll_fds[0].fd = f; poll_fds[0].events = POLLIN; ret = poll(poll_fds, 1, 100); /* timeout = 100 ms */ if (ret > 0) { if (poll_fds[0].revents && POLLIN) { read(f, &irc_count, sizeof(irc_count)); printf("irc_count = %dn", irc_count); } } } Quick and Easy Device Drivers for Embedded Linux Using UIO 18 Copyright © 2011-2017, 2net Ltd
  19. 19. Mapping more than one memory area • Example: a device with two address ranges: info.name = "demo"; info.version = "1.0"; info.mem[0].addr = 0x4804C000; info.mem[0].size = 0x2000; info.mem[0].memtype = UIO_MEM_PHYS; info.mem[1].addr = 0x48060000; info.mem[1].size = 0x4000; info.mem[1].memtype = UIO_MEM_PHYS; return uio_register_device(&pdev->dev, &info); UIO allows up to 5 address ranges Quick and Easy Device Drivers for Embedded Linux Using UIO 19 Copyright © 2011-2017, 2net Ltd
  20. 20. Mapping address ranges • The range to map is specified as mmap offset (last parameter) • Because behind the scenes mmap works in pages instead of bytes, the index has to be given in pages • To mmap address range in info.mem[1], use offset = 1 page: ptr2 = mmap(0, 0x4000, PROT_READ | PROT_WRITE, MAP_SHARED, f, 1 * getpagesize()); Quick and Easy Device Drivers for Embedded Linux Using UIO 20 Copyright © 2011-2017, 2net Ltd
  21. 21. Scheduling • Where interrupts are concerned, the process or thread should be real-time • scheduling policy = SCHED_FIFO • Memory locked using mlockall struct sched_param param; mlockall (MCL_CURRENT | MCL_FUTURE); param.sched_priority = 10; if (sched_setscheduler (getpid (), SCHED_FIFO, &param) != 0) printf ("Failed to change policy and priorityn"); Quick and Easy Device Drivers for Embedded Linux Using UIO 21 Copyright © 2011-2017, 2net Ltd
  22. 22. Interrupt latency • Even a real-time thread may have high jitter on interrupt latency if the kernel is not preemptive • Configure kernel with CONFIG_PREEMPT • Or, implement Real-time kernel patche and configure with CONFIG_PREEMPT_RT • Measures latencies will vary from platform to platform, but should be less than a few hundred microseconds Quick and Easy Device Drivers for Embedded Linux Using UIO 22 Copyright © 2011-2017, 2net Ltd
  23. 23. Further reading • Kernel source documentation: Documentation/DocBook/uio-howto • on-line at https://www.osadl.org/fileadmin/dam/interface/ docbook/howtos/uio-howto.pdf • LWN article: https://lwn.net/Articles/232575/ Quick and Easy Device Drivers for Embedded Linux Using UIO 23 Copyright © 2011-2017, 2net Ltd
  24. 24. Summary • UIO provides a convenient way to implement drivers for FPGA interfaces and hardware for which there is no existing Linux driver • Applicable to hardware that provides mappable memory and generates interrupts Quick and Easy Device Drivers for Embedded Linux Using UIO 24 Copyright © 2011-2017, 2net Ltd
  25. 25. • Any questions? This and other topics associated with building robust embedded systems are covered in my training courses http://www.2net.co.uk/training.html Quick and Easy Device Drivers for Embedded Linux Using UIO 25 Copyright © 2011-2017, 2net Ltd

×