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
{
int irq;
irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;
cpumask_setall(bad_irq_desc.affinity);
bad_irq_desc.cpu = smp_processor_id();
#endif
init_arch_irq();
}
{
unsigned long pend;
unsigned long last;
int irqno;
int i;
for (i = 0; i < 4; i++) {
pend = __raw_readl(S3C24XX_EINTPEND);
break;
printk("irq: clearing pending ext status %08x\n", (int)pend);
last = pend;
}
. . . . . .
/* set all the s3c2410 internal irqs */
/* deal with the special IRQs (cascaded) */
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_RESERVED24:
/* no IRQ here */
break;
//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);
}
}
set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
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);
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 += (IRQ_EINT4 - 4); //Recalculate the interrupt number based on this offset } static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc) Upper interrupt processing function There are five upper-level interrupt handling functions: handle_simple_irq(), handle_level_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) if (!(action->flags & IRQF_DISABLED)) do { retval |= ret; if (status & IRQF_SAMPLE_RANDOM) return retval; void . . . . . . . . . . . . action_ret = handle_IRQ_event(irq, action); void . . . . . . do { desc->status &= ~IRQ_PENDING; //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_PENDING 4 /* An IRQ has appeared on the interrupt line and has been acknowledged, but */ } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING); desc->status &= ~IRQ_INPROGRESS;
irq = __ffs(eintpnd); //Calculate the offset of the interrupt in the external interrupt register EINTPEND
eintpnd &= ~(1<
generic_handle_irq(irq); //According to the recalculated interrupt number, get the corresponding structure irq_desc and call its upper interrupt handling function.
}
{
#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
}
handle_edge_irq(), handle_fasteoi_irq() and handle_percpu_irq().
{
irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0;
local_irq_enable_in_hardirq();
. . . . . .
ret = action->handler(irq, action->dev_id); //Execute interrupt handling function.
. . . . . .
action = action->next;
} while (action); //Call all routines on this interrupt line
add_interrupt_randomness(irq);
local_irq_disable();
}
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;
. . . . . .
}
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;
struct irqaction *action = desc->action;
. . . . . .
spin_unlock(&desc->lock);
action_ret = handle_IRQ_event(irq, action);
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
spin_lock(&desc->lock);
#define IRQ_DISABLED 2 /* This IRQ interrupt line has been disabled by the device driver */
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*/
out_unlock:
spin_unlock(&desc->lock);
}
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
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Design of full-speed USB interface for CC2531 chip
- 【Recruitment】Shenzhen-Two-hour work-Basic MSP430 knowledge
- EEWORLD University Hall ---- Principles of Automatic Control Xie Hongwei National University of Defense Technology
- Over 200 CircuitPython Libraries
- Does anyone know a comparison table of shortwave antenna elevation height and propagation distance?
- Share: Should the circuit board use grid copper or solid copper?
- Highlight Review丨What hard-core technologies did ADI showcase at IMS 2019? Come and find out~
- Google Protobuf 库
- EEWORLD University ---- Wildfire LwIP Application Development Practical Guide
- Compile QT5.6.0