Interrupt Programming in Linux

Slides:



Advertisements
Similar presentations
제10장 디바이스 드라이버.
Advertisements

When Poll is Better than Interrupt
Vision System Lab, Sang-Hun Han
* 07/16/96 처음으로 배우는 C 프로그래밍 제1부 기초 제1장 시작하기 *.
KEY 디바이스 드라이버 Lecture #12. 2 차례 GPIO 및 Control Registers KEY 하드웨어 구성 KEY Driver 프로그램 key-driver.c 시험 응용 프로그램 key-app.c.
6주차:『GPU(CUDA) Programming』
C++ Tutorial 1 서강대학교 데이터베이스 연구실.
Mar OSEK/VDK Woo Dong Kyun.
ROBOTICS LAB. DSP TMS320F2812 ROBOTICS LAB.
Project #2-2. Pintos User Program
Chapter 7 ARP and RARP.
인터럽트 종류 인터럽트 요구시 I/O장치 인식 방법
Linux/UNIX Programming
Linux/UNIX Programming APUE (The Environment of a UNIX Process)
제 4 장 프로세스 Section 1 프로세스의 개념 Section 2 프로세스 스케줄링
제 2장 컴퓨터 구조.
기본 컴퓨터 프로그래밍 Lecture #6.
C 프로그래밍 소개 숙명여대 창병모 2011 가을.
10장 주변장치 (PIO) Slide 1 (of 28).
System Call Linux Kernel 수업 3번째.
7장 : 캐시와 메모리.
Internet Computing KUT Youn-Hee Han
3장 MPU 내부구조 Slide 1 (of 28).
임베디드 하드웨어 Lecture #6.
FUSING.
디바이스 드라이버 기초 디바이스 드라이버의 개요 파일 연산 디바이스 드라이버 등록 디바이스 드라이버 구성
디바이스 드라이버.
PCI가 어렵울 거라는 생각을 지금부터 버리도록 합시다.
디바이스 드라이버 개요 가상 디바이스드라이버 실습
PXA255-FPGA 장비 개요 및 실습 Lecture #9.
PXA255-FPGA 장비 계요 및 실습 Lecture #9.
MicroC/OS-II Lab. 경희대학교 컴퓨터공학과 조 진 성.
출처: IT CookBook, 컴퓨터 구조와 원리 2.0 제 12장
컴퓨터 구조.
4장. 컴퓨터 시스템의 구성과 기능 다루는 내용 컴퓨터 분해를 통한 본체 살펴보기 컴퓨터 구성요소 컴퓨터의 기능
FND (Flexible Numeric Display)
Embedded System Porting (2)
[INA240] Data Structures and Practice
Chapter 10. Interrupt.
Step Motor Device Driver
Lecture #3 프로세스(Process).
8086 프로세서의 구조 및 동작 방식 시스템 프로그래밍 - Lecture #2 신라대학교 컴퓨터공학과 시스템 프로그래밍.
커널 모듈 프로그래밍 (Kernel Module Programming)
HBE-SMIII-SV210 리눅스 커널과 디바이스 드라이버
전자의료시스템 및 실습 C-언어 구 환 경희대학교 전자정보대학 동서의료공학과.
임베디드 소프트웨어 설계.
Chapter 4 The Von Neumann Model.
adopted from KNK C Programming : A Modern Approach
컴퓨터 시스템 개관 시스템 프로그래밍 - Lecture #1 신라대학교 컴퓨터공학과 시스템 프로그래밍.
문자 디바이스 드라이버 임베디드 시스템.
8장 후반부 처리와 지연된 작업 Sang-bok, Heo.
Linux/UNIX Programming
운영체제 (Operating Systems) (Memory Management Strategies)
Introduction to Programming Language
리눅스 디바이스 드라이버 (Linux Device Driver)
Computer System Overview
Stepper Motor 디바이스 드라이버
Machine architecture Programming Language Design and Implementation (4th Edition) by T. Pratt and M. Zelkowitz Prentice Hall, 2001 Chapter 2.
Linux/UNIX Programming
Operating System Multiple Access Chatting Program using Multithread
Signature, Strong Typing
Signature, Strong Typing
Signature, Strong Typing
Machine architecture Programming Language Design and Implementation (4th Edition) by T. Pratt and M. Zelkowitz Prentice Hall, 2001 Chapter 2.
Machine architecture Programming Language Design and Implementation (4th Edition) by T. Pratt and M. Zelkowitz Prentice Hall, 2001 Chapter 2.
I/O Management and Disk Scheduling
C.
임베디드 하드웨어 Lecture #6.
Lecture 7 7-Segment LED controller using u-controller
Chapter 7: Deadlocks.
Presentation transcript:

