\subsection{Interrupt Management}

\begin{frame}[fragile]
  \frametitle{Registering an interrupt handler 1/2}
  \begin{itemize}
  \item Defined in \code{include/linux/interrupt.h}
    \begin{itemize}
    \item \mint{c}+int request_irq(unsigned int irq,+
      \mint{c}+irq_handler_t handler, unsigned long irq_flags,+
      \mint{c}+const char *devname, void *dev_id);+
      \begin{itemize}
      \item \code{irq} is the requested IRQ channel
      \item \code{handler} is a pointer to the IRQ handler
      \item \code{irq_flags} are option masks (see next slide)
      \item \code{devname} is the registered name
      \item \code{dev_id} is a pointer to some data. It cannot be NULL
        as it is used as an identifier for \code{free_irq} when using
        shared IRQs.
      \end{itemize}
    \item \mint{c}+void free_irq(unsigned int irq, void *dev_id);+
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Registering an interrupt handler 2/2}
  \begin{itemize}
  \item Main \code{irq_flags} bit values (can be combined, none is
    fine too)
    \begin{itemize}
    \item \code{IRQF_SHARED}
      \begin{itemize}
      \item The interrupt channel can be shared by several
        devices. Requires a hardware status register telling whether
        an IRQ was raised or not.
      \end{itemize}
    \item \code{IRQF_SAMPLE_RANDOM}
      \begin{itemize}
      \item Use the IRQ arrival time to feed the kernel random number
        generator.
      \end{itemize}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Interrupt handler constraints}
  \begin{itemize}
  \item No guarantee in which address space the system will be in when
    the interrupt occurs: can't transfer data to and from user space
  \item Interrupt handler execution is managed by the CPU, not by the
    scheduler.  Handlers can't run actions that may sleep, because
    there is nothing to resume their execution. In particular, need to
    allocate memory with \code{GFP_ATOMIC}.
  \item Interrupt handlers are run with all interrupts disabled (since
    2.6.36).  Therefore, they have to complete their job quickly
    enough, to avoiding blocking interrupts for too long.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{/proc/interrupts on a Panda board}
\begin{verbatim}
        CPU0    CPU1
39:     4       0       GIC     TWL6030-PIH
41:     0       0       GIC     l3-dbg-irq
42:     0       0       GIC     l3-app-irq
43:     0       0       GIC     prcm
44:     20294   0       GIC     DMA
52:     0       0       GIC     gpmc
...
IPI0:   0       0       Timer broadcast interrupts
IPI1:   23095   25663   Rescheduling interrupts
IPI2:   0       0       Function call interrupts
IPI3:   231     173     Single function call interrupts
IPI4:   0       0       CPU stop interrupts
LOC:    196407  136995  Local timer interrupts
Err:    0
\end{verbatim}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Interrupt handler prototype}
  \begin{itemize}
  \item \mint{c}+irqreturn_t foo_interrupt(int irq, void *dev_id)+
    \begin{itemize}
    \item \code{irq}, the IRQ number
    \item \code{dev_id}, the opaque pointer passed at
      \code{request_irq()}
    \end{itemize}
  \item Return value
    \begin{itemize}
    \item \code{IRQ_HANDLED}: recognized and handled interrupt
    \item \code{IRQ_NONE}: not on a device managed by the
      module. Useful to share interrupt channels and/or report
      spurious interrupts to the kernel.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Typical interrupt handler's job}
  \begin{itemize}
  \item Acknowledge the interrupt to the device (otherwise no more
    interrupts will be generated, or the interrupt will keep firing
    over and over again)
  \item Read/write data from/to the device
  \item Wake up any waiting process waiting for the completion of an
    operation, typically using wait queues
    \code{wake_up_interruptible(&module_queue);}
\end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Threaded interrupts}
  \begin{itemize}
  \item In 2.6.30, support for threaded interrupts has been added to
    the Linux kernel
    \begin{itemize}
    \item The interrupt handler is executed inside a thread.
    \item Allows to block during the interrupt handler, which is often
      needed for I2C/SPI devices as the interrupt handler needs to
      communicate with them.
    \item Allows to set a priority for the interrupt handler
      execution, which is useful for real-time usage of Linux
    \end{itemize}
  \item \mint{c}+int request_threaded_irq(unsigned int irq,+
    \mint{c}+irq_handler_t handler, irq_handler_t thread_fn,+
    \mint{c}+unsigned long flags, const char *name, void *dev);+
    \begin{itemize}
    \item \code{handler}, ``hard IRQ'' handler
    \item \code{thread_fn}, executed in a thread
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Top half and bottom half processing}
  \begin{itemize}
  \item Splitting the execution of interrupt handlers in 2 parts
    \begin{itemize}
    \item Top half
      \begin{itemize}
      \item This is the real interrupt handler, which should complete
        as quickly as possible since all interrupts are disabled. If
        possible, take the data out of the device and schedule a
        bottom half to handle it.
      \end{itemize}
    \item Bottom half
      \begin{itemize}
      \item Is the general Linux name for various mechanisms which
        allow to postpone the handling of interrupt-related
        work. Implemented in Linux as softirqs, tasklets or
        workqueues.
      \end{itemize}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Top half and bottom half diagram}
  \begin{center}
    \includegraphics[width=\textwidth]{slides/kernel-driver-development-interrupts/thread-halves.pdf}
  \end{center}
