diff options
| -rw-r--r-- | arch/i386/kernel/time_hpet.c | 37 | ||||
| -rw-r--r-- | arch/x86_64/kernel/time.c | 37 |
2 files changed, 62 insertions, 12 deletions
diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c index 14a1376fedd1..6bf14a4e995e 100644 --- a/arch/i386/kernel/time_hpet.c +++ b/arch/i386/kernel/time_hpet.c | |||
| @@ -301,23 +301,25 @@ int hpet_rtc_timer_init(void) | |||
| 301 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; | 301 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; |
| 302 | 302 | ||
| 303 | local_irq_save(flags); | 303 | local_irq_save(flags); |
| 304 | |||
| 304 | cnt = hpet_readl(HPET_COUNTER); | 305 | cnt = hpet_readl(HPET_COUNTER); |
| 305 | cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); | 306 | cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); |
| 306 | hpet_writel(cnt, HPET_T1_CMP); | 307 | hpet_writel(cnt, HPET_T1_CMP); |
| 307 | hpet_t1_cmp = cnt; | 308 | hpet_t1_cmp = cnt; |
| 308 | local_irq_restore(flags); | ||
| 309 | 309 | ||
| 310 | cfg = hpet_readl(HPET_T1_CFG); | 310 | cfg = hpet_readl(HPET_T1_CFG); |
| 311 | cfg &= ~HPET_TN_PERIODIC; | 311 | cfg &= ~HPET_TN_PERIODIC; |
| 312 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; | 312 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; |
| 313 | hpet_writel(cfg, HPET_T1_CFG); | 313 | hpet_writel(cfg, HPET_T1_CFG); |
| 314 | 314 | ||
| 315 | local_irq_restore(flags); | ||
| 316 | |||
| 315 | return 1; | 317 | return 1; |
| 316 | } | 318 | } |
| 317 | 319 | ||
| 318 | static void hpet_rtc_timer_reinit(void) | 320 | static void hpet_rtc_timer_reinit(void) |
| 319 | { | 321 | { |
| 320 | unsigned int cfg, cnt; | 322 | unsigned int cfg, cnt, ticks_per_int, lost_ints; |
| 321 | 323 | ||
| 322 | if (unlikely(!(PIE_on | AIE_on | UIE_on))) { | 324 | if (unlikely(!(PIE_on | AIE_on | UIE_on))) { |
| 323 | cfg = hpet_readl(HPET_T1_CFG); | 325 | cfg = hpet_readl(HPET_T1_CFG); |
| @@ -332,10 +334,33 @@ static void hpet_rtc_timer_reinit(void) | |||
| 332 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; | 334 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; |
| 333 | 335 | ||
| 334 | /* It is more accurate to use the comparator value than current count.*/ | 336 | /* It is more accurate to use the comparator value than current count.*/ |
| 335 | cnt = hpet_t1_cmp; | 337 | ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq; |
| 336 | cnt += hpet_tick*HZ/hpet_rtc_int_freq; | 338 | hpet_t1_cmp += ticks_per_int; |
| 337 | hpet_writel(cnt, HPET_T1_CMP); | 339 | hpet_writel(hpet_t1_cmp, HPET_T1_CMP); |
| 338 | hpet_t1_cmp = cnt; | 340 | |
| 341 | /* | ||
| 342 | * If the interrupt handler was delayed too long, the write above tries | ||
| 343 | * to schedule the next interrupt in the past and the hardware would | ||
| 344 | * not interrupt until the counter had wrapped around. | ||
| 345 | * So we have to check that the comparator wasn't set to a past time. | ||
| 346 | */ | ||
| 347 | cnt = hpet_readl(HPET_COUNTER); | ||
| 348 | if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) { | ||
| 349 | lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1; | ||
| 350 | /* Make sure that, even with the time needed to execute | ||
| 351 | * this code, the next scheduled interrupt has been moved | ||
| 352 | * back to the future: */ | ||
| 353 | lost_ints++; | ||
| 354 | |||
| 355 | hpet_t1_cmp += lost_ints * ticks_per_int; | ||
| 356 | hpet_writel(hpet_t1_cmp, HPET_T1_CMP); | ||
| 357 | |||
| 358 | if (PIE_on) | ||
| 359 | PIE_count += lost_ints; | ||
| 360 | |||
| 361 | printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", | ||
| 362 | hpet_rtc_int_freq); | ||
| 363 | } | ||
| 339 | } | 364 | } |
| 340 | 365 | ||
| 341 | /* | 366 | /* |
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 7a9b18224182..7700e6cd2bd9 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c | |||
| @@ -1148,23 +1148,25 @@ int hpet_rtc_timer_init(void) | |||
| 1148 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; | 1148 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; |
| 1149 | 1149 | ||
| 1150 | local_irq_save(flags); | 1150 | local_irq_save(flags); |
| 1151 | |||
| 1151 | cnt = hpet_readl(HPET_COUNTER); | 1152 | cnt = hpet_readl(HPET_COUNTER); |
| 1152 | cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); | 1153 | cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); |
| 1153 | hpet_writel(cnt, HPET_T1_CMP); | 1154 | hpet_writel(cnt, HPET_T1_CMP); |
| 1154 | hpet_t1_cmp = cnt; | 1155 | hpet_t1_cmp = cnt; |
| 1155 | local_irq_restore(flags); | ||
| 1156 | 1156 | ||
| 1157 | cfg = hpet_readl(HPET_T1_CFG); | 1157 | cfg = hpet_readl(HPET_T1_CFG); |
| 1158 | cfg &= ~HPET_TN_PERIODIC; | 1158 | cfg &= ~HPET_TN_PERIODIC; |
| 1159 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; | 1159 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; |
| 1160 | hpet_writel(cfg, HPET_T1_CFG); | 1160 | hpet_writel(cfg, HPET_T1_CFG); |
| 1161 | 1161 | ||
| 1162 | local_irq_restore(flags); | ||
| 1163 | |||
| 1162 | return 1; | 1164 | return 1; |
| 1163 | } | 1165 | } |
| 1164 | 1166 | ||
| 1165 | static void hpet_rtc_timer_reinit(void) | 1167 | static void hpet_rtc_timer_reinit(void) |
| 1166 | { | 1168 | { |
| 1167 | unsigned int cfg, cnt; | 1169 | unsigned int cfg, cnt, ticks_per_int, lost_ints; |
| 1168 | 1170 | ||
| 1169 | if (unlikely(!(PIE_on | AIE_on | UIE_on))) { | 1171 | if (unlikely(!(PIE_on | AIE_on | UIE_on))) { |
| 1170 | cfg = hpet_readl(HPET_T1_CFG); | 1172 | cfg = hpet_readl(HPET_T1_CFG); |
| @@ -1179,10 +1181,33 @@ static void hpet_rtc_timer_reinit(void) | |||
| 1179 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; | 1181 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; |
| 1180 | 1182 | ||
| 1181 | /* It is more accurate to use the comparator value than current count.*/ | 1183 | /* It is more accurate to use the comparator value than current count.*/ |
| 1182 | cnt = hpet_t1_cmp; | 1184 | ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq; |
| 1183 | cnt += hpet_tick*HZ/hpet_rtc_int_freq; | 1185 | hpet_t1_cmp += ticks_per_int; |
| 1184 | hpet_writel(cnt, HPET_T1_CMP); | 1186 | hpet_writel(hpet_t1_cmp, HPET_T1_CMP); |
| 1185 | hpet_t1_cmp = cnt; | 1187 | |
| 1188 | /* | ||
| 1189 | * If the interrupt handler was delayed too long, the write above tries | ||
| 1190 | * to schedule the next interrupt in the past and the hardware would | ||
| 1191 | * not interrupt until the counter had wrapped around. | ||
| 1192 | * So we have to check that the comparator wasn't set to a past time. | ||
| 1193 | */ | ||
| 1194 | cnt = hpet_readl(HPET_COUNTER); | ||
| 1195 | if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) { | ||
| 1196 | lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1; | ||
| 1197 | /* Make sure that, even with the time needed to execute | ||
| 1198 | * this code, the next scheduled interrupt has been moved | ||
| 1199 | * back to the future: */ | ||
| 1200 | lost_ints++; | ||
| 1201 | |||
| 1202 | hpet_t1_cmp += lost_ints * ticks_per_int; | ||
| 1203 | hpet_writel(hpet_t1_cmp, HPET_T1_CMP); | ||
| 1204 | |||
| 1205 | if (PIE_on) | ||
| 1206 | PIE_count += lost_ints; | ||
| 1207 | |||
| 1208 | printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", | ||
| 1209 | hpet_rtc_int_freq); | ||
| 1210 | } | ||
| 1186 | } | 1211 | } |
| 1187 | 1212 | ||
| 1188 | /* | 1213 | /* |
