linux kernel 中的 setup_irq和request_irq

來源:互聯網
上載者:User

講解的很詳細,轉載下.

 

Linux 核心提供了兩個註冊中斷處理函數的介面:setup_irq和request_irq。這兩個函數都定義在kernel/irq/manage.c裡。

/*

* Internal function to register an irqaction - typically used to

* allocate special interrupts that are part of the architecture.

*/

int setup_irq(unsigned int irq, struct irqaction *new);

/*

* request_irq - allocate an interrupt line

* This call allocates interrupt resources and enables the

* interrupt line and IRQ handling.

*/

int request_irq(unsigned int irq,

irqreturn_t (*handler)(int, void *, struct pt_regs *),

unsigned long irqflags, const char *devname, void *dev_id)

這兩個函數有什麼樣的區別呢?

先看看setup_irq

Setup_irq通常用在系統時鐘(GP Timer)驅動裡,註冊系統時鐘驅動的中斷處理函數。

下面舉個列子, 如s3c2410 timer驅動:

/* arch/arm/mach-s3c2410/time.c */

static struct irqaction s3c2410_timer_irq = {

.name = "S3C2410 Timer Tick",

.flags = IRQF_DISABLED | IRQF_TIMER,

.handler = s3c2410_timer_interrupt,

};

static void __init s3c2410_timer_init (void)

{

s3c2410_timer_setup();

setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);

}

struct sys_timer s3c24xx_timer = {

.init = s3c2410_timer_init,

.offset = s3c2410_gettimeoffset,

.resume = s3c2410_timer_setup

};

struct sys_timer s3c24xx_timer = {

.init = s3c2410_timer_init,

.offset = s3c2410_gettimeoffset,

.resume = s3c2410_timer_setup

};

可以看到,setup_irq的使用流程很簡單。首先定義s3c2410 timer驅動的irqaction結構體,該結構體用於描述timer中斷的基本屬性包括中斷名、類別以及該中斷handler等。然後通過setup_irq函數將timer的irqaction註冊進核心。其中,IRQ_TIMER4為s3c2410 timer的中斷號。

再看看request_irq

request_irq源碼如下:

/* kernel/irq/manage.c */

int request_irq(unsigned int irq,

irqreturn_t (*handler)(int, void *, struct pt_regs *),

unsigned long irqflags, const char *devname, void *dev_id)

{

struct irqaction *action;

int retval;

#ifdef CONFIG_LOCKDEP

/*

* Lockdep wants atomic interrupt handlers:

*/

irqflags |= SA_INTERRUPT;

#endif

/*

* Sanity-check: shared interrupts must pass in a real dev-ID,

* otherwise we'll have trouble later trying to figure out

* which interrupt is which (messes up the interrupt freeing

* logic etc).

*/

if ((irqflags & IRQF_SHARED) && !dev_id) /* 使用共用中斷但沒有提供非NULL的dev_id則返回錯誤 */

return -EINVAL;

if (irq >= NR_IRQS) /* 中斷號超出最大值 */

return -EINVAL;

if (irq_desc[irq].status & IRQ_NOREQUEST) /* 該中斷號已被使用並且未共用 */

return -EINVAL;

if (!handler)

return -EINVAL;

action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC); /* 動態建立一個irqaction */

if (!action)

return -ENOMEM;

/* 下面幾行是根據request_irq 傳進來的參數對irqaction結構體賦值 */

action->handler = handler;

action->flags = irqflags;

cpus_clear(action->mask);

action->name = devname;

action->next = NULL;

action->dev_id = dev_id;

select_smp_affinity(irq);

retval = setup_irq(irq, action); /* 調用setup_irq註冊該中斷的irqaction結構體 */

if (retval)

kfree(action);

return retval;

}

由上可以看出,request_irq的大致流程為先對申請的中斷線進行安全檢測,然後根據request_irq傳進來的參數,動態建立該中斷對應的irqaction結構體,最後通過setup_irq函數將該irqaction註冊進核心適當的位置。

這兩個函數的使用流程搞清楚了,那麼兩者之間的聯絡也就清楚了:

1) Request_irq的註冊過程包含setup_irq,最終是調用setup_irq。