Interrupt Programming in Linux 경희대학교 컴퓨터공학과 조 진 성

주요 내용 주요 내용 인터럽트 개념 PXA255 CPU에서의 인터럽트 하드웨어 리눅스에서의 인터럽트 처리 인터럽트 프로그래밍 예

인터럽트 인터페이스 intr request status reg CPU intr ack mechanism IR PC 임베디드 시스템의 실시간성 요구에 필수적인 요소 CPU status reg data mechanism PC intr request intr ack data/address IR

인터럽트 Suppose a peripheral intermittently receives data, which must be serviced by the processor The processor can poll the peripheral regularly to see if data has arrived – wasteful The peripheral can interrupt the processor when it has data Requires an extra pin or pins: Int If Int is 1, processor suspends current program, jumps to an Interrupt Service Routine (ISR) Known as interrupt-driven I/O Essentially, “polling” of the interrupt pin is built-into the hardware, so no extra time!

인터럽트 What is the address (interrupt address vector) of the ISR? Fixed interrupt Address built into microprocessor, cannot be changed Either ISR stored at address or a jump to actual ISR stored if not enough bytes available Vectored interrupt Peripheral must provide the address Common when microprocessor has multiple peripherals connected by a system bus Compromise: interrupt address table

인터럽트 기반 I/O(fixed ISR location) 1(a): μP is executing its main program. 1(b): P1 receives input data in a register with address 0x8000. 2: P1 asserts Int to request servicing by the microprocessor. 3: After completing instruction at 100, μP sees Int asserted, saves the PC’s value of 100, and sets PC to the ISR fixed location of 16. 4(a): The ISR reads data from 0x8000, modifies the data, and writes the resulting data to 0x8001. 5: The ISR returns, thus restoring PC to 100+1=101, where μP resumes executing. 4(b): After being read, P1 de-asserts Int. Time

인터럽트 기반 I/O(fixed ISR location) 1(a): P is executing its main program 1(b): P1 receives input data in a register with address 0x8000. μP P1 P2 System bus Int Data memory 0x8000 0x8001 16: MOV R0, 0x8000 17: # modifies R0 18: MOV 0x8001, R0 19: RETI # ISR return ISR 100: 101: instruction ... Main program Program memory PC

인터럽트 기반 I/O(fixed ISR location) 2: P1 asserts Int to request servicing by the microprocessor μP P1 P2 System bus Data memory 0x8000 0x8001 16: MOV R0, 0x8000 17: # modifies R0 18: MOV 0x8001, R0 19: RETI # ISR return ISR 100: 101: instruction ... Main program Program memory PC Int 1 Int

인터럽트 기반 I/O(fixed ISR location) 3: After completing instruction at 100, P sees Int asserted, saves the PC’s value of 100, and sets PC to the ISR fixed location of 16. μP P1 P2 System bus Data memory 0x8000 0x8001 16: MOV R0, 0x8000 17: # modifies R0 18: MOV 0x8001, R0 19: RETI # ISR return ISR 100: 101: instruction ... Main program Program memory PC Int 100

인터럽트 기반 I/O(fixed ISR location) 4(a): The ISR reads data from 0x8000, modifies the data, and writes the resulting data to 0x8001. 4(b): After being read, P1 deasserts Int. μP P1 P2 System bus Data memory 0x8000 0x8001 16: MOV R0, 0x8000 17: # modifies R0 18: MOV 0x8001, R0 19: RETI # ISR return ISR 100: 101: instruction ... Main program Program memory PC Int System bus P1 0x8000 P2 0x8001 Int P1 100

