<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > ARM Linux中斷機制之中斷的初始化

ARM Linux中斷機制之中斷的初始化

作者: 時(shí)間:2016-11-10 來(lái)源:網(wǎng)絡(luò ) 收藏
一,認識幾個(gè)重要結構體:

1.中斷描述符

本文引用地址:http://dyxdggzs.com/article/201611/317087.htm

對于每一條中斷線(xiàn)都由一個(gè)irq_desc結構來(lái)描述。

//在include/linux/irq.h中

struct irq_desc {
unsigned intirq;//中斷號
struct timer_rand_state *timer_rand_state;
unsigned int *kstat_irqs;
#ifdef CONFIG_INTR_REMAP
struct irq_2_iommu *irq_2_iommu;
#endif

/*

在kernel/irq/chip.c中實(shí)現了5個(gè)函數:handle_simple_irq(),handle_level_irq(),
handle_edge_irq(),handle_fasteoi_irq()以及handle_percpu_irq()。 handle_irq指針可
以指向這5個(gè)函數中的一個(gè), 選擇一種中斷事件處理策略, 這是通過(guò)函數set_irq_handler()
完成的

*/
irq_flow_handler_thandle_irq;//上層中斷處理函數,
struct irq_chip*chip;//底層硬件操作
struct msi_desc*msi_desc;
void*handler_data;//附加參數,用于handle_irq
void*chip_data;//平臺相關(guān)附加參數,用于chip
struct irqaction*action;/* IRQ action list*///中斷服務(wù)例程鏈表
unsigned intstatus;/* IRQ status *///中斷當前的狀態(tài)

//中斷關(guān)閉打開(kāi)層數調用一次disable_irq( ) ,depth加1;調用一次enable_irq( )該值減1,

//如果depth等于0就開(kāi)啟這條中斷線(xiàn),如果depth大于0就關(guān)閉中斷線(xiàn)。

unsigned intdepth;
unsigned intwake_depth;////* 喚醒次數 */
unsigned intirq_count;/* 發(fā)生的中斷次數 */
unsigned longlast_unhandled;/* Aging timer for unhandled count */
unsigned intirqs_unhandled;
spinlock_tlock;
#ifdef CONFIG_SMP
cpumask_var_taffinity;
unsigned intcpu;
#ifdef CONFIG_GENERIC_PENDING_IRQ
cpumask_var_tpending_mask;
#endif
#endif
atomic_tthreads_active;
wait_queue_head_t wait_for_threads;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry*dir;///proc/irq/ 入口
#endif
const char*name;///proc/interrupts 中顯示的中斷名稱(chēng)
} ____cacheline_internodealigned_in_smp;


/*在kernel/irq/handle.c中有個(gè)全局irq_desc數組,描述了系統中所有的中斷線(xiàn):

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為最大中斷數對于s3c2410芯片,在文件arch/arm/mach-s3c2410/include/mach/irqs.h中定義如下:

#ifdef CONFIG_CPU_S3C2443
#define NR_IRQS (IRQ_S3C2443_AC97+1)
#else
#define NR_IRQS (IRQ_S3C2440_AC97+1)//每一個(gè)中斷源都對應一個(gè)irq_desc結構體。
#endif

*/

2. 中斷硬件操作函數集

//在include/linux/irq.h中定義

//該結構體中各函數在文件linux/arch/arm/plat-s3c24xx/irq.c中實(shí)現

struct irq_chip {
const char*name;//用于 /proc/interrupts
unsigned int(*startup)(unsigned int irq);//默認為 enable 如果為NULL
void(*shutdown)(unsigned int irq);//默認為 disable 如果為NULL
void(*enable)(unsigned int irq);//允許中斷,默認為 unmask 如果為NULL
void(*disable)(unsigned int irq);//禁止中斷,默認為 mask如果為 NULL

void(*ack)(unsigned int irq);//響應一個(gè)中斷,清除中斷標志
void(*mask)(unsigned int irq);//mask 一個(gè)中斷源,通常是關(guān)閉中斷
void(*mask_ack)(unsigned int irq);//響應并 mask 中斷源
void(*unmask)(unsigned int irq);//unmask 中斷源
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);//設置中斷觸發(fā)方式 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.中斷處理例程描述符

//在include/linux/interrupt.h中

struct irqaction {
irq_handler_t handler;/* 具體的中斷處理程序 */
unsigned long flags;//用一組標志描述中斷線(xiàn)與 I/O 設備之間的關(guān)系。
cpumask_t mask;
const char *name;/* 名稱(chēng),會(huì )顯示在/proc/interreupts中 */
void *dev_id;/* 設備ID,用于區分共享一條中斷線(xiàn)的多個(gè)處理程序 ,以便從共享中斷線(xiàn)的諸多中斷處理程序中刪除指定的那一個(gè)*/
struct irqaction *next;/* 指向下一個(gè)irq_action結構 */
int irq;/* 中斷通道號 */
struct proc_dir_entry *dir; /* procfs目錄 */
irq_handler_t thread_fn;
struct task_struct *thread;
unsigned long thread_flags;
};

