& t* X$ F N# T1 r/ J0 r4 \内核版本2.6.30 * Z7 J, W/ X/ v6 P# _' v* |( Y, e8 ]+ O p* X5 u4 K9 [
CPU:S3C24405 R$ D0 M& d: Y0 }! R) `
4 J! s; ^0 J% L$ k. T- D
$ U( e: I. `( K: U2 y2 m 8 j4 u$ r- z( @: m l本文主要说明节拍定时器是如何添加到内核中的,不对定时器实现进行说明。( W$ y* ~( T( e, N. ^, {) |# p9 ?
0 I3 T; L* Y( M/ K; u* d
4 [9 o2 }1 V, _9 h6 V2 [, o, z# }/ Q. M! u
ARM 平台的节拍定时器对象使用sys_timer来表示,该结构体位于arch/arm/include/asm/mach/time.h。 8 O$ A' O8 @3 Z/ a$ B9 k ! o6 I! V% G9 p# k; l. E, }/* & \& M U3 e; b! W9 X7 p * This is our kernel timer structure. 0 T" ]. |. Z4 N% F. N7 ^ ** w3 O9 T' q+ f
* - init 3 l4 p2 l( P+ v& i& ]% J8 i * Initialise the kernels jiffy timer source, claim interrupt) |, ], @$ u7 R! W7 n
* using setup_irq. This is called early on during initialisation; C8 P, e, |( B4 r2 V& b* h* @
* while interrupts are still disabled on the local CPU. i# w+ C8 e# n! O" L8 t * - suspend 7 Z/ U" H! o' i2 k: U * Suspend the kernel jiffy timer source, if necessary. This, r" l7 Z3 T( L& J; ~. e
* is called with interrupts disabled, after all normal devices " ?5 i/ ?& K3 |( T' C0 d: A. { * have been suspended. If no action is required, set this to% Y; j& V8 V7 ?3 O! i1 ^. N
* NULL. : }( O8 Z! ^# Z: Q( F7 S' M. V * - resume ( z' H }( f# @- O6 Z * Resume the kernel jiffy timer source, if necessary. This 4 Z4 ^( K! x; Q l2 Z * is called with interrupts disabled before any normal devices$ z3 X) q- f# x* e: I# Y
* are resumed. If no action is required, set this to NULL.9 p$ _# X" w1 w8 u
* - offset8 i% b6 w5 L3 L
* Return the timer offset in microseconds since the last timer# W6 N* \) N# a1 e% o% m { R; u
* interrupt. Note: this must take account of any unprocessed # ]" V9 n$ h& ^- {8 f * timer interrupt which may be pending.1 h" p- e8 @5 ~) H. c
*/1 z# @3 J% b# s6 R- a$ X
struct sys_timer { 4 @9 O& u8 |( u1 M8 }* [. c struct sys_device dev; 8 C% o- c+ e6 o. s+ o void (*init)(void); . C* V/ P% ^6 d8 ~& J void (*suspend)(void); 0 E: @! m g+ X' B9 e% ] void (*resume)(void);: T8 l1 _6 f! b! n6 r$ T5 P
#ifndef CONFIG_GENERIC_TIME m, {# D! C, X- @9 p3 v
unsigned long (*offset)(void);- w! U2 V% M2 H# S9 d- J N' K4 F3 Y
#endif) Y. u. l9 h7 o* }* W0 |
}; + @" i4 ?6 H, d. a* _5 a3 {" m) G7 W/ ?0 |6 P' i9 O+ w
S3C2440的sys_timer的定义在linux/arch/arm/plat-s3c24xx/time.c中,给出的三个方法也在该文件中定义。 : u2 t( V9 m+ W8 x7 a2 k ~: `struct sys_timer s3c24xx_timer = { % L/ ^; h4 d5 }# y# Y% u .init = s3c2410_timer_init," x* |4 b7 O6 t- N
.offset = s3c2410_gettimeoffset, ; W* c, S L; }( S .resume = s3c2410_timer_setup! y5 i7 f5 J; T" j
}; + S: X$ L9 E. x. }. U% r2 Z2 H* {) M* \& k7 v0 N; U
如何将该定时器告知内核呢? 2 q# ]% g* k" V* S7 _; ]在linux/arch/arm/mach-s3c2440/mach-smdk2440.c的最后使用了宏( h. T3 W4 F/ I) t: U. H# Q
( U' F* T0 m( P+ mMACHINE_START(S3C2440, "SMDK2440") ( e n4 C4 c$ I0 ?1 X /* Maintainer: Ben Dooks <ben@fluff.org> */ * i9 o& B+ v- F .phys_io = S3C2410_PA_UART,& P q/ D2 W7 Q5 E; c$ _& {
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, , Y5 s( G& ?$ \# a4 o( }* c& l* u .boot_params = S3C2410_SDRAM_PA + 0x100,3 k; ]' U$ h# x4 s. M0 G/ G$ J7 p1 w
+ \ c a" p: H2 w& F4 P- | .init_irq = s3c24xx_init_irq,% S" i$ R! V7 W4 Y4 {
.map_io = smdk2440_map_io,8 l3 n4 P7 m: L9 y+ R
.init_machine = smdk2440_machine_init, & o# G h8 G& b0 G; `+ V .timer = &s3c24xx_timer, 4 r" i6 R" J9 K- p) M2 FMACHINE_END, l. p m; w T) M
7 G$ B+ W7 f" u ?! H
该宏用于初始化结构体struct machine_desc,结构体成员如下: & N5 \+ u# W5 N8 n) D% Istruct machine_desc { # W3 M, M' y. V( T+ \) H& m /* 0 a) H! W# L% t1 I! u6 V * Note! The first four elements are used/ k$ ]4 R/ o6 m( V2 H
* by assembler code in head.S, head-common.S / \" w" Q: a; v2 \) u */ " Y3 o: t1 l! V+ l' K unsigned int nr; /* architecture number */3 T" A6 l& x, W( ~ o a' {
unsigned int phys_io; /* start of physical io */% w: f* i7 K M& |3 e9 z6 T# V
unsigned int io_pg_offst; /* byte offset for io 7 \$ O- } l6 I3 b. @2 S4 M6 p# Q * page tabe entry */' s/ t; y2 P2 y9 A) m8 D
# S3 h) P! a9 r8 [4 x const char *name; /* architecture name */ 5 n, {1 s M6 {7 e" J unsigned long boot_params; /* tagged list */ 1 Y" r3 G( S e( @ 3 j; U8 `( V O& T$ q' H4 L
unsigned int video_start; /* start of video RAM */ ) m. c7 ?3 h) b U7 S6 T S# c6 R3 V unsigned int video_end; /* end of video RAM */ ) w& Z, a8 o$ q4 I . |- o* K: ^& W- N
unsigned int reserve_lp0 :1; /* never has lp0 */ ) g& n4 G3 E/ h/ J. {5 w unsigned int reserve_lp1 :1; /* never has lp1 */ % k$ s4 ^, M$ O/ `( y unsigned int reserve_lp2 :1; /* never has lp2 */) j" O* C7 g# D6 D5 Z7 b: t! f
unsigned int soft_reboot :1; /* soft reboot */ 4 b, u V2 A: ?) ] L# v' m5 E0 J5 g void (*fixup)(struct machine_desc *,/ L$ i/ [1 j( c8 `- ]. Q. i
struct tag *, char **, 6 R. r* Y1 b9 L& S" E struct meminfo *);! X) E4 j# @- u4 s2 F5 {( m
void (*map_io)(void);/* IO mapping function */0 l3 ? m# g/ q; B. T1 ~$ ^
void (*init_irq)(void); 9 S% R0 |0 }5 Z. z0 U1 r struct sys_timer *timer; /* system tick timer */: M9 I) |+ A) H
void (*init_machine)(void);1 g7 ~0 V% a1 U$ J* e
};+ S3 j7 l; A/ A( C6 n
- a* ^, B7 n4 m; X/ S+ Y; K在这里我们看到了timer指针。通过该宏将timer指针指向了s3c24xx_timer。% u4 }6 k1 Q/ s- W
接着,再看linux/arch/arm/kernel/setup.c中的setup_arch函数,该函数中执行了下面这话: " m9 K5 f! o" }' X# u # P! V4 h' I Q( N system_timer = mdesc->timer; ( S5 I; ?) |4 v1 E! R2 H7 \ 4 a4 ~9 E2 G* V% `7 Ymdesc->timer即为上面宏所给出的s3c24xx_timer,而system_timer为全局变量。通过该全局变量就可使用节拍定时器。( k8 S3 g- {+ Z" j+ H: W: k; B7 \( k
5 K s- u% y/ G, n$ _! o" N2 r
最后,我们看下节拍定时器的init方法何时被调用,调用顺序如下: * X6 P1 L4 g t. q0 X % G/ ~3 e. X8 P, H0 P# Vstart_kernel ()--> time_init() --> system_timer->init() 4 O; A y- g' J7 p 0 @# T& B# C) ]4 _time_init -函数位于linux/arch/arm/kernel/time.c。 0 ^0 n9 U: G$ g% R' X/ P" z X( N9 j
8 U# N/ G k' r* k" ? J 8 ?3 t9 V: l# x * k- G+ T9 l2 [. k: Y, D% l 0 H- B. X! m" s. S* P# o8 C" g. q6 @1 _5 W
! ^$ i: d4 Y7 k! m 作者: younicp 时间: 2020-6-12 13:13
节拍定时器