인터럽트 기반 I/O(fixed ISR location) 5: The ISR returns, thus restoring PC to 100+1=101, where P resumes executing. μP P1 P2 System bus Data memory 0x8000 0x8001 16: MOV R0, 0x8000 17: # modifies R0 18: MOV 0x8001, R0 19: RETI # ISR return ISR 100: 101: instruction ... Main program Program memory PC Int 100 +1

인터럽트 기반 I/O(vectored interrupt) 1(a): μP is executing its main program. 1(b): P1 receives input data in a register with address 0x8000. 2: P1 asserts Int to request servicing by the microprocessor. 3: After completing instruction at 100, μP sees Int asserted, saves the PC’s value of 100, and asserts Inta. 5(a): μP jumps to the address on the bus (16). The ISR there reads data from 0x8000, modifies the data, and writes the resulting data to 0x8001. 6: The ISR returns, thus restoring PC to 100+1=101, where μP resumes executing. 5(b): After being read, P1 deasserts Int. Time 4: P1 detects Inta and puts interrupt address vector 16 on the data bus.

인터럽트 기반 I/O(vectored interrupt) 1(a): P is executing its main program 1(b): P1 receives input data in a register with address 0x8000. μP P1 P2 System bus Data memory 0x8000 0x8001 16: MOV R0, 0x8000 17: # modifies R0 18: MOV 0x8001, R0 19: RETI # ISR return ISR 100: 101: instruction ... Main program Program memory PC 100 Int Inta 16

인터럽트 기반 I/O(vectored interrupt) 2: P1 asserts Int to request servicing by the microprocessor μP P1 P2 System bus Data memory 0x8000 0x8001 16: MOV R0, 0x8000 17: # modifies R0 18: MOV 0x8001, R0 19: RETI # ISR return ISR 100: 101: instruction ... Main program Program memory PC 100 Inta 16 1 Int Int

인터럽트 기반 I/O(vectored interrupt) 3: After completing instruction at 100, μP sees Int asserted, saves the PC’s value of 100, and asserts Inta μP P1 P2 System bus Data memory 0x8000 0x8001 16: MOV R0, 0x8000 17: # modifies R0 18: MOV 0x8001, R0 19: RETI # ISR return ISR 100: 101: instruction ... Main program Program memory PC Int Inta 16 100 1

인터럽트 기반 I/O(vectored interrupt) 4: P1 detects Inta and puts interrupt address vector 16 on the data bus μP P1 P2 System bus Data memory 0x8000 0x8001 16: MOV R0, 0x8000 17: # modifies R0 18: MOV 0x8001, R0 19: RETI # ISR return ISR 100: 101: instruction ... Main program Program memory PC Int Inta 16 16 System bus 100

인터럽트 기반 I/O(vectored interrupt) 5(a): PC jumps to the address on the bus (16). The ISR there reads data from 0x8000, modifies the data, and writes the resulting data to 0x8001. 5(b): After being read, P1 deasserts Int. μP P1 P2 System bus Data memory 0x8000 0x8001 16: MOV R0, 0x8000 17: # modifies R0 18: MOV 0x8001, R0 19: RETI # ISR return ISR 100: 101: instruction ... Main program Program memory PC Int Inta 16 100

인터럽트 기반 I/O(vectored interrupt) 6: The ISR returns, thus restoring the PC to 100+1=101, where the μP resumes μP P1 P2 System bus Data memory 0x8000 0x8001 16: MOV R0, 0x8000 17: # modifies R0 18: MOV 0x8001, R0 19: RETI # ISR return ISR 100: 101: instruction ... Main program Program memory PC Int 100 +1

Interrupt address table Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesn’t provide ISR address, but rather index into table Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Additional interrupt issues Maskable vs. non-maskable interrupts Maskable: programmer can set bit that causes processor to ignore interrupt Important when in the middle of time-critical code Non-maskable: a separate interrupt pin that can’t be masked Typically reserved for drastic situations, like power failure requiring immediate backup of data to non-volatile memory Jump to ISR Some microprocessors treat jump same as call of any subroutine Complete state saved (PC, registers) – may take hundreds of cycles Others only save partial state, like PC only Thus, ISR must not modify registers, or else must save them first Assembly-language programmer must be aware of which registers stored

