aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/hpet.c295
1 files changed, 293 insertions, 2 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 03d3655734b4..31e9191b7e19 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -21,10 +21,19 @@
21 NSEC = 10^-9 */ 21 NSEC = 10^-9 */
22#define FSEC_PER_NSEC 1000000L 22#define FSEC_PER_NSEC 1000000L
23 23
24#define HPET_DEV_USED_BIT 2
25#define HPET_DEV_USED (1 << HPET_DEV_USED_BIT)
26#define HPET_DEV_VALID 0x8
27#define HPET_DEV_FSB_CAP 0x1000
28#define HPET_DEV_PERI_CAP 0x2000
29
30#define EVT_TO_HPET_DEV(evt) container_of(evt, struct hpet_dev, evt)
31
24/* 32/*
25 * HPET address is set in acpi/boot.c, when an ACPI entry exists 33 * HPET address is set in acpi/boot.c, when an ACPI entry exists
26 */ 34 */
27unsigned long hpet_address; 35unsigned long hpet_address;
36unsigned long hpet_num_timers;
28static void __iomem *hpet_virt_address; 37static void __iomem *hpet_virt_address;
29 38
30struct hpet_dev { 39struct hpet_dev {
@@ -36,6 +45,10 @@ struct hpet_dev {
36 char name[10]; 45 char name[10];
37}; 46};
38 47
48static struct hpet_dev *hpet_devs;
49
50static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev);
51
39unsigned long hpet_readl(unsigned long a) 52unsigned long hpet_readl(unsigned long a)
40{ 53{
41 return readl(hpet_virt_address + a); 54 return readl(hpet_virt_address + a);
@@ -145,6 +158,16 @@ static void hpet_reserve_platform_timers(unsigned long id)
145 Tn_INT_ROUTE_CNF_MASK) >> Tn_INT_ROUTE_CNF_SHIFT; 158 Tn_INT_ROUTE_CNF_MASK) >> Tn_INT_ROUTE_CNF_SHIFT;
146 } 159 }
147 160
161 for (i = 0; i < nrtimers; i++) {
162 struct hpet_dev *hdev = &hpet_devs[i];
163
164 if (!(hdev->flags & HPET_DEV_VALID))
165 continue;
166
167 hd.hd_irq[hdev->num] = hdev->irq;
168 hpet_reserve_timer(&hd, hdev->num);
169 }
170
148 hpet_alloc(&hd); 171 hpet_alloc(&hd);
149 172
150} 173}
@@ -238,6 +261,8 @@ static void hpet_legacy_clockevent_register(void)
238 printk(KERN_DEBUG "hpet clockevent registered\n"); 261 printk(KERN_DEBUG "hpet clockevent registered\n");
239} 262}
240 263
264static int hpet_setup_msi_irq(unsigned int irq);
265
241static void hpet_set_mode(enum clock_event_mode mode, 266static void hpet_set_mode(enum clock_event_mode mode,
242 struct clock_event_device *evt, int timer) 267 struct clock_event_device *evt, int timer)
243{ 268{
@@ -279,7 +304,15 @@ static void hpet_set_mode(enum clock_event_mode mode,
279 break; 304 break;
280 305
281 case CLOCK_EVT_MODE_RESUME: 306 case CLOCK_EVT_MODE_RESUME:
282 hpet_enable_legacy_int(); 307 if (timer == 0) {
308 hpet_enable_legacy_int();
309 } else {
310 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
311 hpet_setup_msi_irq(hdev->irq);
312 disable_irq(hdev->irq);
313 irq_set_affinity(hdev->irq, cpumask_of_cpu(hdev->cpu));
314 enable_irq(hdev->irq);
315 }
283 break; 316 break;
284 } 317 }
285} 318}
@@ -318,7 +351,7 @@ static int hpet_legacy_next_event(unsigned long delta,
318/* 351/*
319 * HPET MSI Support 352 * HPET MSI Support
320 */ 353 */
321 354#ifdef CONFIG_PCI_MSI
322void hpet_msi_unmask(unsigned int irq) 355void hpet_msi_unmask(unsigned int irq)
323{ 356{
324 struct hpet_dev *hdev = get_irq_data(irq); 357 struct hpet_dev *hdev = get_irq_data(irq);
@@ -358,6 +391,253 @@ void hpet_msi_read(unsigned int irq, struct msi_msg *msg)
358 msg->address_hi = 0; 391 msg->address_hi = 0;
359} 392}
360 393
394static void hpet_msi_set_mode(enum clock_event_mode mode,
395 struct clock_event_device *evt)
396{
397 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
398 hpet_set_mode(mode, evt, hdev->num);
399}
400
401static int hpet_msi_next_event(unsigned long delta,
402 struct clock_event_device *evt)
403{
404 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
405 return hpet_next_event(delta, evt, hdev->num);
406}
407
408static int hpet_setup_msi_irq(unsigned int irq)
409{
410 if (arch_setup_hpet_msi(irq)) {
411 destroy_irq(irq);
412 return -EINVAL;
413 }
414 return 0;
415}
416
417static int hpet_assign_irq(struct hpet_dev *dev)
418{
419 unsigned int irq;
420
421 irq = create_irq();
422 if (!irq)
423 return -EINVAL;
424
425 set_irq_data(irq, dev);
426
427 if (hpet_setup_msi_irq(irq))
428 return -EINVAL;
429
430 dev->irq = irq;
431 return 0;
432}
433
434static irqreturn_t hpet_interrupt_handler(int irq, void *data)
435{
436 struct hpet_dev *dev = (struct hpet_dev *)data;
437 struct clock_event_device *hevt = &dev->evt;
438
439 if (!hevt->event_handler) {
440 printk(KERN_INFO "Spurious HPET timer interrupt on HPET timer %d\n",
441 dev->num);
442 return IRQ_HANDLED;
443 }
444
445 hevt->event_handler(hevt);
446 return IRQ_HANDLED;
447}
448
449static int hpet_setup_irq(struct hpet_dev *dev)
450{
451
452 if (request_irq(dev->irq, hpet_interrupt_handler,
453 IRQF_SHARED|IRQF_NOBALANCING, dev->name, dev))
454 return -1;
455
456 disable_irq(dev->irq);
457 irq_set_affinity(dev->irq, cpumask_of_cpu(dev->cpu));
458 enable_irq(dev->irq);
459
460 return 0;
461}
462
463/* This should be called in specific @cpu */
464static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
465{
466 struct clock_event_device *evt = &hdev->evt;
467 uint64_t hpet_freq;
468
469 WARN_ON(cpu != smp_processor_id());
470 if (!(hdev->flags & HPET_DEV_VALID))
471 return;
472
473 if (hpet_setup_msi_irq(hdev->irq))
474 return;
475
476 hdev->cpu = cpu;
477 per_cpu(cpu_hpet_dev, cpu) = hdev;
478 evt->name = hdev->name;
479 hpet_setup_irq(hdev);
480 evt->irq = hdev->irq;
481
482 evt->rating = 110;
483 evt->features = CLOCK_EVT_FEAT_ONESHOT;
484 if (hdev->flags & HPET_DEV_PERI_CAP)
485 evt->features |= CLOCK_EVT_FEAT_PERIODIC;
486
487 evt->set_mode = hpet_msi_set_mode;
488 evt->set_next_event = hpet_msi_next_event;
489 evt->shift = 32;
490
491 /*
492 * The period is a femto seconds value. We need to calculate the
493 * scaled math multiplication factor for nanosecond to hpet tick
494 * conversion.
495 */
496 hpet_freq = 1000000000000000ULL;
497 do_div(hpet_freq, hpet_period);
498 evt->mult = div_sc((unsigned long) hpet_freq,
499 NSEC_PER_SEC, evt->shift);
500 /* Calculate the max delta */
501 evt->max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, evt);
502 /* 5 usec minimum reprogramming delta. */
503 evt->min_delta_ns = 5000;
504
505 evt->cpumask = cpumask_of_cpu(hdev->cpu);
506 clockevents_register_device(evt);
507}
508
509#ifdef CONFIG_HPET
510/* Reserve at least one timer for userspace (/dev/hpet) */
511#define RESERVE_TIMERS 1
512#else
513#define RESERVE_TIMERS 0
514#endif
515void hpet_msi_capability_lookup(unsigned int start_timer)
516{
517 unsigned int id;
518 unsigned int num_timers;
519 unsigned int num_timers_used = 0;
520 int i;
521
522 id = hpet_readl(HPET_ID);
523
524 num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT);
525 num_timers++; /* Value read out starts from 0 */
526
527 hpet_devs = kzalloc(sizeof(struct hpet_dev) * num_timers, GFP_KERNEL);
528 if (!hpet_devs)
529 return;
530
531 hpet_num_timers = num_timers;
532
533 for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) {
534 struct hpet_dev *hdev = &hpet_devs[num_timers_used];
535 unsigned long cfg = hpet_readl(HPET_Tn_CFG(i));
536
537 /* Only consider HPET timer with MSI support */
538 if (!(cfg & HPET_TN_FSB_CAP))
539 continue;
540
541 hdev->flags = 0;
542 if (cfg & HPET_TN_PERIODIC_CAP)
543 hdev->flags |= HPET_DEV_PERI_CAP;
544 hdev->num = i;
545
546 sprintf(hdev->name, "hpet%d", i);
547 if (hpet_assign_irq(hdev))
548 continue;
549
550 hdev->flags |= HPET_DEV_FSB_CAP;
551 hdev->flags |= HPET_DEV_VALID;
552 num_timers_used++;
553 if (num_timers_used == num_possible_cpus())
554 break;
555 }
556
557 printk(KERN_INFO "HPET: %d timers in total, %d timers will be used for per-cpu timer\n",
558 num_timers, num_timers_used);
559}
560
561static struct hpet_dev *hpet_get_unused_timer(void)
562{
563 int i;
564
565 if (!hpet_devs)
566 return NULL;
567
568 for (i = 0; i < hpet_num_timers; i++) {
569 struct hpet_dev *hdev = &hpet_devs[i];
570
571 if (!(hdev->flags & HPET_DEV_VALID))
572 continue;
573 if (test_and_set_bit(HPET_DEV_USED_BIT,
574 (unsigned long *)&hdev->flags))
575 continue;
576 return hdev;
577 }
578 return NULL;
579}
580
581struct hpet_work_struct {
582 struct delayed_work work;
583 struct completion complete;
584};
585
586static void hpet_work(struct work_struct *w)
587{
588 struct hpet_dev *hdev;
589 int cpu = smp_processor_id();
590 struct hpet_work_struct *hpet_work;
591
592 hpet_work = container_of(w, struct hpet_work_struct, work.work);
593
594 hdev = hpet_get_unused_timer();
595 if (hdev)
596 init_one_hpet_msi_clockevent(hdev, cpu);
597
598 complete(&hpet_work->complete);
599}
600
601static int hpet_cpuhp_notify(struct notifier_block *n,
602 unsigned long action, void *hcpu)
603{
604 unsigned long cpu = (unsigned long)hcpu;
605 struct hpet_work_struct work;
606 struct hpet_dev *hdev = per_cpu(cpu_hpet_dev, cpu);
607
608 switch (action & 0xf) {
609 case CPU_ONLINE:
610 INIT_DELAYED_WORK(&work.work, hpet_work);
611 init_completion(&work.complete);
612 /* FIXME: add schedule_work_on() */
613 schedule_delayed_work_on(cpu, &work.work, 0);
614 wait_for_completion(&work.complete);
615 break;
616 case CPU_DEAD:
617 if (hdev) {
618 free_irq(hdev->irq, hdev);
619 hdev->flags &= ~HPET_DEV_USED;
620 per_cpu(cpu_hpet_dev, cpu) = NULL;
621 }
622 break;
623 }
624 return NOTIFY_OK;
625}
626#else
627
628void hpet_msi_capability_lookup(unsigned int start_timer)
629{
630 return;
631}
632
633static int hpet_cpuhp_notify(struct notifier_block *n,
634 unsigned long action, void *hcpu)
635{
636 return NOTIFY_OK;
637}
638
639#endif
640
361/* 641/*
362 * Clock source related code 642 * Clock source related code
363 */ 643 */
@@ -493,8 +773,10 @@ int __init hpet_enable(void)
493 773
494 if (id & HPET_ID_LEGSUP) { 774 if (id & HPET_ID_LEGSUP) {
495 hpet_legacy_clockevent_register(); 775 hpet_legacy_clockevent_register();
776 hpet_msi_capability_lookup(2);
496 return 1; 777 return 1;
497 } 778 }
779 hpet_msi_capability_lookup(0);
498 return 0; 780 return 0;
499 781
500out_nohpet: 782out_nohpet:
@@ -511,6 +793,8 @@ out_nohpet:
511 */ 793 */
512static __init int hpet_late_init(void) 794static __init int hpet_late_init(void)
513{ 795{
796 int cpu;
797
514 if (boot_hpet_disable) 798 if (boot_hpet_disable)
515 return -ENODEV; 799 return -ENODEV;
516 800
@@ -526,6 +810,13 @@ static __init int hpet_late_init(void)
526 810
527 hpet_reserve_platform_timers(hpet_readl(HPET_ID)); 811 hpet_reserve_platform_timers(hpet_readl(HPET_ID));
528 812
813 for_each_online_cpu(cpu) {
814 hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu);
815 }
816
817 /* This notifier should be called after workqueue is ready */
818 hotcpu_notifier(hpet_cpuhp_notify, -20);
819
529 return 0; 820 return 0;
530} 821}
531fs_initcall(hpet_late_init); 822fs_initcall(hpet_late_init);