12. 인터럽트 처리

Download Report

Transcript 12. 인터럽트 처리

12. 인터럽트 처리
김진홍
[email protected]
2015.11.30.
목차
1. 인터럽트
2. 인터럽트 발생 시간 체크
2/13
1. 인터럽트
인터럽트란
• 인터럽트란
• 프로세스가 수행되는 도중에 다른 서비스 처리 루틴이 끼어드는 것
• 인터럽트 발생 시점에 잠시 정지 -> 정해진 인터럽트 처리 루틴 수행 -> 복귀
1. 프로세서의 현재 상태 저장
1. 인터럽트
2. 인터럽트 발생 시간 체크
2. 처리
3. 원래 처리되고 있던 루틴으로 복귀
•
종류
•
시리얼 인터럽트
•
DMA 인터럽트
•
키보드 인터럽트
•
프린터 인터럽트
4/13
IRQ 인터럽트의 처리 과정
• core별 처리 과정
•
•
i386계열
•
내부 인터럽트 벡터 테이블 안에 IRQ 인터럽트 벡터가 포함되어 있음
•
인터럽트가 발생하면 해당 테이블에 처리 루틴으로 분기됨
ARM 계열
•
1. 인터럽트
2. 인터럽트 발생 시간 체크
IRQ 벡터가 하나이므로 인터럽트 제어장치를 통해 인터럽트 처리를 재분기 함
=> 리눅스에서 통합하여 처리함
•
프로세서마다 처리 방식이 다르기 때문에 do_IRQ()를 호출하여 처리 함
•
do_IRQ()는 irq_desc라는 전역 변수에 등록된 인터럽트 서비스 함수를 호출 함
•
처리하고자 하는 IRQ 번호에 해당하는 인터럽트 서비스 함수를 irq_desc에 등록
5/13
IRQ 인터럽트의 처리 과정
• IRQ 인터럽트 처리 과정
하드웨어 장치
1. 인터럽트
커널
디바이스 드라이버
struct xxx data;
아키텍처별 IRQ 인식 처리 루틴
1) 등록
do_IRQ(n)
2. 인터럽트 발생 시간 체크
request_irq(irq, int_handler, frag, “xxx”, &data);
irq_desc[irqs]
등록된 irq_desc에서 발생된 irq
인터럽트 서비스 함수 호출
irqreturn_t int_handler(int irq, void *dev_id, struct ptr_regs *regs)
{
2) 호출
:
인터럽트 처리
:
}
3) 제거
free_irq(irq, &data);
6/13
인터럽트 서비스 함수의 형식
• 인터럽트 처리
•
인터럽트가 발생 했을 때 처리할 루틴을 담은 인터럽트 서비스 함수가 필요함
•
irqreturn_t int_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
1. 인터럽트
2. 인터럽트 발생 시간 체크
return IRQ_HANDLED;
}
•
irq
•
•
•
인터럽트 번호
*dev_id
•
인터럽트 id
•
또는 인터럽트 함수가 사용 가능한 메모리 주소
struct pt_regs *regs
•
인터럽트가 발생했을 당시의 레지스터 값
7/13
인터럽트 서비스 함수의 형식
• 인터럽트 서비스 함수 내의 메모리 할당
•
kmalloc과 kfree 함수를 사용
•
vmalloc vfree, ioremap 같은 가상메모리를 이용하는 함수를 사용하면 안됨
•
GFP_ATOMIC 인자를 사용해야 함
•
•
메모리가 있으면 할당, 없으면 NULL
1. 인터럽트
2. 인터럽트 발생 시간 체크
irqreturn_t int_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
char *data;
:
data = kmalloc(128, GFP_ATOMIC);
if(data != NULL)
{
:
kfree(data);
}
:
return IRQ_HANDLED;
}
8/13
인터럽트 서비스 함수의 등록과 해제
• 인터럽트 서비스 함수 등록
•
인터럽트를 처리하기 위해 가장 먼저 처리하는 것
•
int request_irq
1. 인터럽트
(
unsigned int irq,
2. 인터럽트 발생 시간 체크
irqreturn_t (*handler) (int, void *, struct pt_regs *),
unsigned long frags, const char *device, void *dev_id
);
9/13
인터럽트 서비스 함수의 등록과 해제
• 인터럽트 서비스 함수 해제
•
더 이상 필요 없을 때 제거
•
void free_irq(unsigned int irq, void *dev_id);
•
int xxx_release(struct inode *inode, struct file *filp)
{
1. 인터럽트
2. 인터럽트 발생 시간 체크
//하드웨어 인터럽트 금지 처리 루틴
:…
free_irq(xxx_IRQ, NULL);
return 0;
}
10/13
인터럽트 함수와 디바이스 드라이버간의 데이터 공유
• 데이터 공유
•
인터럽트 서비스 함수는 문맥과 별개로 임의의 시점에서 수행됨
•
인터럽트 서비스 함수와 디바이스 드라이버 함수간에 데이터 공유 하는 방법이 필요함
•
•
전역 변수를 이용 => 동일한 인터럽트 서비스 함수로 여러 디바이스를 제어할 수 없음
•
dev_id 매개변수를 사용 => 여러 디바이스를 동일한 입터럽트 서비스 함수로 제어
1. 인터럽트
2. 인터럽트 발생 시간 체크
전역변수를 이용하는 경우
•
static unsigned long int_count = 0;
irqreturn_t count_interrupt(int irq, void *dev_id, struct pt_regs *regs)
•
{
int int_release(struct inode *inode, struct file *filp)
{
int_count++;
//하드웨어 인터럽트 금지 처리 루틴
return IRQ_HANDLED;
:
}
free_irq(XXX_IRQ, NULL);
int int_open(struct inode *inode, struct file *filp)
printk(“int_count %d\n”, int_count);
{
return 0;
if(!request_irq(XXX_IRQ, count_interrupt, SA_INTERRUPT, “test”, NULL))
}
{
// 하드웨어 인터럽트 허가 처리 루틴
:
int_count = 0;
}
return 0; }
11/13
인터럽트 함수와 디바이스 드라이버간의 데이터 공유
• 데이터 공유
•
dev_id를 이용하는 경우
•
typedef struct
{
1. 인터럽트
unsigned long ioaddress;
unsigned long count;
2. 인터럽트 발생 시간 체크
} __attribute__ ((packed)) R_INT_INFO;
irqreturn_t count_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
R_INT_INFO *ptrinfo;
ptrinfo = (R_INT_INFO *) dev_id;
printk(“INT READ I/O %02X\n”, inb(printinfo->ioaddress));
ptrinfo -> count++;
return IRQ_HANDLED;
}
•
int int_open(struct inode * inode, struct file *filp)
•
int int_release(struct inode *inode, struct file *filp)
•
… 교재 코드 참고
12/13
인터럽트 서비스 등록과 해제 시점
• 등록과 해제 시점
•
응용 프로그램이 디바이스 파일을 열었을 때 등록
•
•
open() 함수에서 인터럽트 서비스 함수 등록
응용 프로그램이 디바이스 파일을 닫았을 때 제거
•
close() 함수에서 인터럽트 서비스 함수 제거
1. 인터럽트
2. 인터럽트 발생 시간 체크
13/13
인터럽트의 공유
• 개요
•
PCI 디바이스 드라이버나 시리얼 디바이스들은 인터럽트 하나를 공유하여 여러 하드웨어에서
동작하는 경우가 있음
•
1. 인터럽트
인터럽트 서비스 함수를 등록할 때 같은 인터럽트 번호에 대해 다른 인터럽트 서비스 함수를 등록
2. 인터럽트 발생 시간 체크
할 수 있도록 지원 함
•
request_irq(XXX_IRQ, xxx_int_service_func, SA_INTERRUPT|SA_SHIRQ, PRINT_DEV_NAME, 0x01)
•
free_irq(XXX_IRQ, 0x01);
•
•
frags 매개변수에는 SA_SHIRQ가 포함되어야 함
•
dev_id 매개 변수에는 동일한 인터럽트 서비스 함수를 구별하기 위해 0이 아닌 값을 사용 해야 함
•
request_irq와 free_irq를 위해 dev_id 값은 동일해야 함
irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
인터럽트_관리_구조체 *ptrMng = (인터럽트_관리_구조체 *) dev_id;
if(자신의 인터럽트 체크 함수(ptrMng))
{
//인터럽트 처리
:
return IRQ_HANDLED;
}
return IRQ_NONE;
14/13
인터럽트의 금지와 해제
• 개요
•
현재 인터럽트 서비스 함수가 동작하도 있어도 또다른 인터럽트 발생 가능
•
•
우선순위에 따라 처리 됨
•
우선순위가 높은 인터럽트 처리중일때 낮은 인터럽트가 발생하면 낮은 인터럽트가 대기 함
•
우선순위가 낮은 인터럽트 처리중일때 높은 인터럽트가 발생하면 높은 인터럽트가 처리 됨
1. 인터럽트
2. 인터럽트 발생 시간 체크
하드웨어에 따라 인터럽트 도중에 수행이 중지되면 곤란한 디바이스가 존재함
•
해결책
•
인터럽트 도중 다른 인터럽트가 발생하지 못하게 막는 경우
•
•
request_irq() 함수의 frags 매개변수에 SA_INTERRUPT 설정 -> 빠른 인터럽트 핸들러 라고 함
데이터 처리를 보호하기 위해 인터럽트를 강제로 막는 경우
•
•
특정 인터럽트 번호에 대한 금지와 해제를 수행 함
•
void disable_irq(int irq) : 인터럽트 금지
•
void enable_irq(int irq) : 인터럽트 허가
[일반적인 사용방법]
unsigned long frags;
local_save_flags(frags);
local_irq_disable();
//인터럽트 호출에서 보호하고자 하는 루틴
local_restore_flags(frags);
프로세서 전체의 인터럽트를 금지하고 해제
•
local_irq_disable/enable(void) : 프로세서 인터럽트 처리를 금지/허가
•
local_save_flags/restore(unsigned long frags) : 현재의 프로세스의 상태를 저장/복구
15/13
seqlock_t 구조체
• 개요
•
배경
•
디바이스 드라이버가 사용하는 변수와 인터럽트 서비스 함수가 사용하는 변수가 전역변수로
서로 같을 경우
•
•
인터럽트 금지루틴이 길거나 잦다면 시스템 효율이 떨어지게 됨
•
상황
•
{
하드웨어에서 읽어온 값이 인터럽트 서비스
해결책
•
unsinged char ReadData = 0;
irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
함수에서 변경될경우 다른 결과가 발생할 수 있음
•
2. 인터럽트 발생 시간 체크
동기화를 위해 인터럽트의 금지와 해제를 이용함
•
1. 인터럽트
ReadData = inb(IN_ADDR);
return IRQ_HANDLED;
}
ssize_t xxx_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
if(ReadData)
seqlock_t 구조체
{
처리루틴
}
outb(ReadData | 0x80);
return 1;
}
16/13
seqlock_t 구조체
• 개요
•
seqlock_t 구조체
•
구현
•
장점
•
•
•
•
경량
특징
reader보다 writer가 먼저
•
writer는 다른 writer가
seqlock_t the_lock = SEQLOCK_UNLOCKED;
unsigned int seq;
•
•
제어용 변수 선언
데이터 변경 루틴
•
1. 인터럽트
2. 인터럽트 발생 시간 체크
write_seqlock(&the_lock);
:
데이터 변경 루틴
없으면 항상 락을 잠글 수 있음
:
write_sequnlock(&the_lock);
•
데이터 취득 루틴
do{
seq = read_seqbegin(&the_lock);
:
데이터 값 처리 루틴
:
}while read_seqretry(&the_lock, seq);
17/13
인터럽트 발생 횟수 확인
• 개요
•
보통 디바이스 드라이버가 제대로 동작하는지 확인 하려면 인터럽트 동작을 확인 함
•
인터럽트 호출 횟수는 리눅스 커널에서 알아서 계산함
•
proc/interrupts
1. 인터럽트
2. 인터럽트 발생 시간 체크
18/13
Q&A
19/40