名称
calc_deltaf - ETC クロックの誤差を求める
書式
static int64_t
calc_deltaf(
mic_ctx_t * mic_ctx);
引数
- mic_ctx
- 誤差を求めるETCを持つカードの context
説明
引数 mic_ctx で指定されたカードの ETC の、仕様値 15.625 MHz からの誤差を求める。
戻り値
ETC の基準クロック (15.625 MHz) からの誤差。単位 Hz。
参照
実装
103 static int64_t
104 calc_deltaf(mic_ctx_t *mic_ctx)
105 {
106 const int64_t ETC_CLK_FREQ = 15625000;
107 const uint32_t TIME_DELAY_IN_SEC = 10;
108 const int64_t etc_cnt1 = ETC_CLK_FREQ * TIME_DELAY_IN_SEC;
109 int64_t etc_cnt2;
110
111 unsigned long cnt1, cnt2;
112 int64_t deltaf_in_ppm, deltaf;
113
114 /*
115 * (etc_freq2 / etc_freq1) = (etc_count2 / etc_count1)
116 * etc_freq1 = ETC_CLK_FREQ
117 * => etc_count1 = TIME_DELAY_IN_SEC * ETC_CLK_FREQ
118 * (etc_freq2 / etc_freq1) = (etc_count2 / etc_count1)
119 * etc_freq2 = etc_freq1 * (etc_count2 / etc_count1)
120 * etc_freq2 - etc_freq1 = etc_freq1((etc_count2 / etc_count1) - 1)
121 * deltaf = etc_freq1(etc_count2 - etc_count1)/etc_count1
122 * deltaf_in_ppm = deltaf * 10 ^ 6 / etc_freq1
123 * deltaf_in_ppm = ((etc_count2 - etc_count1) * 10 ^ 6) / etc_count1
124 */
125 unsigned long flags;
126 /* Need to implement the monotonic/irqsave logic for windows */
127 struct timespec ts1, ts2;
128 int64_t mono_ns;
129 local_irq_save(flags);
130 cnt1 = etc_read(mic_ctx->mmio.va);
131 getrawmonotonic(&ts1);
132 local_irq_restore(flags);
133
134 mdelay(TIME_DELAY_IN_SEC * 1000);
135
136 local_irq_save(flags);
137 cnt2 = etc_read(mic_ctx->mmio.va);
138 getrawmonotonic(&ts2);
139 local_irq_restore(flags);
140 etc_cnt2 = cnt2 - cnt1;
141 ts2 = timespec_sub(ts2, ts1);
142 mono_ns = timespec_to_ns(&ts2);
143 /* Recalculate etc_cnt2 based on getrawmonotonic */
144 etc_cnt2 = (etc_cnt2 * TIME_DELAY_IN_SEC * 1000 * 1000 * 1000) / mono_ns;
145 deltaf = ( ETC_CLK_FREQ * (etc_cnt2 - etc_cnt1)) / etc_cnt1;
146 deltaf_in_ppm = (1000 * 1000 * (etc_cnt2 - etc_cnt1)) / etc_cnt1;
147 pr_debug("etc deltaf: %lld\n", deltaf);
148 /*
149 * For intel chipsets, Spread Spectrum Clocking (SSC) (in the limit)
150 * is downspread with a frequency of 30hz and an amplitude of 0.5%
151 * which translates to 2500ppm. This is also the ppm observed on KNC + CrownPass
152 * Hence, if ppm > 2500, the code would need to retry to eliminate any chance of error
153 * Added an error margin of 1ppm (etc mmio reads can take really long time)
154 */
155 if (deltaf_in_ppm > 2501 || deltaf_in_ppm < -2501)
156 printk(KERN_ERR "ETC timer compensation(%lldppm) is much higher"
157 "than expected\n", deltaf_in_ppm);
158
159 return deltaf;
160 }
最終更新:2012年11月25日 15:56