PXA255 General Purpose I/O Block Diagram Pin Direction Register(GPDR) Alternate Function Register(GAFR) Pin Set Registers(GPSR) Edge Detect Status Register(GEDR) Rising Edge Detect Enable Register(GRER) Falling Edge Detect Enable Register(GFER) Edge Detect Pin-Level Register(GPLR) 1 Alternate Function (Output) Alternate Function (Input) Pin Clear Registers(GPCR) 2 3 Power Manager Sleep Wake-up logic 0x40E0_000C/10/14 GPDR 1 : 출력 0 : 입력 0x40E0_0054/58/5C 0x40E0_0060/64/68 Base Address 0x40E0_0000 0x40E0_0048/4C/50 0x40E0_0030/34/38 0x40E0_003C/40/44 0x40E0_0000/04/08 세부적인 내용은 Embedded SW I 참조 GPIO 는 총 84개가 존재한다. Intel PXA255 Developer’s Manual Page 4-1. 참조 GPDR - GPIO Pin Direction Registers (GPDR0, GPDR1, GPDR2) GAFR - GPIO Alternate Function Register (GAFR0_L, GAFR0_U, GAFR1_L,GAFR1_U,GAFR2_L,GAFR2_U) GPSR - GPIO Pin Output Set Register GPCR - GPIO Pin Output Clear Register GEDR - GPIO Edge Detect Status Register GRER - GPIO Rising Edge Detect Enable Register GFER - GPIO Falling Edge Detect Enable Register GPLR - GPIO Pin Level Register

PXA255 Interrupt controller Level Register(ICLR) All Other Qualified interrupt Bits 0 : IRQ 1 : FIQ 40D0 0008 XScale CORE 23 23 CCR[DIM]=0 & IDLE mode=‘1’ Interrupt Controller Mask Register (ICMR) 40D0 0004 FIQ Interrupt Source Bit CPSR.6(F) Interrupt Controller Pending Register (ICPR) 40D0 0010 IRQ Interrupt Controller IRQ Pending Register (ICIP) CPSR.7(I) 40D0 0000 Intel PXA255 Developer’s Manual Page 4-20. 참조 ICIP - Interrupt Controller IRQ Pending register ICFP - Interrupt Controller FIQ Pending register ICPR - Interrupt Controller Pending register ICMR - Interrupt Controller Mask register ICLR - Interrupt Controller Level register ICCR - Interrupt Controller Control register Interrupt Controller FIQ Pending Register (ICFP) 40D0 000C 40D0 0014 : Interrupt controller control register (ICCR) ICCR.0 : disable idle mask(DIM)

Interrupt Controller(2) All interrupts routed to FIQ or IRQ Two level interrupt structure 1. What module caused interrupt Serial channel, DMA, Power Management, etc 2. Why did an interrupt occur there? RX, TX, over-run, under-run, Data Done, Battery Fault, etc Template for servicing interrupts provided with firmware Peripheral/PCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

ICMR(Interrupt Controller Mask Register) 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 0000 0000 0000 000? ?000 0000 ???? ???? IM31 – IM28 IM27 – IM24 IM23 – IM20 IM19 – IM17 IM14 – IM12 IM11 – IM8 Reserved IM[x] Interrupt Mask ‘x’ (where x= 8 through 14 and 17 through 31). 0 – Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or Power Manager). 1 – Pending interrupt is allowed to become active (interrupts are sent to CPU and Power Manager). NOTE: In idle mode, the IM bits are ignored if ICCR[DIM] is cleared. Reserved[0-7, 15, 16] Physical Address : 0x40D0/0004  

ICLR(Interrupt Controller Level Register) 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 0000 0000 0000 000# #000 0000 #### #### IL31 – IL28 IL27 – IL24 IL23 – IL20 IL19 – IL17 IL14 – IL12 IL11 – IL8 Reserved IL[x] Interrupt Level ‘x’ (where n = 8 through 14 and 17 through 31). 0 – Interrupt routed to IRQ interrupt input. 1 – Interrupt routed to FIQ interrupt input. Reserved[0-7, 15, 16] Physical Address : 0x40D0/0008  