這三個(gè)結構體間的關(guān)系表示如下

二,中斷初始化過(guò)程
中斷機制的初始化通過(guò) 兩個(gè)函數完成:early_trap_init()和init_IRQ(),在此我們先討論函數init_IRQ()。
//函數init_IRQ在文件linux/arch/arm/kernel/irq.c中實(shí)現。
void __init init_IRQ(void)
{
int irq;
/* 設置 irq_desc 數組的 status 為 IRQ_NOREQUEST | IRQ_NOPROBE(沒(méi)有請求,沒(méi)有檢測) */
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在文件linux/arch/arm/kernel/irq.c中定義如下
void (*init_arch_irq)(void) __initdata = NULL;
該函數指針在 setup_arch()中被賦值,
init_arch_irq = mdesc->init_irq;
指向 machine_desc 中定義的 init_irq 函數。
在平臺smdk2440中,該函數在文件linux/arch/arm/plat-s3c24xx/irq.c中實(shí)現。
*/
init_arch_irq();
}
//函數s3c24xx_init_irq在文件linux/arch/arm/plat-s3c24xx/irq.c中實(shí)現
void __init s3c24xx_init_irq(void)
{
unsigned long pend;
unsigned long last;
int irqno;
int i;
irqdbf("s3c2410_init_irq: clearing interrupt status flagsn");
/* 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);//清除外部中斷寄存器EINTPEND中的請求標志,
printk("irq: clearing pending ext status %08xn", (int)pend);
last = pend;
}
last = 0;

。。。。。。
//設置各中斷的底層硬件操作函數集desc->chip,中斷上層處理函數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);
}
}
//以下幾個(gè)中斷都有多個(gè)中斷源,每一個(gè)中斷源也都有各自的中斷號,它們的多個(gè)中斷源中任意一個(gè)產(chǎn)生中斷
//該中斷都會(huì )被觸發(fā),而不是直接出發(fā)子中斷。這幾個(gè)中斷并不處理中斷函數,它們的中作是計算子中斷的中斷號,
//并根據子中斷的中斷號在數組irq_desc[NR_IRQS]中去找出該中斷號對應的irq_desc結構,并調用該結構中的中斷處理函數。
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, s3c_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_irq_handler(irqno, handle_edge_irq);//設置子中斷的上層處理函數
set_irq_flags(irqno, IRQF_VALID);
}
。。。。。。

}

比如此時(shí)外部中斷10產(chǎn)生了中斷,中斷號為IRQ_EINT8t23的中斷被觸發(fā),執行函數s3c_irq_demux_extint8()。

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);//計算該中斷在外部中斷寄存器EINTPEND中的偏移量
eintpnd &= ~(1<

irq += (IRQ_EINT4 - 4);//根據這個(gè)偏移量重新計算中斷號
generic_handle_irq(irq);//根據重新計算的中斷號獲取對應的結構體irq_desc,并調用它的上層中斷處理函數。
}

}

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);//直接調用上層中斷處理函數
#else
if (likely(desc->handle_irq))
desc->handle_irq(irq, desc);
else
__do_IRQ(irq);//通用中斷處理函數,該函數最終調用desc->handle_irq(irq, desc);
#endif
}

上層中斷處理函數

上層中斷處理函數有5個(gè)分別為:handle_simple_irq(),handle_level_irq(),
handle_edge_irq(),handle_fasteoi_irq()以及handle_percpu_irq()。

這幾個(gè)函數在文件kernel/irq/chip.c中實(shí)現。常用的有兩個(gè)handle_level_irq(),和handle_edge_irq()。

這5個(gè)上層中斷處理函數都是通過(guò)調用函數handle_IRQ_event()來(lái)做進(jìn)一步處理。

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);//執行中斷處理函數。


。。。。。。

retval |= ret;
action = action->next;
} while (action);//調用該中斷線(xiàn)上的所有例程

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);

//該函數與函數handle_level_irq不太一樣的是,該函數多了一個(gè)循環(huán)。即如果在本次中斷

//的處理過(guò)程中該中斷線(xiàn)上又有中斷產(chǎn)生,則再次執行該中斷線(xiàn)上的處理例程

/*

以下是5個(gè)常用的中斷線(xiàn)狀態(tài)。

#define IRQ_INPROGRESS 1 /* 正在執行這個(gè) IRQ 的一個(gè)處理程序 */
#define IRQ_DISABLED 2 /* 由設備驅動(dòng)程序已經(jīng)禁用了這條 IRQ 中斷線(xiàn) */

#define IRQ_PENDING 4 /* 一個(gè) IRQ 已經(jīng)出現在中斷線(xiàn)上,且被應答,但還沒(méi)有
為它提供服務(wù) */
#define IRQ_REPLAY 8 /* 當 Linux 重新發(fā)送一個(gè)已被刪除的 IRQ 時(shí) */
#define IRQ_WAITING 32 /* 當對硬件設備進(jìn)行探測時(shí),設置這個(gè)狀態(tài)以標記正在被
測試的 irq */

*/

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

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



關(guān)鍵詞: ARMLinux中斷機制初始

評論


技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>