<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

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

          ARM Linux中斷機(jī)制之中斷的初始化

          作者: 時間:2016-11-10 來源:網(wǎng)絡(luò) 收藏
          一,認(rèn)識幾個重要結(jié)構(gòu)體:

          1.中斷描述符

          本文引用地址:http://www.ex-cimer.com/article/201611/317087.htm

          對于每一條中斷線都由一個irq_desc結(jié)構(gòu)來描述。

          //在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中實現(xiàn)了5個函數(shù):handle_simple_irq(),handle_level_irq(),
          handle_edge_irq(),handle_fasteoi_irq()以及handle_percpu_irq()。 handle_irq指針可
          以指向這5個函數(shù)中的一個, 選擇一種中斷事件處理策略, 這是通過函數(shù)set_irq_handler()
          完成的

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

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

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

          unsigned intdepth;
          unsigned intwake_depth;////* 喚醒次數(shù) */
          unsigned intirq_count;/* 發(fā)生的中斷次數(shù) */
          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 中顯示的中斷名稱
          } ____cacheline_internodealigned_in_smp;


          /*在kernel/irq/handle.c中有個全局irq_desc數(shù)組,描述了系統(tǒng)中所有的中斷線:

          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為最大中斷數(shù)對于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)//每一個中斷源都對應(yīng)一個irq_desc結(jié)構(gòu)體。
          #endif

          */

          2. 中斷硬件操作函數(shù)集

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

          //該結(jié)構(gòu)體中各函數(shù)在文件linux/arch/arm/plat-s3c24xx/irq.c中實現(xiàn)

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

          void(*ack)(unsigned int irq);//響應(yīng)一個中斷,清除中斷標(biāo)志
          void(*mask)(unsigned int irq);//mask 一個中斷源,通常是關(guān)閉中斷
          void(*mask_ack)(unsigned int irq);//響應(yīng)并 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);//設(shè)置中斷觸發(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;//用一組標(biāo)志描述中斷線與 I/O 設(shè)備之間的關(guān)系。
          cpumask_t mask;
          const char *name;/* 名稱,會顯示在/proc/interreupts中 */
          void *dev_id;/* 設(shè)備ID,用于區(qū)分共享一條中斷線的多個處理程序 ,以便從共享中斷線的諸多中斷處理程序中刪除指定的那一個*/
          struct irqaction *next;/* 指向下一個irq_action結(jié)構(gòu) */
          int irq;/* 中斷通道號 */
          struct proc_dir_entry *dir; /* procfs目錄 */
          irq_handler_t thread_fn;
          struct task_struct *thread;
          unsigned long thread_flags;
          };

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

          二,中斷初始化過程
          中斷機(jī)制的初始化通過 兩個函數(shù)完成:early_trap_init()和init_IRQ(),在此我們先討論函數(shù)init_IRQ()。
          //函數(shù)init_IRQ在文件linux/arch/arm/kernel/irq.c中實現(xiàn)。
          void __init init_IRQ(void)
          {
          int irq;
          /* 設(shè)置 irq_desc 數(shù)組的 status 為 IRQ_NOREQUEST | IRQ_NOPROBE(沒有請求,沒有檢測) */
          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;
          該函數(shù)指針在 setup_arch()中被賦值,
          init_arch_irq = mdesc->init_irq;
          指向 machine_desc 中定義的 init_irq 函數(shù)。
          在平臺smdk2440中,該函數(shù)在文件linux/arch/arm/plat-s3c24xx/irq.c中實現(xiàn)。
          */
          init_arch_irq();
          }
          //函數(shù)s3c24xx_init_irq在文件linux/arch/arm/plat-s3c24xx/irq.c中實現(xiàn)
          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中的請求標(biāo)志,
          printk("irq: clearing pending ext status %08xn", (int)pend);
          last = pend;
          }
          last = 0;

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

          }

          比如此時外部中斷10產(chǎn)生了中斷,中斷號為IRQ_EINT8t23的中斷被觸發(fā),執(zhí)行函數(shù)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);//根據(jù)這個偏移量重新計算中斷號
          generic_handle_irq(irq);//根據(jù)重新計算的中斷號獲取對應(yīng)的結(jié)構(gòu)體irq_desc,并調(diào)用它的上層中斷處理函數(shù)。
          }

          }

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

          上層中斷處理函數(shù)

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

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

          這5個上層中斷處理函數(shù)都是通過調(diào)用函數(shù)handle_IRQ_event()來做進(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);//執(zhí)行中斷處理函數(shù)。


          。。。。。。

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

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

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

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

          /*

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

          #define IRQ_INPROGRESS 1 /* 正在執(zhí)行這個 IRQ 的一個處理程序 */
          #define IRQ_DISABLED 2 /* 由設(shè)備驅(qū)動程序已經(jīng)禁用了這條 IRQ 中斷線 */

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

          */

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

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



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

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();