aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/hpet.c198
1 files changed, 124 insertions, 74 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 175d24be0833..88b4da373081 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -226,22 +226,7 @@ static void hpet_reserve_platform_timers(unsigned int id) { }
226 */ 226 */
227static unsigned long hpet_freq; 227static unsigned long hpet_freq;
228 228
229static void hpet_legacy_set_mode(enum clock_event_mode mode, 229static struct clock_event_device hpet_clockevent;
230 struct clock_event_device *evt);
231static int hpet_legacy_next_event(unsigned long delta,
232 struct clock_event_device *evt);
233
234/*
235 * The hpet clock event device
236 */
237static struct clock_event_device hpet_clockevent = {
238 .name = "hpet",
239 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
240 .set_mode = hpet_legacy_set_mode,
241 .set_next_event = hpet_legacy_next_event,
242 .irq = 0,
243 .rating = 50,
244};
245 230
246static void hpet_stop_counter(void) 231static void hpet_stop_counter(void)
247{ 232{
@@ -306,64 +291,74 @@ static void hpet_legacy_clockevent_register(void)
306 printk(KERN_DEBUG "hpet clockevent registered\n"); 291 printk(KERN_DEBUG "hpet clockevent registered\n");
307} 292}
308 293
309static void hpet_set_mode(enum clock_event_mode mode, 294static int hpet_set_periodic(struct clock_event_device *evt, int timer)
310 struct clock_event_device *evt, int timer)
311{ 295{
312 unsigned int cfg, cmp, now; 296 unsigned int cfg, cmp, now;
313 uint64_t delta; 297 uint64_t delta;
314 298
315 switch (mode) { 299 hpet_stop_counter();
316 case CLOCK_EVT_MODE_PERIODIC: 300 delta = ((uint64_t)(NSEC_PER_SEC / HZ)) * evt->mult;
317 hpet_stop_counter(); 301 delta >>= evt->shift;
318 delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult; 302 now = hpet_readl(HPET_COUNTER);
319 delta >>= evt->shift; 303 cmp = now + (unsigned int)delta;
320 now = hpet_readl(HPET_COUNTER); 304 cfg = hpet_readl(HPET_Tn_CFG(timer));
321 cmp = now + (unsigned int) delta; 305 cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
322 cfg = hpet_readl(HPET_Tn_CFG(timer)); 306 HPET_TN_32BIT;
323 cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | 307 hpet_writel(cfg, HPET_Tn_CFG(timer));
324 HPET_TN_SETVAL | HPET_TN_32BIT; 308 hpet_writel(cmp, HPET_Tn_CMP(timer));
325 hpet_writel(cfg, HPET_Tn_CFG(timer)); 309 udelay(1);
326 hpet_writel(cmp, HPET_Tn_CMP(timer)); 310 /*
327 udelay(1); 311 * HPET on AMD 81xx needs a second write (with HPET_TN_SETVAL
328 /* 312 * cleared) to T0_CMP to set the period. The HPET_TN_SETVAL
329 * HPET on AMD 81xx needs a second write (with HPET_TN_SETVAL 313 * bit is automatically cleared after the first write.
330 * cleared) to T0_CMP to set the period. The HPET_TN_SETVAL 314 * (See AMD-8111 HyperTransport I/O Hub Data Sheet,
331 * bit is automatically cleared after the first write. 315 * Publication # 24674)
332 * (See AMD-8111 HyperTransport I/O Hub Data Sheet, 316 */
333 * Publication # 24674) 317 hpet_writel((unsigned int)delta, HPET_Tn_CMP(timer));
334 */ 318 hpet_start_counter();
335 hpet_writel((unsigned int) delta, HPET_Tn_CMP(timer)); 319 hpet_print_config();
336 hpet_start_counter();
337 hpet_print_config();
338 break;
339 320
340 case CLOCK_EVT_MODE_ONESHOT: 321 return 0;
341 cfg = hpet_readl(HPET_Tn_CFG(timer)); 322}
342 cfg &= ~HPET_TN_PERIODIC;
343 cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
344 hpet_writel(cfg, HPET_Tn_CFG(timer));
345 break;
346 323
347 case CLOCK_EVT_MODE_UNUSED: 324static int hpet_set_oneshot(struct clock_event_device *evt, int timer)
348 case CLOCK_EVT_MODE_SHUTDOWN: 325{
349 cfg = hpet_readl(HPET_Tn_CFG(timer)); 326 unsigned int cfg;
350 cfg &= ~HPET_TN_ENABLE;
351 hpet_writel(cfg, HPET_Tn_CFG(timer));
352 break;
353 327
354 case CLOCK_EVT_MODE_RESUME: 328 cfg = hpet_readl(HPET_Tn_CFG(timer));
355 if (timer == 0) { 329 cfg &= ~HPET_TN_PERIODIC;
356 hpet_enable_legacy_int(); 330 cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
357 } else { 331 hpet_writel(cfg, HPET_Tn_CFG(timer));
358 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); 332
359 irq_domain_activate_irq(irq_get_irq_data(hdev->irq)); 333 return 0;
360 disable_irq(hdev->irq); 334}
361 irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu)); 335
362 enable_irq(hdev->irq); 336static int hpet_shutdown(struct clock_event_device *evt, int timer)
363 } 337{
364 hpet_print_config(); 338 unsigned int cfg;
365 break; 339
340 cfg = hpet_readl(HPET_Tn_CFG(timer));
341 cfg &= ~HPET_TN_ENABLE;
342 hpet_writel(cfg, HPET_Tn_CFG(timer));
343
344 return 0;
345}
346
347static int hpet_resume(struct clock_event_device *evt, int timer)
348{
349 if (!timer) {
350 hpet_enable_legacy_int();
351 } else {
352 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
353
354 irq_domain_activate_irq(irq_get_irq_data(hdev->irq));
355 disable_irq(hdev->irq);
356 irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));
357 enable_irq(hdev->irq);
366 } 358 }
359 hpet_print_config();
360
361 return 0;
367} 362}
368 363
369static int hpet_next_event(unsigned long delta, 364static int hpet_next_event(unsigned long delta,
@@ -403,10 +398,24 @@ static int hpet_next_event(unsigned long delta,
403 return res < HPET_MIN_CYCLES ? -ETIME : 0; 398 return res < HPET_MIN_CYCLES ? -ETIME : 0;
404} 399}
405 400
406static void hpet_legacy_set_mode(enum clock_event_mode mode, 401static int hpet_legacy_shutdown(struct clock_event_device *evt)
407 struct clock_event_device *evt) 402{
403 return hpet_shutdown(evt, 0);
404}
405
406static int hpet_legacy_set_oneshot(struct clock_event_device *evt)
407{
408 return hpet_set_oneshot(evt, 0);
409}
410
411static int hpet_legacy_set_periodic(struct clock_event_device *evt)
408{ 412{
409 hpet_set_mode(mode, evt, 0); 413 return hpet_set_periodic(evt, 0);
414}
415
416static int hpet_legacy_resume(struct clock_event_device *evt)
417{
418 return hpet_resume(evt, 0);
410} 419}
411 420
412static int hpet_legacy_next_event(unsigned long delta, 421static int hpet_legacy_next_event(unsigned long delta,
@@ -416,6 +425,22 @@ static int hpet_legacy_next_event(unsigned long delta,
416} 425}
417 426
418/* 427/*
428 * The hpet clock event device
429 */
430static struct clock_event_device hpet_clockevent = {
431 .name = "hpet",
432 .features = CLOCK_EVT_FEAT_PERIODIC |
433 CLOCK_EVT_FEAT_ONESHOT,
434 .set_state_periodic = hpet_legacy_set_periodic,
435 .set_state_oneshot = hpet_legacy_set_oneshot,
436 .set_state_shutdown = hpet_legacy_shutdown,
437 .tick_resume = hpet_legacy_resume,
438 .set_next_event = hpet_legacy_next_event,
439 .irq = 0,
440 .rating = 50,
441};
442
443/*
419 * HPET MSI Support 444 * HPET MSI Support
420 */ 445 */
421#ifdef CONFIG_PCI_MSI 446#ifdef CONFIG_PCI_MSI
@@ -459,11 +484,32 @@ void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg)
459 msg->address_hi = 0; 484 msg->address_hi = 0;
460} 485}
461 486
462static void hpet_msi_set_mode(enum clock_event_mode mode, 487static int hpet_msi_shutdown(struct clock_event_device *evt)
463 struct clock_event_device *evt) 488{
489 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
490
491 return hpet_shutdown(evt, hdev->num);
492}
493
494static int hpet_msi_set_oneshot(struct clock_event_device *evt)
495{
496 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
497
498 return hpet_set_oneshot(evt, hdev->num);
499}
500
501static int hpet_msi_set_periodic(struct clock_event_device *evt)
464{ 502{
465 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); 503 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
466 hpet_set_mode(mode, evt, hdev->num); 504
505 return hpet_set_periodic(evt, hdev->num);
506}
507
508static int hpet_msi_resume(struct clock_event_device *evt)
509{
510 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
511
512 return hpet_resume(evt, hdev->num);
467} 513}
468 514
469static int hpet_msi_next_event(unsigned long delta, 515static int hpet_msi_next_event(unsigned long delta,
@@ -523,10 +569,14 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
523 569
524 evt->rating = 110; 570 evt->rating = 110;
525 evt->features = CLOCK_EVT_FEAT_ONESHOT; 571 evt->features = CLOCK_EVT_FEAT_ONESHOT;
526 if (hdev->flags & HPET_DEV_PERI_CAP) 572 if (hdev->flags & HPET_DEV_PERI_CAP) {
527 evt->features |= CLOCK_EVT_FEAT_PERIODIC; 573 evt->features |= CLOCK_EVT_FEAT_PERIODIC;
574 evt->set_state_periodic = hpet_msi_set_periodic;
575 }
528 576
529 evt->set_mode = hpet_msi_set_mode; 577 evt->set_state_shutdown = hpet_msi_shutdown;
578 evt->set_state_oneshot = hpet_msi_set_oneshot;
579 evt->tick_resume = hpet_msi_resume;
530 evt->set_next_event = hpet_msi_next_event; 580 evt->set_next_event = hpet_msi_next_event;
531 evt->cpumask = cpumask_of(hdev->cpu); 581 evt->cpumask = cpumask_of(hdev->cpu);
532 582