interrupt programming in linux

55
Embedded System Lab. II Interrupt Programming in Linux Interrupt Programming in Linux 경경경경경 경경경경경경 경 경 경

Upload: aolani

Post on 13-Feb-2016

54 views

Category:

Documents


2 download

DESCRIPTION

Interrupt Programming in Linux. 경희대학교 컴퓨터공학과 조 진 성. 주요 내용. 주요 내용 인터럽트 개념 PXA255 CPU 에서의 인터럽트 하드웨어 리눅스에서의 인터럽트 처리 인터럽트 프로그래밍 예. intr request. status reg. CPU. intr ack. mechanism. IR. PC. data/address. data reg. 인터럽트 인터페이스. 임베디드 시스템의 실시간성 요구에 필수적인 요소. 인터럽트. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Interrupt Programming in Linux

Embedded System Lab II

Interrupt Programming in Interrupt Programming in LinuxLinux

경희대학교 컴퓨터공학과

조 진 성

Embedded System Lab II 2

주요 내용

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

Embedded System Lab II 3

인터럽트 인터페이스

임베디드 시스템의 실시간성 요구에 필수적인 요소

CPU

statusreg

datareg m

echa

nism

PCintr request

intr ack

dataaddress

IR

Embedded System Lab II 4

인터럽트

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 ndash 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 IO Essentially ldquopollingrdquo of the interrupt pin is built-into the hardware so

no extra time

Embedded System Lab II 5

인터럽트 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

Embedded System Lab II 6

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP

sees Int asserted saves the PCrsquos 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

Embedded System Lab II 7

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Embedded System Lab II 8

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

IntInt1

Embedded System Lab II 9

인터럽트 기반 IO(fixed ISR location)

3 After completing instruction at 100 P sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PC

Int

100100

Embedded System Lab II 10

μ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

100101

instruction instruction

Main program

Program memory

PC

Int

