ARM Linux中断分析以s3c2410为例.docx
- 文档编号:3737948
- 上传时间:2022-11-25
- 格式:DOCX
- 页数:11
- 大小:21.01KB
ARM Linux中断分析以s3c2410为例.docx
《ARM Linux中断分析以s3c2410为例.docx》由会员分享,可在线阅读,更多相关《ARM Linux中断分析以s3c2410为例.docx(11页珍藏版)》请在冰豆网上搜索。
ARMLinux中断分析以s3c2410为例
ARMLinux中断分析(以s3c2410为例)
首先,当然是进入start_kernel,调用setup_arch进行平台体系(处理器芯片)相关的初始化,然后复制中断向量表到内存中并对irq进行初始化
/*init/main.c*/
asmlinkagevoid__initstart_kernel(void)
{
……
setup_arch(&command_line);
……
trap_init();
……
init_IRQ();
……
}
trap_init复制中断向量表到内存地址CONFIG_VECTORS_BASE
/*arch/arm/kernel/traps.c*/
void__inittrap_init(void)
{
unsignedlongvectors=CONFIG_VECTORS_BASE;
externchar__stubs_start[],__stubs_end[];
externchar__vectors_start[],__vectors_end[];
externchar__kuser_helper_start[],__kuser_helper_end[];
intkuser_sz=__kuser_helper_end-__kuser_helper_start;
/*
*Copythevectors,stubsandkuserhelpers(inentry-armv.S)
*intothevectorpage,mappedat0xffff0000,andensurethese
*arevisibletotheinstructionstream.
*/
memcpy((void*)vectors,__vectors_start,__vectors_end-__vectors_start);
memcpy((void*)vectors+0x200,__stubs_start,__stubs_end-__stubs_start);
memcpy((void*)vectors+0x1000-kuser_sz,__kuser_helper_start,kuser_sz);
/*
*Copysignalreturnhandlersintothevectorpage,and
*setsigreturntobeapointertothese.
*/
memcpy((void*)KERN_SIGRETURN_CODE,sigreturn_codes,
sizeof(sigreturn_codes));
flush_icache_range(vectors,vectors+PAGE_SIZE);
modify_domain(DOMAIN_USER,DOMAIN_CLIENT);
}
init_IRQ对irq进行初始化时,又调用了init_arch_irq对于具体平台体系的中断进行初始化。
而init_arch_irq是在start_kernel里调用setup_arch函数设定的
/*arch/arm/kernel/irq.cn*/
void__initinit_IRQ(void)
{
intirq;
for(irq=0;irq irq_desc[irq].status|=IRQ_NOREQUEST|IRQ_NOPROBE; #ifdefCONFIG_SMP bad_irq_desc.affinity=CPU_MASK_ALL; bad_irq_desc.cpu=smp_processor_id(); #endif init_arch_irq(); } setup_arch里指定了具体平台体系的中断初始化函数,其中mdesc是一个machine_desc结构体指针 /*arch/arm/kernel/setup.c*/ void__initsetup_arch(char**cmdline_p) { …… init_arch_irq=mdesc->init_irq; …… } machine_desc是用于描述平台体系(处理器芯片)的结构体,其定义如下: /*include/asm/mach/arch.h*/ structmachine_desc{ /* *Note! Thefirstfourelementsareused *byassemblercodeinhead-armv.S */ unsignedintnr;/*architecturenumber*/ unsignedintphys_io;/*startofphysicalio*/ unsignedintio_pg_offst;/*byteoffsetforio *pagetabeentry*/ constchar*name;/*architecturename*/ unsignedlongboot_params;/*taggedlist*/ unsignedintvideo_start;/*startofvideoRAM*/ unsignedintvideo_end;/*endofvideoRAM*/ unsignedintreserve_lp0: 1;/*neverhaslp0*/ unsignedintreserve_lp1: 1;/*neverhaslp1*/ unsignedintreserve_lp2: 1;/*neverhaslp2*/ unsignedintsoft_reboot: 1;/*softreboot*/ void(*fixup)(structmachine_desc*, structtag*,char**, structmeminfo*); void(*map_io)(void);/*IOmappingfunction*/ void(*init_irq)(void); structsys_timer*timer;/*systemticktimer*/ void(*init_machine)(void); }; /* *Setofmacrostodefinearchitecturefeatures.Thisisbuiltinto *atablebythelinker. */ #defineMACHINE_START(_type,_name)\ staticconststructmachine_desc__mach_desc_##_type\ __used\ __attribute__((__section__(".arch.info.init")))={\ .nr=MACH_TYPE_##_type,\ .name=_name, #defineMACHINE_END\ }; 对于s3c2410处理器芯片,其machine_desc变量的定义如下: /*arch/arm/mach-s3c2410/mach-smdk2410.c*/ MACHINE_START(SMDK2410,"SMDK2410")/*@TODO: requestanewidentifierandswitch *toSMDK2410*/ /*Maintainer: JonasDietsche*/ .phys_io=S3C2410_PA_UART, .io_pg_offst=(((u32)S3C24XX_VA_UART)>>18)&0xfffc, .boot_params=S3C2410_SDRAM_PA+0x100, .map_io=smdk2410_map_io, .init_irq=s3c24xx_init_irq, .init_machine=smdk2410_init, .timer=&s3c24xx_timer, MACHINE_END 接下来,我们看看s3c2410处理器芯片的irq初始化函数 /*arch/arm/plat-s3c24xx/irq.c*/ /*s3c24xx_init_irq * *InitialiseS3C2410IRQsystem */ /*s3c24xx系列芯片中断初始化函数*/ void__inits3c24xx_init_irq(void) { unsignedlongpend; unsignedlonglast; intirqno; inti; irqdbf("s3c2410_init_irq: clearinginterruptstatusflags\n"); /*first,clearallinterruptspending...*/ /*清空各个中断请求信号*/ last=0; for(i=0;i<4;i++){ pend=__raw_readl(S3C24XX_EINTPEND); if(pend==0||pend==last) break; __raw_writel(pend,S3C24XX_EINTPEND); printk("irq: clearingpendingextstatus%08x\n",(int)pend); last=pend; } last=0; for(i=0;i<4;i++){ pend=__raw_readl(S3C2410_INTPND); if(pend==0||pend==last) break; __raw_writel(pend,S3C2410_SRCPND); __raw_writel(pend,S3C2410_INTPND); printk("irq: clearingpendingstatus%08x\n",(int)pend); last=pend; } last=0; for(i=0;i<4;i++){ pend=__raw_readl(S3C2410_SUBSRCPND); if(pend==0||pend==last) break; printk("irq: clearingsubpendingstatus%08x\n",(int)pend); __raw_writel(pend,S3C2410_SUBSRCPND); last=pend; } /*registerthemaininterrupts*/ /*注册主要中断*/ irqdbf("s3c2410_init_irq: registerings3c2410interrupthandlers\n"); for(irqno=IRQ_EINT4t7;irqno<=IRQ_ADCPARENT;irqno++){ /*setallthes3c2410internalirqs*/ switch(irqno){ /*dealwiththespecialIRQs(cascaded)*/ caseIRQ_EINT4t7: caseIRQ_EINT8t23: caseIRQ_UART0: caseIRQ_UART1: caseIRQ_UART2: caseIRQ_ADCPARENT: set_irq_chip(irqno,&s3c_irq_level_chip);/*设置中断操作函数集(电平)*/ set_irq_handler(irqno,handle_level_irq);/*设置中断的高层流处理函数(电平)*/ break; caseIRQ_RESERVED6: caseIRQ_RESERVED24: /*noIRQhere*/ break; default: //irqdbf("registeringirq%d(s3cirq)\n",irqno); set_irq_chip(irqno,&s3c_irq_chip);/*默认中断为边缘触发*/ set_irq_handler(irqno,handle_edge_irq); set_irq_flags(irqno,IRQF_VALID); } } /*setupthecascadeirqhandlers*/ /*设置中断的高层流处理函数*/ 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); /*externalinterrupts*/ for(irqno=IRQ_EINT0;irqno<=IRQ_EINT3;irqno++){ irqdbf("registeringirq%d(extint)\n",irqno); set_irq_chip(irqno,&s3c_irq_eint0t4); set_irq_handler(irqno,handle_edge_irq); set_irq_flags(irqno,IRQF_VALID); } for(irqno=IRQ_EINT4;irqno<=IRQ_EINT23;irqno++){ irqdbf("registeringirq%d(extendeds3cirq)\n",irqno); set_irq_chip(irqno,&s3c_irqext_chip); set_irq_handler(irqno,handle_edge_irq); set_irq_flags(irqno,IRQF_VALID); } /*registertheuartinterrupts*/ irqdbf("s3c2410: registeringexternalinterrupts\n"); for(irqno=IRQ_S3CUART_RX0;irqno<=IRQ_S3CUART_ERR0;irqno++){ irqdbf("registeringirq%d(s3cuart0irq)\n",irqno); set_irq_chip(irqno,&s3c_irq_uart0); set_irq_handler(irqno,handle_level_irq); set_irq_flags(irqno,IRQF_VALID); } for(irqno=IRQ_S3CUART_RX1;irqno<=IRQ_S3CUART_ERR1;irqno++){ irqdbf("registeringirq%d(s3cuart1irq)\n",irqno); set_irq_chip(irqno,&s3c_irq_uart1); set_irq_handler(irqno,handle_level_irq); set_irq_flags(irqno,IRQF_VALID); } for(irqno=IRQ_S3CUART_RX2;irqno<=IRQ_S3CUART_ERR2;irqno++){ irqdbf("registeringirq%d(s3cuart2irq)\n",irqno); set_irq_chip(irqno,&s3c_irq_uart2); set_irq_handler(irqno,handle_level_irq); set_irq_flags(irqno,IRQF_VALID); } for(irqno=IRQ_TC;irqno<=IRQ_ADC;irqno++){ irqdbf("registeringirq%d(s3cadcirq)\n",irqno); set_irq_chip(irqno,&s3c_irq_adc); set_irq_handler(irqno,handle_edge_irq); set_irq_flags(irqno,IRQF_VALID); } irqdbf("s3c2410: registeredinterrupthandlers\n"); } 接着,我们来看一下中断处理过程 /*arch/arm/kernel/irq.c*/ /* *do_IRQhandlesallhardwareIRQ's.DecodedIRQsshouldnot *comeviathisfunction.Instead,theyshouldprovidetheir *own'handler' */ asmlinkagevoid__exceptionasm_do_IRQ(unsignedintirq,structpt_regs*regs) { structpt_regs*old_regs=set_irq_regs(regs);/*保存寄存器中的内容*/ structirq_desc*desc=irq_desc+irq;/*获取中断源*/ /* *Somehardwaregivesrandomlywronginterrupts.Rather *thancrashing,dosomethingsensible. */ if(irq>=NR_IRQS) desc=&bad_irq_desc; irq_enter(); desc_handle_irq(irq,desc);/*调用已安装的中断高层流处理函数*/ /*AT91specificworkaround*/ irq_finish(irq); irq_exit(); set_irq_regs(old_regs); } 接下来,我们以IRQ_UART2(s3c2410串口2中断)为例,看看中断是如何分流到我们通过request_irq注册的中断处理函数 在s3c24xx_init_irq里IRQ_S3CUART_TX2中断的中断高层流处理函数被设置为s3c_irq_demux_uart2。 s3c_irq_demux_uart2主要工作是调用s3c_irq_demux_uart对串口中断进行分流处理,因为串口中断包含Rx(接收)中断、Tx(发送)中断和Rxerror(接收错误)中断 /*arch/arm/plat-s3c2410/irq.c*/ staticvoids3c_irq_demux_uart2(unsignedintirq,structirq_desc*desc) { irq=irq; s3c_irq_demux_uart(IRQ_S3CUART_RX2); } s3c_irq_demux_uart通过副中断源引脚寄存器的值,判断中断源并执行相应的中断处理函数 /*arch/arm/plat-s3c2410/irq.c*/ /*start: 标示发出该中断信号的是哪个uart,即其值应为 *IRQ_S3CUART_RX0、IRQ_S3CUART_RX1或IRQ_S3CUART_RX2 */ staticvoids3c_irq_demux_uart(unsignedintstart) { unsignedintsubsrc,submsk; unsignedintoffset=start-IRQ_S3CUART_RX0;/*获取该UART中断源在副中断屏蔽寄存器中的偏移量*/ structirq_desc*desc; /*readthecurrentpendinginterrupts,andthemask *forwhatitisavailable*/ subsrc=__raw_readl(S3C2410_SUBSRCPND);/*读取副中断源引脚寄存器*/ submsk=__raw_readl(S3C2410_INTSUBMSK);/*读取副中断屏蔽寄存器*/ irqdbf2("s3c_irq_demux_uart: start=%d(%d),subsrc=0x%08x,0x%08x\n", start,offset,subsrc,submsk); subsrc&=~submsk;/*只留下已使能(未屏蔽)的中断源*/ subsrc>>=offset;/*截取发送中断的uart源到subsrc低3位*/ subsrc&=7; if(subsrc! =0) { desc=irq_desc+start; if(subsrc&1)/*Rx中断*/ desc_handle_irq(start,desc); desc++; if(subsrc&2)/*Tx中断*/ desc_handle_irq(start+1,desc); desc++; if(subsrc&4)/*Rxerror中断*/ desc_handle_irq(start+2,desc); } } desc_handle_irq实际上只是调用了de
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ARM Linux中断分析以s3c2410为例 Linux 中断 分析 s3c2410