ARM Linux interrupt mechanism interrupt initialization

Publisher:skyhcgLatest update time:2016-07-28 Source: eefocusKeywords:ARM Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
First, recognize several important structures:

1. Interrupt Descriptor

Each interrupt line is described by an irq_desc structure.

//In include/linux/irq.h

struct irq_desc {
 unsigned int irq;//interrupt number
 struct timer_rand_state *timer_rand_state;
 unsigned int *kstat_irqs ;
#ifdef CONFIG_INTR_REMAP
 struct irq_2_iommu *irq_2_iommu;
#endif

/*

Five functions are implemented in kernel/irq/chip.c: handle_simple_irq(), handle_level_irq(), 
handle_edge_irq(), handle_fasteoi_irq() and handle_percpu_irq(). The handle_irq pointer can
point to one of these five functions to select an interrupt event handling strategy, which is
done by the function set_irq_handler()

*/
 irq_flow_handler_t handle_irq;//Upper-layer interrupt processing function,
 struct irq_chip *chip;//Underlying hardware operation
 struct msi_desc *msi_desc;
 void *handler_data;//Additional parameters for handle_irq
 void *chip_data;//Platform-related additional parameters for chip
 struct irqaction *action; /* IRQ action list *///Interrupt service routine list
 unsigned int status; /* IRQ status *///Current status of the interrupt

//Call disable_irq() once to turn on or off interrupts, and the depth will increase by 1; call enable_irq() once to decrease the value by 1.

//If depth is equal to 0, turn on this interrupt line, if depth is greater than 0, turn off the interrupt line.

 unsigned int depth; 
 unsigned int wake_depth; ////* wake-up times */ 
 unsigned int irq_count; /* interrupt times */ 
 unsigned long last_unhandled; /* Aging timer for unhandled count */
 unsigned int irqs_unhandled;
 spinlock_t lock;
#ifdef CONFIG_SMP
 cpumask_var_t affinity;
 unsigned int cpu;
#ifdef CONFIG_GENERIC_PENDING_IRQ
 cpumask_var_t pending_mask;
#endif
#endif
 atomic_t threads_active;
 wait_queue_head_t wait_for_threads;
#ifdef CONFIG_PROC_FS
 struct proc_dir_entry *dir;///proc/irq/ entry
#endif
 const char *name;//interrupt name displayed in/proc/interrupts
} ____cacheline_internodealigned_in_smp;


/*In kernel/irq/handle.c there is a global irq_desc array that describes all interrupt lines in the system:

struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
 [0 ... NR_IRQS-1] = {
  .status = IRQ_DISABLED,
  .chip = &no_irq_chip,
  .handle_irq = handle_bad_irq,
  .depth = 1,
  .lock = __SPIN_LOCK_UNLOCKED(irq_desc- >lock) ,
 }
};

NR_IRQS is the maximum number of interrupts for the s3c2410 chip, which is defined in the file arch/arm/mach-s3c2410/include/mach/irqs.h as follows:

#ifdef CONFIG_CPU_S3C2443
#define NR_IRQS (IRQ_S3C2443_AC97+1)
#else
#define NR_IRQS (IRQ_S3C2440_AC97+1) //Each interrupt source corresponds to an irq_desc structure.
#endif

*/

2. Interrupt hardware operation function set

//Defined in include/linux/irq.h

//The functions in this structure are implemented in the file linux/arch/arm/plat-s3c24xx/irq.c

struct irq_chip {
 const char *name; //used for /proc/interrupts
 unsigned int (*startup)(unsigned int irq); //default is enable if NULL
 void (*shutdown)(unsigned int irq); //default is disable if NULL
 void (*enable)(unsigned int irq); //enable interrupts, default is unmask if NULL
 void (*disable)(unsigned int irq); //disable interrupts, default is mask if NULL

 void (*ack)(unsigned int irq); //Respond to an interrupt and clear the interrupt flag
 void (*mask)(unsigned int irq); //Mask an interrupt source, usually turn off the interrupt
 void (*mask_ack)(unsigned int irq); //Respond and mask the interrupt source
 void (*unmask)(unsigned int irq); //Unmask the interrupt source
 void (*eoi)(unsigned int irq);