2) Request_irq比setup_irq多一套錯誤偵測機制,即kmalloc前面3行if語句。

而Setup_irq通常是直接註冊irqaction,並沒針對相應中斷線進行錯誤偵測,如該irq 線是否已經被佔用等。因此setup_irq通常只用在特定的中斷線上,如System timer。除系統時鐘驅動外,大部份驅動還是通過request_irq註冊中斷。

這裡有個小問題:

既然Request_irq實際上就是包含了setup_irq的註冊過程,那系統時鐘驅動(GP Timer Driver)中斷可以用request_irq來註冊嗎?

做個小實驗, 將s3c2410 timer驅動的setup_irq那行去掉,改為用request_irq註冊。

修改後代碼如下:

static void __init s3c2410_timer_init (void)

{

s3c2410_timer_setup();

//setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);

request_irq(IRQ_TIMER4, s3c2410_timer_interrupt,

IRQF_DISABLED | IRQF_TIMER, "S3C2410 Timer Tick", NULL);

}

編譯運行。

結果:核心掛掉

為什麼呢?很明顯,系統時鐘驅動中斷不能用request_irq註冊,大致搜了一下源碼也發現,看到其他平台相關的時鐘驅動中斷部分都是用的setup_irq註冊的。

我們來分析一下原因。

看看request_irq和setup_irq 還有哪些細節不一樣?

仔細觀察後注意到request_irq內有這麼一行代碼:

action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);

作用為動態建立一個irqaction。

Kmalloc實際上也是使用的slab機制進行分配的。源碼如下:

/* include/linux/slab.h */

static inline void *kmalloc(size_t size, gfp_t flags)

{

if (__builtin_constant_p(size)) {

int i = 0;

#define CACHE(x) \

if (size <= x) \

goto found; \

else \

i++;

#include "kmalloc_sizes.h"

#undef CACHE

{

extern void __you_cannot_kmalloc_that_much(void);

__you_cannot_kmalloc_that_much();

}

found:

return kmem_cache_alloc((flags & GFP_DMA) ?

malloc_sizes[i].cs_dmacachep :

malloc_sizes[i].cs_cachep, flags);

}

return __kmalloc(size, flags);

}

使用slab機制分配記憶體必須先對slab進行初始化,包括mem_init和kmem_cache_init。

看看kernel的初始化流程:

/* init/main.c */

asmlinkage void __init start_kernel(void)

{

……

time_init();

……

vfs_caches_init_early();

cpuset_init_early();

mem_init(); ß------ initializes the memory data structures

kmem_cache_init(); ß---- set up the general caches

……

}

Time_init函數在mem_init和kmem_cache_init之前被調用,而time_init會調用體繫結構相關部分系統時鐘驅動的初始化函數。拿s3c2410的例子來說,time_init最終會調用s3c2410_timer_init函數,進行s3c2410時鐘驅動的初始化和註冊中斷處理函數。

具體過程如下:

time_init函數定義在arch/arm/kernel/time.c內:

void __init time_init(void)

{

#ifndef CONFIG_GENERIC_TIME

if (system_timer->offset == NULL)

system_timer->offset = dummy_gettimeoffset;

#endif

system_timer->init(); ß-這行實際執行的就是s3c2410_timer_init

#ifdef CONFIG_NO_IDLE_HZ

if (system_timer->dyn_tick)

system_timer->dyn_tick->lock = SPIN_LOCK_UNLOCKED;

#endif

}

system_timer在setup_arch(arch/arm/kernel/setup.c)內通過map_desc機制被初始化為s3c24xx_timer. 如上面s3c2410時鐘驅動代碼所示,s3c24xx_timer的init成員即指向s3c2410_timer_init函數。

現在我們搞清楚了,我們大概的估計是系統時鐘驅動(GP Timer Driver)的中斷處理函數不能用request_irq註冊是因為request_irq內會調用kmalloc動態分配記憶體建立timer的irqaction結構體。而kmalloc也是使用的slab記憶體配置機制,使用kmalloc前必須先對kernel的slab以及mem data structure進行初始化。而這部分初始化工作是在系統時鐘驅動初始化之後才進行的,所以造成kmalloc失敗,從而造成系統時鐘驅動的中斷未註冊成功,進而核心掛掉。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.