\end{frame}

\begin{frame}
  \frametitle{Softirqs}
  \begin{itemize}
  \item Softirqs are a form of bottom half processing
  \item The softirqs handlers are executed with all interrupts
    enabled, and a given softirq handler can run simultaneously on
    multiple CPUs
  \item They are executed once all interrupt handlers have completed,
    before the kernel resumes scheduling processes, so sleeping is not
    allowed.
  \item The number of softirqs is fixed in the system, so softirqs are
    not directly used by drivers, but by complete kernel subsystems
    (network, etc.)
  \item The list of softirqs is defined in
    \code{include/linux/interrupt.h}: \code{HI}, \code{TIMER},
    \code{NET_TX}, \code{NET_RX}, \code{BLOCK}, \code{BLOCK_IOPOLL},
    \code{TASKLET}, \code{SCHED}, \code{HRTIMER}, \code{RCU}
  \item The \code{HI} and \code{TASKLET} softirqs are used to execute
    tasklets
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Tasklets}
  \begin{itemize}
  \item Tasklets are executed within the \code{HI} and \code{TASKLET}
    softirqs. They are executed with all interrupts enabled, but a
    given tasklet is guaranteed to execute on a single CPU at a time.
  \item A tasklet can be declared statically with the
    \code{DECLARE_TASKLET()} macro or dynamically with the
    \code{tasklet_init()} function. A tasklet is simply implemented as
    a function. Tasklets can easily be used by individual device
    drivers, as opposed to softirqs.
  \item The interrupt handler can schedule the execution of a tasklet
    with
    \begin{itemize}
    \item \code{tasklet_schedule()} to get it executed in the
      \code{TASKLET} softirq
    \item \code{tasklet_hi_schedule()} to get it executed in the
      \code{HI} softirq (higher priority)
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Tasklet Example: simplified atmel\_serial.c 1/2}
\begin{minted}[fontsize=\small]{c}
/* The tasklet function */
static void atmel_tasklet_func(unsigned long data) {
        struct uart_port *port = (struct uart_port *)data;
        [...]
}

/* Registering the tasklet */
init function(...) {
        [...]
        tasklet_init(&atmel_port->tasklet,
            atmel_tasklet_func,(unsigned long)port);
        [...]
}
\end{minted}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Tasklet Example: simplified atmel\_serial.c 2/2}
\begin{minted}[fontsize=\small]{c}
/* Removing the tasklet */
cleanup function(...) {
        [...]
        tasklet_kill(&atmel_port->tasklet);
        [...]
}

/* Triggering execution of the tasklet */
somewhere function(...) {
        tasklet_schedule(&atmel_port->tasklet);
}
\end{minted}
\end{frame}

\begin{frame}
  \frametitle{Workqueues}
  \begin{itemize}
  \item Workqueues are a general mechanism for deferring work. It is
    not limited in usage to handling interrupts.
  \item The function registered as workqueue is executed in a thread,
    which means :
    \begin{itemize}
    \item All interrupts are enabled
    \item Sleeping is allowed
    \end{itemize}
  \item A workqueue is registered with \code{INIT_WORK} and typically
    triggered with \code{queue_work()}
  \item The complete API, in \code{include/linux/workqueue.h} provides
    many other possibilities (creating its own workqueue threads,
    etc.)
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Interrupt management summary}
  \begin{itemize}
  \item Device driver
    \begin{itemize}
    \item When the device file is first opened, register an interrupt
      handler for the device's interrupt channel.
    \end{itemize}
  \item Interrupt handler
    \begin{itemize}
    \item Called when an interrupt is raised.
    \item Acknowledge the interrupt
    \item If needed, schedule a tasklet taking care of handling
      data. Otherwise, wake up processes waiting for the data.
    \end{itemize}
  \item Tasklet
    \begin{itemize}
    \item Process the data
    \item Wake up processes waiting for the data
    \end{itemize}
  \item Device driver
    \begin{itemize}
    \item When the device is no longer opened by any process,
      unregister the interrupt handler.
    \end{itemize}
  \end{itemize}
\end{frame}