 void (*end)(unsigned int irq);
 void (*set_affinity)(unsigned int irq,
     const struct cpumask *dest);
 int (*retrigger)(unsigned int irq);
 int (*set_type)(unsigned int irq, unsigned int flow_type); //Set the interrupt trigger mode IRQ_TYPE_LEVEL
 int (*set_wake)(unsigned int irq, unsigned int on);

 /* Currently used only by UML, might disappear one day.*/
#ifdef CONFIG_IRQ_RELEASE_METHOD
 void (*release)(unsigned int irq, void *dev_id);
#endif
 /*
  * For compatibility, ->typename is copied into ->name .
  * Will disappear.
  */
 const char *typename;
};

3. Interrupt handling routine descriptor

//In include/linux/interrupt.h

struct irqaction {
 irq_handler_t handler; /* Specific interrupt handler*/ 
 unsigned long flags; //Use a set of flags to describe the relationship between the interrupt line and the I/O device.
 cpumask_t mask;
 const char *name; /* Name, which will be displayed in /proc/interreupts*/ 
 void *dev_id; /* Device ID, used to distinguish multiple handlers that share an interrupt line, so as to delete the specified one from the many interrupt handlers that share the interrupt line*/ 
 struct irqaction *next; /* Points to the next irq_action structure*/ 
 int irq; /* Interrupt channel number*/ 
 struct proc_dir_entry *dir; /* procfs directory*/
 irq_handler_t thread_fn;
 struct task_struct *thread;
 unsigned long thread_flags;
};

 

The relationship between these three structures is shown as follows

ARM Linux interrupt mechanism interrupt initialization - Dust - Learning Bits
 
Second, interrupt initialization process
 
The initialization of the interrupt mechanism is completed through two functions: early_trap_init() and init_IRQ(). Here we first discuss the function init_IRQ().
//The function init_IRQ is implemented in the file linux/arch/arm/kernel/irq.c.
void __init init_IRQ(void)
{
 int irq;
/* Set the status of the irq_desc array to IRQ_NOREQUEST | IRQ_NOPROBE (no request, no detection) */
 for (irq = 0; irq < NR_IRQS; irq++)
  irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;
#ifdef CONFIG_SMP
 cpumask_setall(bad_irq_desc.affinity);
 bad_irq_desc.cpu = smp_processor_id();
#endif
/*
init_arch_irq is defined in the file linux/arch/arm/kernel/irq.c as follows
void (*init_arch_irq)(void) __initdata = NULL;
This function pointer is assigned in setup_arch().
init_arch_irq = mdesc->init_irq;
Points to the init_irq function defined in machine_desc.
In platform smdk2440, this function is implemented in the file linux/arch/arm/plat-s3c24xx/irq.c.
*/
 init_arch_irq();
}
//The function s3c24xx_init_irq is implemented in the file linux/arch/arm/plat-s3c24xx/irq.c
void __init s3c24xx_init_irq(void)
{
 unsigned long pend;
 unsigned long last;
 int irqno;
 int i;
 irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
 /* first, clear all interrupts pending... */
 last = 0;
 for (i = 0; i < 4; i++) {
  pend = __raw_readl(S3C24XX_EINTPEND);
  if (pend == 0 || pend == last)
   break;
  __raw_writel(pend, S3C24XX_EINTPEND); //Clear the request flag in the external interrupt register EINTPEND,
  printk("irq: clearing pending ext status %08x\n", (int)pend);
  last = pend;
 }
 last = 0;

. . . . . .
 
 //Set the underlying hardware operation function set of each interrupt desc->chip, interrupt upper layer processing function desc->handle_irq
 for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
  /* set all the s3c2410 internal irqs */
  switch (irqno) {
   /* deal with the special IRQs (cascaded) */
  case IRQ_EINT4t7:
  case IRQ_EINT8t23:
  case IRQ_UART0:
  case IRQ_UART1:
  case IRQ_UART2:
  case IRQ_ADCPARENT:
   set_irq_chip(irqno, &s3c_irq_level_chip);
   set_irq_handler(irqno, handle_level_irq);
   break;
  case IRQ_RESERVED6:
  case IRQ_RESERVED24:
   /* no IRQ here */
   break;
  default:
   //irqdbf("registering irq %d (s3c irq)\n", irqno);
   set_irq_chip(irqno, &s3c_irq_chip);
   set_irq_handler(irqno, handle_edge_irq);
   set_irq_flags(irqno, IRQF_VALID);
  }
 }
 //The following interrupts have multiple interrupt sources, each of which has its own interrupt number. Any of their multiple interrupt sources can generate an interrupt.
