2

I am writing a device driver for a custom piece of hardware using the Linux kernel 2.6.33. I need am using DMA to transfer data to and from the device. For the output DMA, I was thinking that I would keep track of several output buffers using the Linked List API (struct list_head, list_add(), etc.).

When the device finished the DMA transfer, it raises an interrupt. The interrupt handler would then retrieve item in the linked list to transfer, and remove it from the list.

My question is, is this actually a safe thing to do inside of an interrupt handler? Or are there inherent race conditions in this API that would make it not safe?

The small section in Linux Device Drivers, 3rd Ed. doesn't make mention of this. The section in Essential Linux Device Drivers is more complete but also does not touch on this subject.

Edit: I am beginning to think that it may very well not be race condition free as msh suggests, due to a note listed in the list_empty_careful() function:

* NOTE: using list_empty_careful() without synchronization
* can only be safe if the only activity that can happen
* to the list entry is list_del_init(). Eg. it cannot be used
* if another CPU could re-list_add() it.

http://lxr.free-electrons.com/source/include/linux/list.h?v=2.6.33;a=powerpc#L202

Note that I plan to add to the queue in process context and remove from the queue in interrupt context. Do you really not need synchronization around the functions for a list?

Benjamin Leinweber
  • 2,774
  • 1
  • 24
  • 41

1 Answers1

2

It is perfectly safe to use kernel linked lists in interrupt context, but but retrieving anything in interrupt handlers is a bad idea. In the interrupt handler you should acknowledge interrupt, schedule "bottom half" and quit. All processing should be done by the "bottom half" (bottom half is just a piece of deferred work - there are several suitable mechanisms - tasklets, work queue, etc).

msh
  • 2,700
  • 1
  • 17
  • 23
  • The buffer is pre-allocated and populated in the write() function and queued up in the linked list. The only thing that my interrupt handler is going to do is to free the previous buffer, then tell the hardware where the next DMA buffer is and start the transaction. Do you really think I need the overhead of a bottom half for these simple transactions? – Benjamin Leinweber May 20 '13 at 03:51
  • I'd say - yes, freeing memory and talking to the hardware can add unacceptable latency to interrupt handlers. – msh May 20 '13 at 07:47
  • Linked list is safe for interrupt context, it is not intrinsically thread-safe like circular buffer and if you want to use it from multiple threads, you do nee synchronization. Which is one more reason to move it out of the interrupt handler. – msh May 21 '13 at 04:20
  • Your right. I've put the whole thing in a workqueue since those execute in process context and I can use a mutex for synchronization. – Benjamin Leinweber May 21 '13 at 04:54