9G10核心時鐘tick實現

2022-06-21 07:06:12 字數 4898 閱讀 7457

9g10中pit(periodic interval timer)提供os排程中斷,它提供了最高精度和最有效的管理(即使系統長時間響應)。

一. 硬體

pit目標是提供os的週期中斷。pit提供乙個可程式設計溢位計數器和乙個reset-on-read特性。它包含兩個計數器:20bit cpiv counter和12bit picnt(periodic interval) counter。兩個計數器都工作在master clock/16。

cpiv從0增加到pit_mr中piv設定值,到達設定值後復位(0)且picnt加1。假如中斷是能,pit_sr的pits位置位,觸發乙個中斷。

寫乙個新的piv值到pitmr不會reset/restart計數器。

當讀取pit_pivr(periodic interval value register)時,picnt復位(0),且pits清零(獲取到乙個中斷)。picnt表示自從上次讀取pit_pivr後多少個periodic interval過去了。

當讀取pit_piir(periodic interval image register)時,對cpiv和picnt無影響。

pit可通過pit_mr的piten位使能或關閉,僅當cpiv變為0時piten才生效。

pit共有4個暫存器,分別是pit_mr(mode register),pit_sr(status register),pit_pivr(periodic interval value register),pit_piir(periodic interval image register)。

pit_mr: bit0-19 piv, bit24 piten, bit25 pitien

pit_sr:bit0 pits

pit_pivr:bit0-19 cpiv,bit20-31 picnt

pit_piir:bit0-19 cpiv,bit20-31 picnt

二. 軟體

在板級檔案中machine_desc中設定timer=&at91sam926x_timer,下面看下at91sam926x_timer的初始化函式。

at91sam926x_time.c

/** set up both clocksource and clockevent support.

*/static void __init at91sam926x_pit_init(void)

static struct clocksource pit_clk = ;

static struct clock_event_device pit_clkevt = ;

clocksource註冊過程

clocksource_register(&pit_clk); -->clocksource_enqueue(&pit_clk);

將pit_clk新增到系統時鐘源list中。

clockevents_register_device(&pit_clkevt);

-->clockevents_do_notify(clock_evt_notify_add, &pit_clkevt);

--> raw_notifier_call_chain(&clockevents_chain, reason, &pit_clkevt);

-->__raw_notifier_call_chain(nh, val, v, -1, null);

-->notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);

-->nb->notifier_call(nb, val, v);

即nb->notifier_call((&clockevents_chain)->head, clock_evt_notify_add, &pit_clkevt);

kernel/notifier.c

notifier_call()函式的初始化在start_kernel()的tick_init()中,後面分析。

-->tick_check_new_device(&pit_clkevt); //kernel/time/tick-common.c

確認clock_event_device的rating是否高於當前的,高於則替換當前時鐘事件裝置

若pit_clkevt->features&clock_evt_feat_oneshot 還要呼叫 tick_oneshot_notify()

-->tick_setup_device(td, newdev, cpu, cpumask_of(cpu));

-->tick_setup_periodic(newdev, 0);

---->tick_set_periodic_handler(newdev, 0);

------>(&pit_clkevt)->event_handler = tick_handle_periodic;

// kernel/time/tick-common.c

即設定pit_clkevt的事件處理函式為tick_handle_periodic()。

---->clockevents_set_mode(dev, clock_evt_mode_periodic);

---->(&pit_clkevt)->set_mode(clock_evt_mode_periodic, &pit_clkevt);

pit_clkevt.mode = clock_evt_mode_periodic;

至此呼叫pit_clkevt的set_mode()函式,完成全部初始化工作

在init/main.c的start_kernel()中tick_init()呼叫過程:

tick_init(); //kernel/time/tick-common.c

-->clockevents_register_notifier(&tick_notifier);

-->raw_notifier_chain_register(&clockevents_chain, nb);

-->notifier_chain_register(&nh->head, n); // kernel/notifier.c

-->向clockevents_chian註冊tick_notifier()

static int tick_notify(struct notifier_block *nb, unsigned long reason,

void *dev)

return notify_ok;

}static struct notifier_block tick_notifier = ;

即向系統註冊了notifier_block結構體tick_notifier的notifier_call()**函式。

中斷處理過程

根據初始化過程,每個tick或hz產生一次中斷。

static struct irqaction at91sam926x_pit_irq = ;

static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)

while (nr_ticks);

return irq_handled;

}return irq_none;

}at91sam926x_pit_interrupt()

-->pit_clkevt.event_handler(&pit_clkevt);

-->tick_handle_periodic(&pit_clkevt); //kernel/time/tick-common.c

-->tick_periodic(cpu);

-->do_timer(1); //kernel/timer.c 更新jiffies_64和時間

-->update_times(ticks);

-->update_wall_time(); //更新xtime

void do_timer(unsigned long ticks)

static inline void update_times(unsigned long ticks)

三. 知識擴充套件

1)時鐘系統中最重要的結構體變數:clockevent clocksource xtime。

clockevent為kernel提供了時鐘中斷的一些處理函式,特別是對於tickless系統,提供了設定下一次時鐘中斷時間點的介面set_next_event和timer模式設定介面set_mode。

clocksource則是kernel真正的計數者 時鐘源,常規的時鐘中斷中的計數以及提高精度的補充計數都來自於clocksource。

clocksource成員rating代表了時鐘精度,參考值如下:

1--99: 不適合於用作實際的時鐘源,只用於啟動過程或用於測試;

100--199:基本可用,可用作真實的時鐘源,但不推薦;

200--299:精度較好,可用作真實的時鐘源;

300--399:很好,精確的時鐘源;

400--499:理想的時鐘源,如有可能就必須選擇它作為時鐘源;

xtime是kernel的牆上時間,記錄從1970-1-1至今的時間差,不管是使用者空間還是核心空間要獲取的系統時間都需要去讀取xtime。

2)timer中斷模式

kernel下timer的中斷模式支援2種:週期性和一次性,也就是periodic和oneshot。

對於固定tick(1/hz)系統的timer使用periodic。但是對於tickless系統,則必須要使用oneshot 模式了,因為每次timer中斷間隔不一樣長。

3系統啟動時讀取硬體時間,一般在rtc驅動載入後,呼叫rtc_hctosys()(driver/rtc/hctosys.c)。其根據核心配置config_rtc_hctosys來決定是否同步時間,並讀取config_rtc_hctosys_device(一般為rtc0)來獲取rtc時間。

late_initcall(rtc_hctosys);

參考:

MC9S12G時鐘配置

一 enable外部時鐘 使cpmuosc暫存器的osce位置一 二 計算需要的頻率 以24mhz為例 pllclk 24mhz 2 x oscclk 振盪器頻率,即你的外部晶振 x synr 1 refdv 1 三 計算出synr,refdv後 把synr得值賦給cpmusynr的前六位,把ref...

Oracle9i 10g 樹查詢特性

例子 select select id from test where level a.lv start with id a.id connect by id prior f id f id,idfrom select id,level lvfrom test connect by id fid a...

ORACLE 10g 安裝中的TCP IP核心警告

在虛擬機器vmware6.5的rhel4上安裝oracle 10g時,先決條件檢查中核心引數檢查出現警告.其中的引數均為tcp ip rmem default 預設的接收視窗大小 rmem max 接收視窗的最大大小 wmem default 預設的傳送視窗大小 wmem max 傳送視窗的最大大小...