//The interrupt will be triggered instead of directly triggering the sub-interrupt. These interrupts do not process interrupt functions. Their job is to calculate the interrupt number of the sub-interrupt.
//According to the interrupt number of the sub-interrupt, find the irq_desc structure corresponding to the interrupt number in the array irq_desc[NR_IRQS] and call the interrupt handling function in the structure.
 set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
 set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
 set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
 set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
 set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
 set_irq_chained_handler(IRQ_ADCPARENT, s 3c_irq_demux_adc);
 
. . . . . .
 
 for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
  irqdbf("registering irq %d (extended s3c irq)\n", irqno);
  set_irq_chip(irqno, &s3c_irqext_chip); //Set the hardware operation function set of the sub-interrupt
  set_irq_handler(irqno, handle_edge_irq); //Set the upper layer processing function of the sub-interrupt
  set_irq_flags(irqno, IRQF_VALID);
 }
 
. . . . . .
 
}

 For example, at this time, external interrupt 10 generates an interrupt, the interrupt number IRQ_EINT8t23 is triggered, and the function s3c_irq_demux_extint8() is executed.

static void
s3c_irq_demux_extint8(unsigned int irq,
        struct irq_desc *desc)
{
 unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
 unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);

 eintpnd &= ~eintmsk;
 eintpnd &= ~0xff; /* ignore lower irqs */

 /* we may as well handle all the pending IRQs here */

 while (eintpnd) {
  irq = __ffs(eintpnd); //Calculate the offset of the interrupt in the external interrupt register EINTPEND
  eintpnd &= ~(1<

  irq += (IRQ_EINT4 - 4); //Recalculate the interrupt number based on this offset
  generic_handle_irq(irq); //According to the recalculated interrupt number, get the corresponding structure irq_desc and call its upper interrupt handling function.
 }

}

 

static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
 desc->handle_irq(irq, desc); //Directly call the upper-level interrupt processing function
#else
 if (likely(desc->handle_irq))
  desc->handle_irq(irq, desc);
 else
  __do_IRQ(irq); //Generic interrupt processing function, which eventually calls desc->handle_irq(irq, desc); 
#endif
}

 

Upper interrupt processing function

There are five upper-level interrupt handling functions: handle_simple_irq(), handle_level_irq(), 
handle_edge_irq(), handle_fasteoi_irq() and handle_percpu_irq().

These functions are implemented in the file kernel/irq/chip.c. Two commonly used ones are handle_level_irq() and handle_edge_irq().

These five upper-level interrupt handling functions are further processed by calling the function handle_IRQ_event().

irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
 irqreturn_t ret, retval = IRQ_NONE;
 unsigned int status = 0;

 if (!(action->flags & IRQF_DISABLED))
  local_irq_enable_in_hardirq();

 do {


. . . . . .


  ret = action->handler(irq, action->dev_id); //Execute interrupt handling function.


. . . . . .

 

  retval |= ret;
  action = action->next;
 } while (action); //Call all routines on this interrupt line

 if (status & IRQF_SAMPLE_RANDOM)
  add_interrupt_randomness(irq);
 local_irq_disable();

 return retval;
}

 

void
handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
 struct irqaction *action;
 irqreturn_t action_ret;

. . . . . .


 desc = irq_remap_to_desc(irq, desc);

. . . . . .


 action = desc->action;

 action_ret = handle_IRQ_event(irq, action);


. . . . . .


}

 