ICCR(Interrupt Controller Control Register) 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ???? ???? ???? ???? ???? ???? ???? ???X Reserved DIM DIM[0] Disable Idle mask. 0 – All enabled interrupts bring the processor out of idle mode. 1 – Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle mode. This bit is cleared during all resets. Reserved[31:1] Physical Address : 0x40D0/0014  

ICIP(Interrupt Controller IRQ Pending Register) 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 0000 0000 0000 000? ?000 0000 ???? ???? IP31 – IP28 IP27 – IP24 IP23 – IP20 IP19 – IP17 IP14 – IP12 IP11 – IP8 Reserved IP[x] : IRQ Pending x (where x = 8 through 14 and 17 through 31). 0 – IRQ NOT requested by any enabled source. 1 – IRQ requested by an enabled source. Reserved[0-7, 15, 16] Physical Address : 0x40D0/0000  

ICFP(Interrupt Controller FIQ Pending Register) 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 0000 0000 0000 000? ?000 0000 ???? ???? FP31 – FP28 FP27 – FP24 FP23 – FP20 FP19 – FP17 FP11 – FP8 Reserved FP14 – FP12 FP[x] : FIQ Pending x (where x = 8 through 14 and 17 through 31). 0 – FIQ NOT requested by any enabled source. 1 – FIQ requested by an enabled source. Reserved[0-7, 15, 16] Physical Address : 0x40D0/000C  

ICPR(Interrupt Controller Pending Register) 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 0000 0000 0000 000? ?000 0000 ???? ???? IS31 – IS28 IS27 – IS24 IS23 – IS20 IS19 – IS17 IS11 – IS8 Reserved IS14 – IS12 a 32-bit read-only register that shows all active interrupts in the system. These bits are not affected by the state of the mask register (ICMR). Clearing the interrupt status bit at the source, automatically clears the corresponding ICPR flag, provided there are no other interrupt status bits set within the source unit. Table 4-36 참조 Physical Address : 0x40D0/0010  

