Interrupt Handling Linux Kernel Programming CIS 4930COP 5641
- Slides: 36
Interrupt Handling Linux Kernel Programming CIS 4930/COP 5641
Topics n n n Overview Registration of handlers Interrupt sharing Interaction with hardware Limitations of handlers Bottom halves
Interrupts n Provides a mechanism other than busy waiting to be notified of an event q E. g. , Interrupt-driven I/O n Hardware generates interrupts when q q n n New data arrives and is ready for retrieval Ready to accept new data or to acknowledge a successful data transfer Signal from device to notify the CPU of an event (hardware desires attention) Concurrency issues arise
Interrupt-Driven I/O n Hardware generates interrupts when q q New data arrives and is ready for retrieval Ready to accept new data or to acknowledge a successful data transfer
Overview of Interrupts
Parallel Port Interrupts with short n LDD 3 illustrates interrupt handling with the short module n Setting bit 4 of the parallel port HW’s control port (0 x 37 a or 0 x 27 a) enables interrupt reporting Once enabled, the parallel interface generates an interrupt whenever the electrical signal at pin 10 (ACK bit) changes from low to high (edge-triggered) n
Hardware Configuration of LED Devices
Interrupts with short n n Pins 9 and 10 of the parallel connector are shorted Pin 9 is the most significant bit of the data byte Writing ASCII values to /dev/short 0 will not generate any interrupts An interrupt is raised whenever the electrical signal at pin 10 (ACK bit) changes from low to high
Installing (Registering) an Interrupt Handler n n Without an installed interrupt handler, Linux simply supplies an ack request_irq() q q irq number handler § q q q n irqreturn_t (*irq_handler_t)(int, void *) flags name Dev void free_irq(unsigned int, void *)
request_irq() n n n returns zero on success Common error is –EBUSY, which denotes given interrupt line is already in use and not shared can sleep q n Calls kmalloc() Make sure device is completely set up before calling request_irq q Interrupt may occur during/after called
Flags (include/linux/interrupt. h) n IRQF_DISABLED q q n n n IRQF_SHARED IRQF_TIMER IRQF_NO_THREAD IRQF_NO_SUSPEND IRQF_SAMPLE_RANDOM q n local_irq_enable_in_hardirq(); http: //lwn. net/Articles/380931/ http: //lwn. net/Articles/507115/ …
IRQF_SHARED n n n If interrupt lines are few (typically 16), sharing is likely necessary Each installed interrupt handler will be called dev parameter passed to request_irq cannot be NULL q Allows a means to distinguish between interrupt handlers when removal is requested
Interrupt Sharing n When an interrupt arrives, the kernel invokes every handler registered for that interrupt q n The handler must be able to recognize its own interrupts No probing function is available for shared handlers q Most hardware designed for interrupt sharing can tell the CPU which interrupt it is using n No need for explicit probing
Installing an Interrupt Handler n The short example if (short_irq >= 0) { result = request_irq(short_irq, short_interrupt, NULL, "short", NULL); if (result) { printk(KERN_INFO "short: can't get assigned irq %in", short_irq); short_irq = -1; } else { /* enable it -- assume this *is* a parallel port */ outb(0 x 10, short_base+2); } }
The /proc Interface n /proc/interrupts shows interrupts 0: 2: 8: 10: 11: 12: NMI: LOC: ERR: MIS: CPU 0 4848108 0 3 4335 8903 49 0 4848187 0 0 CPU 1 34 IO-APIC-edge 0 XT-PIC 1 IO-APIC-edge 1 IO-APIC-level 0 IO-APIC-level 1 IO-APIC-edge 0 4848186 timer cascade rtc aic 7 xxx uhci_hcd i 8042 Device names Linux often handles individual interrupts on the same CPU to maximize cache locality
The /proc Interface n /proc/stat shows number of interrupts received since system boot q q Architecture dependent file format Look for the intr string intr 5167833 5154006 2 0 2 4907 0 2 68 4 0 4406 9291 50 0 0 Total number Interrupt number 4 used 4907 times
Implementing a Handler n n No transferring data to and from user space Cannot sleep q q n Cannot call schedule, wait_event Can only use GFP_ATOMIC to allocate memory Might need to clear a bit on the device q Inform device subsequent interrupts should be provided
Implementing a Handler n Wakes up processes waiting for device services q E. g. , network card n n n Must process packets while waiting for more packets The interrupt handler copies new networking packets into main memory and readies network card for more packets The handler needs to execute in a minimum amount of time q Uses bottom half (typically tasklet or workqueue) to schedule computation later n E. g. network card – to sort packets and send them to correct application
Implementing a Handler n The short example irqreturn_t short_interrupt(int irq, void *dev_id) { struct timeval tv; int written; do_gettimeofday(&tv); written = sprintf((char *)short_head, "%08 u. %06 un", (int)(tv. tv_sec % 10000), (int)(tv. tv_usec)); short_incr_bp(&short_head, written); /* bp = buffer pointer */ wake_up_interruptible(&short_queue); return IRQ_HANDLED; }
Variable can be Implementing a Handleraccessed externally at any time static inline void short_incr_bp(volatile unsigned long *index, int delta) { unsigned long new = *index + delta; barrier(); /* Don't optimize these two together */ *index = (new >= (short_buffer + PAGE_SIZE)) ? short_buffer : new; } n Without barrier… static inline void short_incr_bp(volatile unsigned long *index, int delta) { *index = *index + delta; /* could expose an incorrect value */ if (*index >= (short_buffer + PAGE_SIZE)) *index = short_buffer; }
Implementing a Handler n To read the buffer, use /dev/shortint ssize_t short_i_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { int count 0; DEFINE_WAIT(wait); while (short_head == short_tail) { prepare_to_wait(&short_queue, &wait, TASK_INTERRUPTIBLE); if (short_head == short_tail) { schedule(); } finish_wait(&short_queue, &wait); if (signal_pending(current)) /* a signal arrived */ return -ERESTARTSYS; /* tell the fs layer to handle it */ }
Implementing a Handler /* count 0 is the number of readable data bytes */ count 0 = short_head - short_tail; if (count 0 < 0) {/* wrapped */ count 0 = short_buffer + PAGE_SIZE - short_tail; } if (count 0 < count) { count = count 0; } if (copy_to_user(buf, (char *)short_tail, count)) { return -EFAULT; } short_incr_bp(&short_tail, count); /* wrap the tail pointer */ return count; }
Handler Arguments and Return Value n Typical use of the argument in an interrupt handler static irqreturn_t sample_interrupt(int irq, void *dev_id) { struct sample_dev *dev = dev_id; /* now `dev' points to the right hardware item */ /*. . */ } q q irq: for printk dev_id: for finding out which instance of device is in charge of the current interrupt event
Handler Arguments and Return Value n Returns IRQ_HANDLED if from drivers device; otherwise, returns IRQ_NONE q Kernel can detect “spurious interrupts” if all interrupts on line return IRQ_NONE
Handler return Value n In the short example, use shared=1 to install a shared interrupted handler irqreturn_t short_sh_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int value, written; struct timeval tv; /* If it wasn't short, return immediately */ value = inb(short_base); Check the most if (!(value & 0 x 80)) significant bit return IRQ_NONE; /* clear the interrupting bit */ outb(value & 0 x 7 F, short_base);
Enabling and Disabling Interrupts n Interfaces for manipulating state of interrupts q q q n Disable interrupt system for current processor Mask out interrupt line for entire machine <asm/system. h> and <asm/irq. h> Why? q q Synchronization Common scenario n n Obtain lock to prevent another processor from accessing shared data Disabling interrupts provides protection against concurrent access from a possible interrupt handler
Enabling and Disabling Interrupts n For current processor only q local_irq_disable() disables interrupts n q Dangerous to call if interrupts were already disabled prior to invocation local_irq_enable() enables interrupts n Unconditionally enables interrupts
Enabling and Disabling Interrupts n Sometimes a mechanism is needed to restore interrupts to a previous state q n E. g. common code path can be reached both with and without interrupts enabled Since kernel is complex, much safer to restore to previous state using flags q q local_irq_save(flags) local_irq_restore(flags)
Disabling a Single Interrupt n Can disable (mask out) a specific interrupt line for an entire system q E. g. disable delivery of a device’s interrupts before manipulating its state void disable_irq(int irq); void disable_irq_nosync(int irq); void enable_irq(int irq);
Disabling a Single Interrupt n Calls can be nested q n The calling thread of the disable_irq should not hold resource needed by the target interrupt handler to disable q n If disable_irq is called twice, two enable_irq calls are required to reenable the IRQ Returns only when any currently executing handlers complete disable_irq_nosync returns immediately q Need to handle potential race conditions
Checking Interrupt Status n n Macro irqs_disabled() returns nonzero if the interrupt system on the local processor is disabled Checking current context q in_interrupt() n q Returns nonzero if in interrupt handler or bottom half in_irq() n Returns nonzero only if in interrupt handler
Top and Bottom Halves n Interrupt handling sometimes needs to perform lengthy tasks q This problem is resolved by splitting the interrupt handler into two halves n n Top half responds to the interrupt q The one registered to request_irq q Saves data to device-specific buffer and schedules the bottom half Bottom half is scheduled by the top half to execute later q q With all interrupts enabled Wakes up processes, starts I/O operations, etc.
Top and Bottom Halves n Two mechanisms may be used to implement bottom halves q Tasklets n q Workqueues n n No sleep Can sleep short module can be loaded to use either tasklet or workqueue
Tasklets n n n Cannot run in parallel with itself Can run in parallel with other tasklets on SMP systems Guaranteed to run on the same CPU that first scheduled them
Tasklets n In the short example, use tasklet=1 to install the tasklet-based interrupt handler void short_do_tasklet(unsigned long); DECLARE_TASKLET(short_tasklet, short_do_tasklet, 0); irqreturn_t short_tl_interrupt(int irq, void *dev_id) { /* cast to stop 'volatile' warning */ do_gettimeofday((struct timeval *) tv_head); short_incr_tv(&tv_head); tasklet_schedule(&short_tasklet); short_wq_count++; /* record that an interrupt arrived */ return IRQ_HANDLED; }
Workqueues n n n Invoke a function at some future time in the context of a special worker process Can sleep Generally do not copy data to and from user space
- Irqf_no_thread
- Linux security modules
- Linux kernel hacking
- Interrupt and interrupt responses in 8086
- Aicarm
- Linux kernel internals
- Linux kernel debugging techniques
- Kernel longterm
- Linux
- Block diagram of kernel
- Linux 1992
- Linux kernel map data structure
- Linux firewalls
- Linux kernel hacking
- Linux kernel map data structure
- Compile linux with clang
- Eclipse linux kernel
- Debugger message panic
- Linux kernel backdoor
- Linux kernel eol
- Workqueue in linux
- Remap_pfn_range example
- Saat ini copyright kernel linux dipegang oleh
- Linux
- Linux kernel synchronization
- Serial interrupt in 8051
- Cs423
- What is file management in c
- Linux gui programming
- Low level programming languages
- What is system program
- Integer programming vs linear programming
- Perbedaan linear programming dan integer programming
- Definisi integer
- Greedy vs dynamic
- Android emulator bootloader
- Palm kernel expeller price chart