void
handle_edge_irq(unsigned int irq, struct irq_desc *desc)
{
 spin_lock(&desc->lock);

. . . . . .
  desc = irq_remap_to_desc(irq, desc);
. . . . . .
 desc->status |= IRQ_INPROGRESS;

 do {
  struct irqaction *action = desc->action;
 . . . . . .

 

  desc->status &= ~IRQ_PENDING;
  spin_unlock(&desc->lock);
  action_ret = handle_IRQ_event(irq, action);
  if (!noirqdebug)
   note_interrupt(irq, desc, action_ret);
  spin_lock(&desc->lock);

//This function is different from handle_level_irq in that it has an extra loop. That is, if

//If another interrupt occurs on the interrupt line during the processing of the interrupt line, the processing routine on the interrupt line will be executed again

/*

The following are 5 commonly used interrupt line states.

#define IRQ_INPROGRESS 1 /* A handler for this IRQ is currently being executed */
#define IRQ_DISABLED 2 /* This IRQ interrupt line has been disabled by the device driver */

#define IRQ_PENDING 4 /* An IRQ has appeared on the interrupt line and has been acknowledged, but
it has not been serviced yet*/
#define IRQ_REPLAY 8 /* When Linux resends an IRQ that has been deleted*/
#define IRQ_WAITING 32 /* When probing hardware devices, set this state to mark
the irq being tested*/

*/

 } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);

 desc->status &= ~IRQ_INPROGRESS;
out_unlock:
 spin_unlock(&desc->lock);
}

Keywords:ARM Reference address:ARM Linux interrupt mechanism interrupt initialization

Previous article:ARM Linux interrupt mechanism interrupt application
Next article:ARM: Code, RO-data, RW-data, ZI-data meaning

Recommended ReadingLatest update time:2024-11-16 22:36

Design of a ten-circuit intelligent power distribution monitoring unit based on ARM microprocessor
O Introduction Distribution automation technology is developing rapidly towards digitalization, intelligence, networking and multi-function. This paper takes the microcontroller LPC2132 chip containing ARM7TDMI-STM CPU as the main controller of the system, and focuses on the collection and data communicatio
[Power Management]
Wireless transmission and reception based on ARM and GPRS
Introduction In recent years, wireless communication technology has been widely used. GPRS (General Packet Radio System) is a popular wireless communication network. GPRS network has the advantages of wide coverage, fast data transmission speed, high communication quality, always online and flow-based bi
[Microcontroller]
Wireless transmission and reception based on ARM and GPRS
Asynchronous Transfer Mode ATM in ARM Technology
Asynchronous Transfer Mode (ATM) is a new generation of data transmission and packet switching technology, and is a hot topic in current network technology research and application.     The main features of ATM technology are: 3 ATM is a connection-oriented technology that uses small, fixed-length data transmi
[Microcontroller]
OK6410A development board (VIII) 24 linux-5.11 OK6410A start_kernel Functional perspective Phase III
The third stage of categorizing Linux: removing all processes except idle // 0 : idle // Already analyzed in https://blog.csdn.net/u011011827/article/details/116594370 1 : kernel_init 2 : kthreadd 3 : ... ... Creation of process No. 1 kernel_init Creation Process Relationship with CPU The kernel bare metal program
[Microcontroller]
Application of LPC21XX Series Microcontroller Based on ARM7 in BAS
1. Overview of Building Automation System Building Automation System (BAS) is actually a central monitoring system. It centrally monitors various power equipment, air conditioning equipment, cold and heat source equipment, fire protection, anti-theft equipment, etc. in a building (or building complex), so as to ach
[Microcontroller]
Application of LPC21XX Series Microcontroller Based on ARM7 in BAS
Analysis of abnormal interrupt mechanism of ARM S3C4510B system
This paper introduces the abnormal interrupt mechanism of ARM S3C4510B system, including the classification, response and return of abnormal interrupt; installation and calling of interrupt handler; examples and key codes of SWI and IRQ interrupt. As people's requirements for electronic products become higher and hi
[Microcontroller]
Analysis of abnormal interrupt mechanism of ARM S3C4510B system
Ubuntu12.10 uses DNW to transfer data for ARM development board burning
Part 1 Preface I'm studying OK6410 development board recently, but rvds under windows is not easy to use. To burn the program to the development board, dnw is needed, and all these softwares have to be done under win, which is very frustrating. Besides, 64-bit win7 has various problems. I want to transplant the Linux
[Microcontroller]
Design of CAN Node Based on ARM Processor
introduction With the rapid development of information technology, based on ARM's advantages in embedded systems and the wide application of CAN bus, more and more ARM processors are equipped with CAN controllers, which greatly facilitates the development of CAN bus by developers. This project is based on the d
[Microcontroller]
Design of CAN Node Based on ARM Processor
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号