Why Bottom Halves ? Because interrupt handlers …. run asynchronously and thus interrupt other potentially important code(even other interrupt handlers) run with current interrupt level disabled at best, and at worst (if SA_INTERRUPT set) with all interrupts disabled are often timing-critical because they deal with hardware cannot block Consequently, managing interrupts is divided into two parts (or halves) Some useful tips about how to divide work between top and bottom half if the work is time-sensitive if the work is related to the hardware itself if the work needs to ensure that another interrupt (particularly the same interrupt) does not interrupt it 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Bottom Halves in Linux 2.4 the future when the system is less busy and interrupts are enabled again Three types of bottom halves in 2.4 softirq, tasklet, BH operations on deferrable functions initialization activation masking execution (* activation and execution on the same CPU ? ) 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Bottom Halves in Linux 2.4 History of bottom half status in Linux BH removed in 2.5 Task queues removed in 2.5 Softirq available since 2.3 Tasklet available since 2.3 Work queues available since 2.5 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Softirqs Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible) irq_stat /* structure representing a softirq entry */ /* (linux/interrupt.h) */ struct softirq_action { void (*action) (struct softirq_action *); void *data; / }; /* 32-entry array of softirq_action (kernel/softirq.c) */ static struct softirq_action softirq_vec[32]; typedef struct { unsigned int __softirq_pending; unsigned int __local_irq_count; unsigned int __local_bh_count; unsigned int __syscall_count; struct task_struct *__ksoftirqd_task; unsigned int __nmi_count; } irq_cpustat_t; irq_cpustat_t irq_stat[NR_CPUS]; 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Softirqs Softirq handler Remember that with entire softirq_action as argument (why ?) (ex) void net_tx_action(struct softirq_action *h) { } void net_rx_action(struct softirq_action *h) { } Remember that A softirq handler run with interrupts enabled and cannot sleep. softirqs on current CPU are disabled an interrupt handler can preempt a softirq Another softirq can run on another CPU. Four softirqs used in 2.4 (six in 2.6) HI_SOFTIRQ / TIMER_SOFTIRQ / NET_TX_SOFTIRQ / NET_RX_SOFTIRQ / SCSI_SOFTIRQ /(…)/ TASKLET_SOFTIRQ 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Softirqs Registering softirq handler at run-time by open_softirq( ) open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL); open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL); Raising softirq by raise_softirq( ) (usually, an interrupt handler raises its softirq before returning) raise_softirq(NET_TX_SOFTIRQ); Checking for pending softirqs (kernel version / supported hardware) After processing a hardware interrupt When one of ksoftirqd_CPUn kernel threads is awoken When a packet is received on a NIC When local_bh_enable macro re-enables the softirqs 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Softirqs Executing softirqs : do_softirq( ) if( in_interrupt( ) ) return; local_irq_save( flags ); // disable local INT pending = softirq_pending(cpu); if( pending ){ mask = ~pending; local_bh_disable(cpu); // disable softirq // local_bh_count++ restart: softirq_pending(cpu) = 0; local_irq_enable(); struct softirq_action* h = softirq_vec; do{ if( pending & 1 ) h->action(h); h++; pending >> 1; }while(pending); local_irq_disable(); if( pending & mask ){ mask &= ~pending; goto restart; } local_bh_enable(); if( pending ) wakeup_softirqd(cpu); local_irq_restore( flags ); Executing softirqs : do_softirq( ) local_irq_count(cpu) = = 0 ? // nested ? local_bh_count(cpu) = = 0 ? // enabled ? serializing execution on a CPU softirq not processed in this invocation ? // goto restart only if different types // goto wakeup_softirqd(cpu) if same softirq re-activated 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Kernel Thread : ksoftirqd_CPUn Softirq kernel thread for each CPU Q: what if softirqs raised or re-activated at very high frequency ? either ignore new softirqs that occur while do_softirq( ) is running long softirq latency (even on idle machine) or continuous re-checking for pending softirqs user starving (long response time) softirq kernel threads ksoftirqd_CPUn at low priority give user a priority but run immediately on idle for (; ;) { set_current_state(TASK_INTERRPTIBLE); schedule( ); // now in TASK_RUNNING state while (softirq_pending(cpu)) { do_doftirq( ); if (current->need_resched) } 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Tasklets Implemented on top of softirqs: HI_SOFTIRQ, TASKLET_SOFTIRQ Tasklet structure (linux/interrupt.h) tasklet_vec[NR_CPUS] and tasklet_hi_vec[NR_CPUS] to store scheduled tasklets (like raised softirqs) for regular tasklets and high-priority tasklets struct tasklet_struct { struct tasklet_struct *next; // pointer to next tasklet in the list unsigned long state; // state of the tasklet : 0, SCHED, RUN atomic_t count; // enable (0) /disable (nonzero) tasklet void (*func)(unsigned long); // tasklet handler function unsigned long data; // argument to tasklet function } 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Tasklets Declaring your tasklets statically (linux/interrupt.h) dynamically DECLARE_TASKLET(name, func, data) / DECLARE_TASKLET_DISABLED( ) (ex) DECLARE_TASKLET(my_tasklet, my_tasklet_handler, dev); struct tasklet_struct my_tasklet = { NULL, 0, ATOMIC_INIT(0), my_tasklet_handler, dev}; open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL); open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL); 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈.. void tasklist_init(struct tasklet_struct *t, tasklet_handler, dev);