인터럽트 기반 IO(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

100

Int0

P1

System bus

P1

0x8000

P2

0x8001

Embedded System Lab II 11

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 2: Interrupt Programming in Linux

Embedded System Lab II 2

주요 내용

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

Embedded System Lab II 3

인터럽트 인터페이스

임베디드 시스템의 실시간성 요구에 필수적인 요소

CPU

statusreg

datareg m

echa

nism

PCintr request

intr ack

dataaddress

IR

Embedded System Lab II 4

인터럽트

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 ndash 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 IO Essentially ldquopollingrdquo of the interrupt pin is built-into the hardware so

no extra time

Embedded System Lab II 5

인터럽트 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

Embedded System Lab II 6

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP

sees Int asserted saves the PCrsquos 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

Embedded System Lab II 7

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Embedded System Lab II 8

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

IntInt1

Embedded System Lab II 9

인터럽트 기반 IO(fixed ISR location)

3 After completing instruction at 100 P sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PC

Int

100100

Embedded System Lab II 10

μ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

100101

instruction instruction

Main program

Program memory

PC

Int

인터럽트 기반 IO(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

100

Int0

P1

System bus

P1

0x8000

P2

0x8001

Embedded System Lab II 11

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 3: Interrupt Programming in Linux

Embedded System Lab II 3

인터럽트 인터페이스

임베디드 시스템의 실시간성 요구에 필수적인 요소

CPU

statusreg

datareg m

echa

nism

PCintr request

intr ack

dataaddress

IR

Embedded System Lab II 4

인터럽트

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 ndash 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 IO Essentially ldquopollingrdquo of the interrupt pin is built-into the hardware so

no extra time

Embedded System Lab II 5

인터럽트 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

Embedded System Lab II 6

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP

sees Int asserted saves the PCrsquos 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

Embedded System Lab II 7

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Embedded System Lab II 8

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

IntInt1

Embedded System Lab II 9

인터럽트 기반 IO(fixed ISR location)

3 After completing instruction at 100 P sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PC

Int

100100

Embedded System Lab II 10

μ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

100101

instruction instruction

Main program

Program memory

PC

Int

인터럽트 기반 IO(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

100

Int0

P1

System bus

P1

0x8000

P2

0x8001

Embedded System Lab II 11

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 4: Interrupt Programming in Linux

Embedded System Lab II 4

인터럽트

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 ndash 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 IO Essentially ldquopollingrdquo of the interrupt pin is built-into the hardware so

no extra time

Embedded System Lab II 5

인터럽트 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

Embedded System Lab II 6

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP

sees Int asserted saves the PCrsquos 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

Embedded System Lab II 7

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Embedded System Lab II 8

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

IntInt1

Embedded System Lab II 9

인터럽트 기반 IO(fixed ISR location)

3 After completing instruction at 100 P sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PC

Int

100100

Embedded System Lab II 10

μ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

100101

instruction instruction

Main program

Program memory

PC

Int

인터럽트 기반 IO(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

100

Int0

P1

System bus

P1

0x8000

P2

0x8001

Embedded System Lab II 11

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 5: Interrupt Programming in Linux

Embedded System Lab II 5

인터럽트 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

Embedded System Lab II 6

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP

sees Int asserted saves the PCrsquos 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

Embedded System Lab II 7

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Embedded System Lab II 8

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

IntInt1

Embedded System Lab II 9

인터럽트 기반 IO(fixed ISR location)

3 After completing instruction at 100 P sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PC

Int

100100

Embedded System Lab II 10

μ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

100101

instruction instruction

Main program

Program memory

PC

Int

인터럽트 기반 IO(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

100

Int0

P1

System bus

P1

0x8000

P2

0x8001

Embedded System Lab II 11

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 6: Interrupt Programming in Linux

Embedded System Lab II 6

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP

sees Int asserted saves the PCrsquos 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

Embedded System Lab II 7

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Embedded System Lab II 8

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

IntInt1

Embedded System Lab II 9

인터럽트 기반 IO(fixed ISR location)

3 After completing instruction at 100 P sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PC

Int

100100

Embedded System Lab II 10

μ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

100101

instruction instruction

Main program

Program memory

PC

Int

인터럽트 기반 IO(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

100

Int0

P1

System bus

P1

0x8000

P2

0x8001

Embedded System Lab II 11

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 7: Interrupt Programming in Linux

Embedded System Lab II 7

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Embedded System Lab II 8

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

IntInt1

Embedded System Lab II 9

인터럽트 기반 IO(fixed ISR location)

3 After completing instruction at 100 P sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PC

Int

100100

Embedded System Lab II 10

μ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

100101

instruction instruction

Main program

Program memory

PC

Int

인터럽트 기반 IO(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

100

Int0

P1

System bus

P1

0x8000

P2

0x8001

Embedded System Lab II 11

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 8: Interrupt Programming in Linux

Embedded System Lab II 8

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

IntInt1

Embedded System Lab II 9

인터럽트 기반 IO(fixed ISR location)

3 After completing instruction at 100 P sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PC

Int

100100

Embedded System Lab II 10

μ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

100101

instruction instruction

Main program

Program memory

PC

Int

인터럽트 기반 IO(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

100

Int0

P1

System bus

P1

0x8000

P2

0x8001

Embedded System Lab II 11

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 9: Interrupt Programming in Linux

Embedded System Lab II 9

인터럽트 기반 IO(fixed ISR location)

3 After completing instruction at 100 P sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PC

Int

100100

Embedded System Lab II 10

μ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

100101

instruction instruction

Main program

Program memory

PC

Int

인터럽트 기반 IO(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

100

Int0

P1

System bus

P1

0x8000

P2

0x8001

Embedded System Lab II 11

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 10: Interrupt Programming in Linux

Embedded System Lab II 10

μ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

100101

instruction instruction

Main program

Program memory

PC

Int

인터럽트 기반 IO(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

100

Int0

P1

System bus

P1

0x8000

P2

0x8001

Embedded System Lab II 11

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 11: Interrupt Programming in Linux

Embedded System Lab II 11

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 12: Interrupt Programming in Linux

Embedded System Lab II 12

인터럽트 기반 IO(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 microprocessor3 After completing instruction at 100 μP sees Int

asserted saves the PCrsquos 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

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 13: Interrupt Programming in Linux

Embedded System Lab II 13

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

IntInta

16

1(a) P is executing its main program

1(b) P1 receives input data in a register with address 0x8000

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 14: Interrupt Programming in Linux

Embedded System Lab II 14

인터럽트 기반 IO(vectored interrupt)

μ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

100101

instruction instruction

Main program

Program memory

PC

100

Inta

16

2 P1 asserts Int to request servicing by the microprocessor

Int1

Int

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 15: Interrupt Programming in Linux

Embedded System Lab II 15

인터럽트 기반 IO(vectored interrupt)

3 After completing instruction at 100 μP sees Int asserted saves the PCrsquos 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100100

1Inta

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 16: Interrupt Programming in Linux

Embedded System Lab II 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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

인터럽트 기반 IO(vectored interrupt)

100

4 P1 detects Inta and puts interrupt address vector 16 on the data bus

16

16

System bus

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 17: Interrupt Programming in Linux

Embedded System Lab II 17

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PCInt

Inta

16

100

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

P1 P2

0x8000 0x8001

System bus

0Int

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 18: Interrupt Programming in Linux

Embedded System Lab II 18

인터럽트 기반 IO(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

100101

instruction instruction

Main program

Program memory

PC

Int

100100+1

16 MOV R0 0x8000 17 modifies R0 18 MOV 0x8001 R0 19 RETI ISR return

ISR

100101

instruction instruction

Main program

100

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 19: Interrupt Programming in Linux

Embedded System Lab II 19

Interrupt address table

Compromise between fixed and vectored interrupts One interrupt pin Table in memory holding ISR addresses (maybe 256 words) Peripheral doesnrsquot provide ISR address but rather index into table

Fewer bits are sent by the peripheral Can move ISR location without changing peripheral

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 20: Interrupt Programming in Linux

Embedded System Lab II 20

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 canrsquot 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) ndash 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

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 21: Interrupt Programming in Linux

Embedded System Lab II 21

PXA255 General Purpose IO Block DiagramPin Direction

Register(GPDR) Alternate Function

Register(GAFR) Pin Set

Registers(GPSR)

Edge DetectStatus Register(GEDR)

Rising Edge DetectEnable Register(GRER)

Falling Edge DetectEnable Register(GFER)

EdgeDetect

Pin-LevelRegister(GPLR)

0

1Alternate Function(Output)

Alternate Function(Input)

Pin Clear Registers(GPCR)2

3

3210

Power Manager Sleep Wake-up logic

2

0x40E0_000C1014

GPDR1 출력0 입력

0x40E0_0054585C0x40E0_00606468

0x40E0_00606468

0x40E0_00606468

Base Address0x40E0_0000

0x40E0_00484C50

0x40E0_00303438

0x40E0_003C4044

0x40E0_00000408

세부적인 내용은 Embedded SW I

참조

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 22: Interrupt Programming in Linux

Embedded System Lab II 22

PXA255 Interrupt controller Interrupt Controller

Level Register(ICLR)

Interrupt ControllerMask Register (ICMR)

Interrupt Source Bit

Interrupt ControllerPending Register

(ICPR)Interrupt Controller

IRQ Pending Register (ICIP)

Interrupt ControllerFIQ Pending Register (ICFP)

All Other Qualified interrupt Bits

FIQ

IRQ

23 23 XScale CORE

CPSR6(F)

CPSR7(I)40D0 0000

40D0 0004

40D0 0008

40D0 000C

40D0 0010

40D0 0014 Interrupt controller control register (ICCR) ICCR0 disable idle mask(DIM)

CCR[DIM]=0 amp IDLE mode=lsquo1rsquo

0 IRQ1 FIQ

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 23: Interrupt Programming in Linux

Embedded System Lab II 23

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 PeripheralPCMCIA interrupt mask in each module GPIO masks determined per pin or group of pins

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 24: Interrupt Programming in Linux

Embedded System Lab II 24

ICMR(Interrupt Controller Mask Register)

IM[x] Interrupt Mask lsquoxrsquo (where x= 8 through 14 and 17 through 31)0 ndash Pending interrupt is masked from becoming active (interrupts are NOT sent to CPU or

Power Manager)1 ndash 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 0x40D00004

0000 0000 0000 000 000 0000

IM31 ndash IM28 IM27 ndash IM24 IM23 ndash IM20 IM11 ndash IM8IM19 ndash IM17 ReservedIM14 ndash IM12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 25: Interrupt Programming in Linux

Embedded System Lab II 25

ICLR(Interrupt Controller Level Register)

IL[x] Interrupt Level lsquoxrsquo (where n = 8 through 14 and 17 through 31)0 ndash Interrupt routed to IRQ interrupt input1 ndash Interrupt routed to FIQ interrupt input

Reserved[0-7 15 16]Physical Address 0x40D00008

0000 0000 0000 000 000 0000

IL31 ndash IL28 IL27 ndash IL24 IL23 ndash IL20 IL11 ndash IL8IL19 ndash IL17 ReservedIL14 ndash IL12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 26: Interrupt Programming in Linux

Embedded System Lab II 26

ICCR(Interrupt Controller Control Register)

DIM[0] Disable Idle mask0 ndash All enabled interrupts bring the processor out of idle mode1 ndash Only enabled and unmasked (as defined in the ICMR) bring the processor out of idle

modeThis bit is cleared during all resets

Reserved[311]Physical Address 0x40D00014

X

Reserved DIM

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 27: Interrupt Programming in Linux

Embedded System Lab II 27

ICIP(Interrupt Controller IRQ Pending Register)

IP[x] IRQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash IRQ NOT requested by any enabled source1 ndash IRQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D00000

0000 0000 0000 000 000 0000

IP31 ndash IP28 IP27 ndash IP24 IP23 ndash IP20 IP11 ndash IP8IP19 ndash IP17 ReservedIP14 ndash IP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 28: Interrupt Programming in Linux

Embedded System Lab II 28

ICFP(Interrupt Controller FIQ Pending Register)

FP[x] FIQ Pending x (where x = 8 through 14 and 17 through 31)0 ndash FIQ NOT requested by any enabled source1 ndash FIQ requested by an enabled source

Reserved[0-7 15 16]Physical Address 0x40D0000C

0000 0000 0000 000 000 0000

FP31 ndash FP28 FP27 ndash FP24 FP23 ndash FP20 FP11 ndash FP8FP19 ndash FP17 ReservedFP14 ndash FP12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 29: Interrupt Programming in Linux

Embedded System Lab II 29

ICPR(Interrupt Controller Pending Register)

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 0x40D00010

0000 0000 0000 000 000 0000

IS31 ndash IS28 IS27 ndash IS24 IS23 ndash IS20 IS11 ndash IS8IS19 ndash IS17 ReservedIS14 ndash IS12

3 2 1 07 6 5 411 10 9 815 14 13 1219 18 17 1623 22 21 2027 26 25 2431 30 29 28

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 30: Interrupt Programming in Linux

Embedded System Lab II 30

Why Bottom Halves

Because interrupt handlers hellip 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

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 31: Interrupt Programming in Linux

Embedded System Lab II 31

Bottom Halves in Linux 24

the future when the system is less busy and interrupts are enabled again

Three types of bottom halves in 24 softirq tasklet BH operations on deferrable functions

initialization activation masking execution ( activation and execution on the same

CPU )

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 32: Interrupt Programming in Linux

Embedded System Lab II 32

Bottom Halves in Linux 24

History of bottom half status in Linux BH removed in 25 Task queues removed in 25 Softirq available since 23 Tasklet available since 23 Work queues available since 25

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 33: Interrupt Programming in Linux

Embedded System Lab II 33

Softirqs

Each registered softirq in one entry of softirq_vec[32] (32 softirqs possible)

irq_stat

32-entry array of softirq_action (kernelsoftirqc) static struct softirq_action softirq_vec[32]

structure representing a softirq entry (linuxinterrupth) struct softirq_action void (action) (struct softirq_action ) void data

irq_cpustat_t irq_stat[NR_CPUS]

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

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 34: Interrupt Programming in Linux

Embedded System Lab II 34

Softirqs

Softirq handler 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 24 (six in 26)

HI_SOFTIRQ TIMER_SOFTIRQ NET_TX_SOFTIRQ NET_RX_SOFTIRQ SCSI_SOFTIRQ (hellip) TASKLET_SOFTIRQ

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 35: Interrupt Programming in Linux

Embedded System Lab II 35

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

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 36: Interrupt Programming in Linux

Embedded System Lab II 36

Softirqs

Executing softirqs do_softirq( )if( in_interrupt( ) ) returnlocal_irq_save( flags ) disable local INTpending = 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 amp 1 ) h-gtaction(h) h++ pending gtgt 1 while(pending) local_irq_disable() pending = softirq_pending(cpu) if( pending amp mask ) mask amp= ~pending goto restart local_bh_enable() if( pending ) wakeup_softirqd(cpu)local_irq_restore( flags )

softirq not processed in this invocation goto restart only if different types goto wakeup_softirqd(cpu) if same softirqre-activated

local_irq_count(cpu) = = 0 nested local_bh_count(cpu) = = 0 enabled

serializing execution on a CPU

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 37: Interrupt Programming in Linux

Embedded System Lab II 37

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-gtneed_resched) schedule( )

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 38: Interrupt Programming in Linux

Embedded System Lab II 38

Tasklets

Implemented on top of softirqs HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet structure (linuxinterrupth)

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

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 39: Interrupt Programming in Linux

Embedded System Lab II 39

Tasklets

Declaring your tasklets statically (linuxinterrupth)

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 devopen_softirq(TASKLET_SOFTIRQ tasklet_action NULL)open_softirq(HI_SOFTIRQ tasklet_hi_action NULL)

void tasklist_init(struct tasklet_struct t tasklet_handler dev)

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 40: Interrupt Programming in Linux

Embedded System Lab II 40

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

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 41: Interrupt Programming in Linux

Embedded System Lab II 41

Tasklets

Activating your tasklet tasklet_schedule( ) tasklet_hi_schedule( )

tasklet_schedule(ampmy_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 3insert 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)

what if the same tasklet is scheduled again what if it is already running on another CPU

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 42: Interrupt Programming in Linux

Embedded System Lab II 42

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 ltgt 0 ) reinsert and activate TASKLET_SOFTIRQ defer tasklet otherwise clear TASKLET_STATE_SCHED and execute the tasklet function

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 43: Interrupt Programming in Linux

Embedded System Lab II 43

Tasklets

Controlling tasklets Enable Disable tasklets

tasklet_enable( ) tasklet_disable( )

Remove a tasklet from the pending queue tasklet_kill( )

tasklet_disable(ampmy_tasklet)

we can now do stuff knowing that the tasklet cannot run

tasklet_enable(ampmy_tasklet)

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 44: Interrupt Programming in Linux

Embedded System Lab II 44

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

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 45: Interrupt Programming in Linux

Embedded System Lab II 45

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 22 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

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 46: Interrupt Programming in Linux

Embedded System Lab II 46

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

Can dynamically create new task queues Laterhellip

various queues 1048774 tasklets scheduler queue + keventd --gt ldquowork queuerdquo in 26

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 47: Interrupt Programming in Linux

Embedded System Lab II 47

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 --gt no softirqs)

How to disable bottom halves without disabling interrupts void local_bh_disable( ) --gt __local_bh_count++ (of irq_stat[cpu]) void local_bh_enable( )

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 48: Interrupt Programming in Linux

Embedded System Lab II 48

GPIO 디바이스 드라이버 GPIO 입력

button 를 제어하는 gpio 드라이버 프로그램 소스 예제 (gpioc)

include ltlinuxkernelhgt gpioc include ltlinuxmodulehgtinclude ltlinuxinithgtinclude ltlinuxconfighgtinclude ltlinuxschedhgtinclude ltlinuxstringhgtinclude ltlinuxdelayhgtinclude ltlinuxerrnohgtinclude ltlinuxtypeshgt

include ltasmhardwarehgtinclude ltasmuaccesshgtinclude ltasmirqhgtinclude ltasmparamhgt

define IRQ_BUTTON IRQ_GPIO(16)static void button_interrupt(int irq void dev_id struct pt_regs regs)

static int GPIO_MAJOR = 0static DECLARE_WAIT_QUEUE_HEAD(wait_queue)

GPIO 에 할당된 IRQ값과인터럽트 핸들러

블럭킹 IO 를 위한 대기 큐

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 49: Interrupt Programming in Linux

Embedded System Lab II 49

GPIO 디바이스 드라이버 (2)static void button_interrupt(int irq void dev_id struct pt_regs regs)

wake_up_interruptible(ampwait_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(ampwait_queue) copy_to_user(bufamphellosizeof(hello))

return 0

static int gpio_open(struct inode inode struct file filp)

int resunsigned int gafr

gafr = 0x3GAFR0_U amp= ~gafr

printk(IRQ_BUTTON = dnIRQ_BUTTON)printk(IRQ_TO_GPIO =dnIRQ_TO_GPIO_2_80(IRQ_BUTTON))

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) amp=~GPIO_bit(IRQ_TO_GPIO_2_80(IRQ_BUTTON))

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON)GPIO_FALLING_EDGE)

16 번 포트를 출력으로 설정과 및 에지 신호 설정

16 번포트의 GAFR 설정 해제

대기큐에 있는 프로세스를 깨움( 버튼이 눌러졌을 때 )

대기큐로 진입 ndash 블록킹 상태( 버튼이 눌러지길 기다림 )

블록킹이 해제 후 메시지 출력

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 50: Interrupt Programming in Linux

Embedded System Lab II 50

GPIO 디바이스 드라이버 (3)res = request_irq(IRQ_BUTTONampbutton_interruptSA_INTERRUPT

ButtonNULL)

if(res lt 0)printk(KERN_ERR s Request for IRQ d failedn

__FUNCTION__IRQ_BUTTON)else

enable_irq(IRQ_BUTTON)

MOD_INC_USE_COUNTreturn 0

static int gpio_release(struct inode inode struct file filp)

free_irq(IRQ_BUTTONNULL)disable_irq(IRQ_BUTTON)

MOD_DEC_USE_COUNTreturn 0

static struct file_operations gpio_fops = read gpio_readopen gpio_openrelease gpio_release

인터럽트 핸들러 설치

인터럽트를 활성화

설정된 irq 를 설정 해제한다

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 51: Interrupt Programming in Linux

Embedded System Lab II 51

GPIO 디바이스 드라이버 (4)int init_module(void)

int resultresult = register_chrdev(GPIO_MAJORGPIOINTERRUPTampgpio_fops)

if(result lt 0) printk(KERN_WARNINGCant get major dnGPIO_MAJOR)return result

if(GPIO_MAJOR == 0) GPIO_MAJOR = resultprintk(init module GPIO major number dnresult)

return 0

void cleanup_module(void)

unregister_chrdev(GPIO_MAJORGPIO INTERRUPT)return

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 52: Interrupt Programming in Linux

Embedded System Lab II 52

GPIO 디바이스 드라이버 응용 프로그램

include ltstdiohgt testc include ltstdlibhgtinclude ltunistdhgtinclude ltsystypeshgtinclude ltsysstathgtinclude ltfcntlhgtinclude lterrnohgt

static int dev

int main(void)

char buff[40]dev = open(devgpioO_RDWR)if(dev lt 0)

printf( Device Open ERRORn)exit(1)

printf(Please push the GPIO_16 portn)read(devbuff40)printf(snbuff)

close(dev)return 0

gpio 장치를 open

버튼이 눌러지길 기다림( 블록킹 상태가 됨 )

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 53: Interrupt Programming in Linux

Embedded System Lab II 53

Makefile 작성 예 led Device Driver Makefile Makefile CC = arm-linux-gcc

KERNELDIR = usrsrclinux-2419INCLUDEDIR = -I$(KERNELDIR)includeCFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 $(INCLUDEDIR)

MODULE_OBJS = gpiooMODULE_SRCS = gpioc

TEST_TARGET = testTEST_OBJS = testoTEST_SRCS = testc

all $(MODULE_OBJS) $(TEST_TARGET)

$(TEST_TARGET) $(TEST_OBJS)$(CC) $(TEST_OBJS) -o $

cleanrm -f orm -f $(TEST_TARGET)

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 54: Interrupt Programming in Linux

Embedded System Lab II 54

GPIO 디바이스 드라이버 실행

GPIO 디바이스 드라이버 컴파일 방법

GPIO 디바이스 드라이버 실행 방법 생성된 gpioo 와 test 파일을 타겟 보드로 전송 insmod 로 드라이버를 커널에 loading mknod 를 통해 특수 장치 파일을 만듦

응용프로그램을 실행

$ make

$ insmod gpioo Using gpioo init module GPIO major number 252$ mknod devgpio c 252 0

$ test

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55
Page 55: Interrupt Programming in Linux

Embedded System Lab II 55

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

디바이스 드라이버 실행

  • Slide 1
  • Slide 2
  • Slide 3
  • Slide 4
  • Slide 5
  • Slide 6
  • Slide 7
  • Slide 8
  • Slide 9
  • Slide 10
  • Slide 11
  • Slide 12
  • Slide 13
  • Slide 14
  • Slide 15
  • Slide 16
  • Slide 17
  • Slide 18
  • Slide 19
  • Slide 20
  • Slide 21
  • Slide 22
  • Slide 23
  • Slide 24
  • Slide 25
  • Slide 26
  • Slide 27
  • Slide 28
  • Slide 29
  • Slide 30
  • Slide 31
  • Slide 32
  • Slide 33
  • Slide 34
  • Slide 35
  • Slide 36
  • Slide 37
  • Slide 38
  • Slide 39
  • Slide 40
  • Slide 41
  • Slide 42
  • Slide 43
  • Slide 44
  • Slide 45
  • Slide 46
  • Slide 47
  • Slide 48
  • Slide 49
  • Slide 50
  • Slide 51
  • Slide 52
  • Slide 53
  • Slide 54
  • Slide 55