Arm-Linux S3C2440 interrupt analysis (III)

Source: Internet
Author: User

==== This article is the original site. You are welcome to reprint it! Reprinted please indicate the source: http://blog.csdn.net/yyplc====

In Linux, you can use the following functions to register handle, an entry function related to interruptions and interruptions. You can use this function only when you register IRQ first.

int set_irq_chip(unsigned int irq, structirq_chip *chip)static inline void set_irq_handler(unsigned intirq, irq_flow_handler_t handle)static inline void set_irq_chained_handler(unsignedint irq, irq_flow_handler_t handle)

The implementation code is as follows:

For (irqno = irq_eint4t7; irqno <= irq_adcparent; irqno ++) {/* set all the S3C2410 internal irqs */switch (irqno) {/* deal with the special irqs (cascaded) */Salary: Usage: set_irq_chip (irqno, & temperature); set_irq_handler (irqno, handle_level_irq ); // level-triggered break; caseirq_reserved6: caseirq_reserved24:/* No IRQ here */break; default: // irqdbf ("registeringirq % d (s3c IRQ) \ n ", irqno); set_irq_chip (irqno, & cloud_irq_chip); set_irq_handler (irqno, handle); // set_irq_flags (irqno, ir1__valid );} /* Registration of Cascaded disconnections */Break (irq_eint4t7, break); break (irq_eint8t23, break); break (irq_uart0, break); break (irq_uart1, break ); round (irq_uart2, strong); Round (irq_adcparent, strong);/* externalinterrupts */For (irqno = irq_eint0; irqno <= irq_eint3; irqno ++) {irqdbf ("registeringirq % d (ext int) \ n", irqno); set_irq_chip (irqno, & empty); set_irq_handler (irqno, empty); set_irq_flags (irqno, irqf_valid) ;}for (irqno = random; irqno <= irq_eint23; irqno ++) {irqdbf ("registeringirq % d (Extended s3c IRQ) \ n", irqno ); set_irq_chip (irqno, & assign); set_irq_handler (irqno, assign); random (irqno, ir1__valid);}/* register the uartinterrupts */irqdbf ("S3C2410: registering external interrupts \ n "); For (irqno = temperature; irqno <= temperature; irqno ++) {irqdbf (" registeringirq % d (s3c uart0 IRQ) \ n ", irqno); set_irq_chip (irqno, & assign); set_irq_handler (irqno, assign); set_irq_flags (irqno, irqf_valid) ;}for; irqno ++) {irqdbf ("registeringirq % d (s3c uart1 IRQ) \ n", irqno); set_irq_chip (irqno, & assign); set_irq_handler (irqno, assign ); set_irq_flags (irqno, ir1__valid) ;}for (irqno = random; irqno <= random; irqno ++) {irqdbf ("registeringirq % d (s3c uart2 IRQ) \ n ", irqno); set_irq_chip (irqno, & assign); set_irq_handler (irqno, assign); Round (irqno, ir1__valid);} For (irqno = irq_tc; irqno <= irq_adc; irqno ++) {// register irq_tc and irq_adc irqdbf ("registeringirq % d (s3c adc irq) \ n", irqno); set_irq_chip (irqno, & initi_irq_adc ); set_irq_handler (irqno, handle_edge_irq); set_irq_flags (irqno, ir1__valid );}

From the code above, we can see that registration interruption is mainly the entry to the registration interruption service program. In Linux, all interrupt numbers are managed in a unified manner using a stuctirq_desc data structure. Each interrupt number or a group of Interrupt numbers (such as cascade interruptions) corresponds to a structirq_desc, therefore, based on the corresponding interrupt number, you can obtain the corresponding interrupt description structure irq_desc:

Struct irq_desc * DESC = irq_to_desc (IRQ); irq_desc Data Structure: struct irq_desc {unsigned int IRQ; // interrupt number... Irq_flow_handler_t handle_irq; // The entry function structirq_chip * chip for system interrupt processing; // the corresponding irq_chip structure defines the functions related to interrupt processing... Structirqaction * Action; // the user's interrupt processing function. When request_irq is called, add the unsigned int status; // IRQ status... Spinlock_t lock ;... Const char * Name; }____ cacheline_internodealigned_in_smp;

The irq_chip structure defines various interrupt-related processing behaviors, such as processing related interrupt registers after the interrupt service is enabled or disabled and the interrupt service is completed. The entry functions of Level Trigger and edge trigger interrupt can be seen from the irq_chip structure that only ack functions are different in processing:

struct irq_chip s3c_irq_level_chip = {       .name            = "s3c-level",       .ack        = s3c_irq_maskack,       .mask            = s3c_irq_mask,       .unmask         = s3c_irq_unmask,       .set_wake      = s3c_irq_wake}; struct irq_chip s3c_irq_chip = {       .name            = "s3c",       .ack        = s3c_irq_ack,       .mask            = s3c_irq_mask,       .unmask         = s3c_irq_unmask,       .set_wake      = s3c_irq_wake};

The following code is added to the initiirq_maskack file:

Mask = _ raw_readl (s3c2410_intmsk );

_ Raw_writel (mask | bitval, s3c2410_intmsk );

The function is to block related interruptions.

The interrupt (exception) vector has been initialized in early_trap_init () to copy the abnormal vector table from the physical address 0x00000000 to the virtual address of the virtual 0xffff0000. Exception vectors are defined in arch/ARM/kernel/entry-armv.S:

       .globl      __vectors_start__vectors_start:       swi  SYS_ERROR0       b     vector_und + stubs_offset       ldr    pc, .LCvswi + stubs_offset       b     vector_pabt + stubs_offset       b     vector_dabt + stubs_offset       b     vector_addrexcptn + stubs_offset       b     vector_irq + stubs_offset       b     vector_fiq + stubs_offset        .globl      __vectors_end

When an interruption occurs:

/** Interrupthandling. preserves R7, R8, R9 */. macro irq_handler handler, LR1: get_irqnr_and_baser0, R6, R5, LR movne R1, Sp @ routinecalled with R0 = IRQ Number, R1 = struct pt_regs * @ adrne LR, 1B BNE asm_do_irq // jump to the total entry function interrupted here

Here asm_do_irq corresponds to arch/ARM/kernel/IRQ. C:

asmlinkage void __exception asm_do_IRQ(unsigned int irq,struct pt_regs *regs)

So this is the total entry function for all interruptions in Linux. Asm_doirq () calls generic_handle_irq () and then calls

Generic_handle_irq_desc (), and then process each irq_desc.

static inline void generic_handle_irq_desc(unsigned intirq, struct irq_desc *desc){#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ       desc->handle_irq(irq,desc);#else       if(likely(desc->handle_irq))              desc->handle_irq(irq,desc);       else              __do_IRQ(irq);#endif}

The process from the total entry to the user's interrupt processing function:

Asm_do_irq () --> generic_handle_irq () --> irq_dsc-> handle () à handle_irq_event () à irq_des-> action ()

Finally, we will briefly summarize the interrupt handling process:

(1) The total entry function asm_do_irq is used to obtain the interrupt number IRQ.

(2) asm_do_irq calls the interrupt entry function irq_desc [IRQ] registered by each interrupt number based on the interrupt number-> handle_irq

(3) Call handle_irq_event () in the interrupt entry function to execute the user's interrupt processing function action in sequence.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.