Tasklets Writing your tasklet handler Remember that Tasklets cannot sleep if a tasklet share any data with an interrupt handler ? (tasklets run with all interrupts enabled) if a tasklet shares data with another tasklet or softirq ? void tasklet_handler(unsigned long data) { ….; } 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Tasklets Activating your tasklet tasklet_schedule( ) / tasklet_hi_schedule( ) tasklet_schedule(&my_tasklet); /* mark my_tasklet as pending */ static void tasklet_schedule(struct tasklet_struct *t) { 1. if TASKLET_STATE_SCHED is set, returns; /* already been scheduled ? */ otherwise set TASKLET_STATE_SCHED flag; 2. local_irq_save( flags); // save the state of interrupt system and disable local interrupts 3.insert the tasklet to the head of tasklet_vec or tasklet_hi_vec; 4. raise TASKLET_SOFTIRQ or HI_SOFTIRQ softirq; 5. local_irq_restore(flags); } 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈.. * what if the same tasklet is scheduled again ? * what if it is already running on another CPU ?

Tasklets Handling tasklets via tasklet_action( ) : TASKLET_SOFTIRQ static void tasklet_action(struct softirq_action *a) { 1. disable local interrupts; 2. list = the address of the list pointed to by tasklet_vec[cpu]; 3. put NULL in tasklet_vec[cpu]; // list of scheduled tasklets is emptied // 4. enable local interrupts; 5. for each tasklet decriptor in the list a. if TASKLET_STATE_RUN set, // tasklet of the same type on another CPU reinsert the tasklet descriptor in the list of tasklet_vec[cpu] and activate TASKLET_SOFTIRQ again; otherwise, set TASKLET_STATE_RUN (in SMP) b. if the tasklet is disabled (count <> 0 ?) reinsert and activate TASKLET_SOFTIRQ; // defer tasklet otherwise, clear TASKLET_STATE_SCHED and execute the tasklet function; } 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Tasklets Controlling tasklets Enable / Disable tasklets tasklet_enable( ) / tasklet_disable( ) Remove a tasklet from the pending queue tasklet_kill( ) tasklet_disable(&my_tasklet); /* we can now do stuff knowing that the tasklet cannot run .. */ tasklet_enable(&my_tasklet); 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Tasklets In summary, In most cases, tasklets are preferred way to implement a bottom half for a normal hardware device Tasklets are dynamically created, easy to use, and relatively quick. 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

BH BH interface : a high-priority tasklet with no concurrency at most one BH is running (global_bh_lock spin lock) only for backward compatibility (Linux 2.2 or older) Note that Each BH must be statically defined and there are max 32 BHs. Modules could not directly use BH interface because BH handlers must be defined at compile-time. All BH handlers are strictly serialized. No two BH handlers (even of different types) can run concurrenlty Easy synchronization, but not good for SMP performance a driver using BH interface does not scale well to SMP 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

BH Task queues a group of kernel functions as a BH ? (task queues) Three particular task queues Immediate queue (run by IMMEDIATE_BH) Timer queue (run by TQUEUE_BH) Scheduler queue (run by keventd kernel thread) (* Linux 2.4 *) Can dynamically create new task queues Later… various queues 􀃆 tasklets scheduler queue + keventd --> “work queue” in 2.6 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

Disabling Bottom Halves Data structures accessed by bottom halves must be protected against race conditions because bottom halves can be executed at any time. A trivial way to disable bottom halves on a CPU is to disable interrupts on that CPU. (no interrupts --> no softirqs) How to disable bottom halves without disabling interrupts ? void local_bh_disable( ) --> __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( ) 리눅스에서는 이 모드를 통해 인터럽트 핸들러 구현 fiq안씀 => 수퍼바이저모드로 바꿈..

GPIO 디바이스 드라이버 GPIO 입력 button를 제어하는 gpio 드라이버 프로그램 소스 예제(gpio.c) #include <linux/kernel.h> /* gpio.c */ #include <linux/module.h> #include <linux/init.h> #include <linux/config.h> #include <linux/sched.h> #include <linux/string.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/types.h> #include <asm/hardware.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/param.h> #define IRQ_BUTTON IRQ_GPIO(16) static void button_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int GPIO_MAJOR = 0; static DECLARE_WAIT_QUEUE_HEAD(wait_queue); GPIO에 할당된 IRQ값과 인터럽트 핸들러 블럭킹 I/O를 위한 대기 큐

GPIO 디바이스 드라이버(2) 대기큐에 있는 프로세스를 깨움 대기큐로 진입 – 블록킹 상태 블록킹이 해제 후 메시지 출력 static void button_interrupt(int irq, void *dev_id, struct pt_regs *regs) { wake_up_interruptible(&wait_queue); } static ssize_t gpio_read(struct file *filp, char *buf, size_t count, loff_t *l) char hello[] = "GPIO_16 port was pushed!"; interruptible_sleep_on(&wait_queue); copy_to_user(buf,&hello,sizeof(hello)); return 0; static int gpio_open(struct inode *inode, struct file *filp) int res; unsigned int gafr; gafr = 0x3; GAFR0_U &= ~gafr; printk("IRQ_BUTTON = %d\n",IRQ_BUTTON); printk("IRQ_TO_GPIO =%d\n",IRQ_TO_GPIO_2_80(IRQ_BUTTON)); GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) &= ~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON)); set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON), GPIO_FALLING_EDGE); 대기큐에 있는 프로세스를 깨움 (버튼이 눌러졌을 때) 대기큐로 진입 – 블록킹 상태 (버튼이 눌러지길 기다림) 블록킹이 해제 후 메시지 출력 16번포트의 GAFR설정 해제 16번 포트를 출력으로 설정과 및 에지 신호 설정

GPIO 디바이스 드라이버(3) 인터럽트 핸들러 설치 인터럽트를 활성화 설정된 irq를 설정 해제한다 res = request_irq(IRQ_BUTTON,&button_interrupt,SA_INTERRUPT, "Button",NULL); if(res < 0) printk(KERN_ERR "%s: Request for IRQ %d failed\n", __FUNCTION__,IRQ_BUTTON); else { enable_irq(IRQ_BUTTON); } MOD_INC_USE_COUNT; return 0; static int gpio_release(struct inode *inode, struct file *filp) { free_irq(IRQ_BUTTON,NULL); disable_irq(IRQ_BUTTON); MOD_DEC_USE_COUNT; static struct file_operations gpio_fops = { read: gpio_read, open: gpio_open, release: gpio_release }; 인터럽트 핸들러 설치 인터럽트를 활성화 설정된 irq를 설정 해제한다

GPIO 디바이스 드라이버(4) int init_module(void) { int result; result = register_chrdev(GPIO_MAJOR,"GPIOINTERRUPT",&gpio_fops); if(result < 0) { printk(KERN_WARNING"Can't get major %d\n",GPIO_MAJOR); return result; } if(GPIO_MAJOR == 0) GPIO_MAJOR = result; printk("init module, GPIO major number : %d\n",result); return 0; void cleanup_module(void) unregister_chrdev(GPIO_MAJOR,"GPIO INTERRUPT"); return;

GPIO 디바이스 드라이버 응용 프로그램 gpio장치를 open 버튼이 눌러지길 기다림 (블록킹 상태가 됨) #include <stdio.h> /* test.c */ #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> static int dev; int main(void) { char buff[40]; dev = open("/dev/gpio",O_RDWR); if(dev < 0) { printf( "Device Open ERROR!\n"); exit(1); } printf("Please push the GPIO_16 port!\n"); read(dev,buff,40); printf("%s\n",buff); close(dev); return 0; gpio장치를 open 버튼이 눌러지길 기다림 (블록킹 상태가 됨)

Makefile 작성 예 # led Device Driver Makefile /* Makefile */ CC = arm-linux-gcc KERNELDIR = /usr/src/linux-2.4.19 INCLUDEDIR = -I$(KERNELDIR)/include CFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR) MODULE_OBJS = gpio.o MODULE_SRCS = gpio.c TEST_TARGET = test TEST_OBJS = test.o TEST_SRCS = test.c all: $(MODULE_OBJS) $(TEST_TARGET) $(TEST_TARGET) : $(TEST_OBJS) $(CC) $(TEST_OBJS) -o $@ clean: rm -f *.o rm -f $(TEST_TARGET)

GPIO 디바이스 드라이버 실행 GPIO 디바이스 드라이버 컴파일 방법 GPIO 디바이스 드라이버 실행 방법 생성된 gpio.o와 test파일을 타겟 보드로 전송 insmod로 드라이버를 커널에 loading mknod를 통해 특수 장치 파일을 만듦 응용프로그램을 실행 $ make $ insmod gpio.o Using gpio.o init module, GPIO major number : 252 $ mknod /dev/gpio c 252 0 $ ./test

GPIO 디바이스 드라이버 실행 예 디바이스 드라이버 컴파일 디바이스 드라이버 실행