37
38 static int hpet_init_proxy(int *hpet_vect, iflag_t *hpet_flags);
39 static boolean_t hpet_install_proxy(void);
40 static boolean_t hpet_callback(int code);
41 static boolean_t hpet_cpr(int code);
42 static boolean_t hpet_resume(void);
43 static void hpet_cst_callback(uint32_t code);
44 static boolean_t hpet_deep_idle_config(int code);
45 static int hpet_validate_table(ACPI_TABLE_HPET *hpet_table);
46 static boolean_t hpet_checksum_table(unsigned char *table, unsigned int len);
47 static void *hpet_memory_map(ACPI_TABLE_HPET *hpet_table);
48 static int hpet_start_main_counter(hpet_info_t *hip);
49 static int hpet_stop_main_counter(hpet_info_t *hip);
50 static uint64_t hpet_read_main_counter_value(hpet_info_t *hip);
51 static uint64_t hpet_set_leg_rt_cnf(hpet_info_t *hip, uint32_t new_value);
52 static uint64_t hpet_read_gen_cap(hpet_info_t *hip);
53 static uint64_t hpet_read_gen_config(hpet_info_t *hip);
54 static uint64_t hpet_read_gen_intrpt_stat(hpet_info_t *hip);
55 static uint64_t hpet_read_timer_N_config(hpet_info_t *hip, uint_t n);
56 static hpet_TN_conf_cap_t hpet_convert_timer_N_config(uint64_t conf);
57 /* LINTED E_STATIC_UNUSED */
58 static uint64_t hpet_read_timer_N_comp(hpet_info_t *hip, uint_t n);
59 /* LINTED E_STATIC_UNUSED */
60 static void hpet_write_gen_cap(hpet_info_t *hip, uint64_t l);
61 static void hpet_write_gen_config(hpet_info_t *hip, uint64_t l);
62 static void hpet_write_gen_intrpt_stat(hpet_info_t *hip, uint64_t l);
63 static void hpet_write_timer_N_config(hpet_info_t *hip, uint_t n, uint64_t l);
64 static void hpet_write_timer_N_comp(hpet_info_t *hip, uint_t n, uint64_t l);
65 static void hpet_disable_timer(hpet_info_t *hip, uint32_t timer_n);
66 static void hpet_enable_timer(hpet_info_t *hip, uint32_t timer_n);
67 /* LINTED E_STATIC_UNUSED */
68 static void hpet_write_main_counter_value(hpet_info_t *hip, uint64_t l);
69 static int hpet_get_IOAPIC_intr_capable_timer(hpet_info_t *hip);
70 static int hpet_timer_available(uint32_t allocated_timers, uint32_t n);
71 static void hpet_timer_alloc(uint32_t *allocated_timers, uint32_t n);
72 static void hpet_timer_set_up(hpet_info_t *hip, uint32_t timer_n,
73 uint32_t interrupt);
74 static uint_t hpet_isr(char *arg);
75 static uint32_t hpet_install_interrupt_handler(uint_t (*func)(char *),
76 int vector);
77 static void hpet_uninstall_interrupt_handler(void);
78 static void hpet_expire_all(void);
79 static boolean_t hpet_guaranteed_schedule(hrtime_t required_wakeup_time);
80 static boolean_t hpet_use_hpet_timer(hrtime_t *expire);
81 static void hpet_use_lapic_timer(hrtime_t expire);
82 static void hpet_init_proxy_data(void);
83
84 /*
85 * hpet_state_lock is used to synchronize disabling/enabling deep c-states
86 * and to synchronize suspend/resume.
87 */
88 static kmutex_t hpet_state_lock;
509 hpet_convert_timer_N_config(uint64_t conf)
510 {
511 hpet_TN_conf_cap_t cc = { 0 };
512
513 cc.int_route_cap = HPET_TIMER_N_INT_ROUTE_CAP(conf);
514 cc.fsb_int_del_cap = HPET_TIMER_N_FSB_INT_DEL_CAP(conf);
515 cc.fsb_int_en_cnf = HPET_TIMER_N_FSB_EN_CNF(conf);
516 cc.int_route_cnf = HPET_TIMER_N_INT_ROUTE_CNF(conf);
517 cc.mode32_cnf = HPET_TIMER_N_MODE32_CNF(conf);
518 cc.val_set_cnf = HPET_TIMER_N_VAL_SET_CNF(conf);
519 cc.size_cap = HPET_TIMER_N_SIZE_CAP(conf);
520 cc.per_int_cap = HPET_TIMER_N_PER_INT_CAP(conf);
521 cc.type_cnf = HPET_TIMER_N_TYPE_CNF(conf);
522 cc.int_enb_cnf = HPET_TIMER_N_INT_ENB_CNF(conf);
523 cc.int_type_cnf = HPET_TIMER_N_INT_TYPE_CNF(conf);
524
525 return (cc);
526 }
527
528 static uint64_t
529 hpet_read_timer_N_comp(hpet_info_t *hip, uint_t n)
530 {
531 if (hip->timer_n_config[n].size_cap == 1)
532 return (*(uint64_t *)
533 HPET_TIMER_N_COMP_ADDRESS(hip->logical_address, n));
534 else
535 return (*(uint32_t *)
536 HPET_TIMER_N_COMP_ADDRESS(hip->logical_address, n));
537 }
538
539 static uint64_t
540 hpet_read_main_counter_value(hpet_info_t *hip)
541 {
542 uint64_t value;
543 uint32_t *counter;
544 uint32_t high1, high2, low;
545
546 counter = (uint32_t *)HPET_MAIN_COUNTER_ADDRESS(hip->logical_address);
547
548 /*
549 * 32-bit main counters
550 */
551 if (hip->gen_cap.count_size_cap == 0) {
552 value = (uint64_t)*counter;
553 hip->main_counter_value = value;
554 return (value);
555 }
556
557 /*
558 * HPET spec claims a 64-bit read can be split into two 32-bit reads
559 * by the hardware connection to the HPET.
560 */
561 high2 = counter[1];
562 do {
563 high1 = high2;
564 low = counter[0];
565 high2 = counter[1];
566 } while (high2 != high1);
567
568 value = ((uint64_t)high1 << 32) | low;
569 hip->main_counter_value = value;
570 return (value);
571 }
572
573 static void
574 hpet_write_gen_cap(hpet_info_t *hip, uint64_t l)
575 {
576 *(uint64_t *)HPET_GEN_CAP_ADDRESS(hip->logical_address) = l;
577 }
578
579 static void
580 hpet_write_gen_config(hpet_info_t *hip, uint64_t l)
581 {
582 *(uint64_t *)HPET_GEN_CONFIG_ADDRESS(hip->logical_address) = l;
583 }
584
585 static void
586 hpet_write_gen_intrpt_stat(hpet_info_t *hip, uint64_t l)
587 {
588 *(uint64_t *)HPET_GEN_INTR_STAT_ADDRESS(hip->logical_address) = l;
589 }
590
591 static void
592 hpet_write_timer_N_config(hpet_info_t *hip, uint_t n, uint64_t l)
593 {
594 if (hip->timer_n_config[n].size_cap == 1)
595 *(uint64_t *)HPET_TIMER_N_CONF_ADDRESS(
596 hip->logical_address, n) = l;
597 else
598 *(uint32_t *)HPET_TIMER_N_CONF_ADDRESS(
599 hip->logical_address, n) = (uint32_t)(0xFFFFFFFF & l);
608 static void
609 hpet_disable_timer(hpet_info_t *hip, uint32_t timer_n)
610 {
611 uint64_t l;
612
613 l = hpet_read_timer_N_config(hip, timer_n);
614 l &= ~HPET_TIMER_N_INT_ENB_CNF_BIT;
615 hpet_write_timer_N_config(hip, timer_n, l);
616 }
617
618 static void
619 hpet_enable_timer(hpet_info_t *hip, uint32_t timer_n)
620 {
621 uint64_t l;
622
623 l = hpet_read_timer_N_config(hip, timer_n);
624 l |= HPET_TIMER_N_INT_ENB_CNF_BIT;
625 hpet_write_timer_N_config(hip, timer_n, l);
626 }
627
628 static void
629 hpet_write_main_counter_value(hpet_info_t *hip, uint64_t l)
630 {
631 uint32_t *address;
632
633 /*
634 * HPET spec 1.0a states main counter register should be halted before
635 * it is written to.
636 */
637 ASSERT(!(hpet_read_gen_config(hip) & HPET_GCFR_ENABLE_CNF));
638
639 if (hip->gen_cap.count_size_cap == 1) {
640 *(uint64_t *)HPET_MAIN_COUNTER_ADDRESS(hip->logical_address)
641 = l;
642 } else {
643 address = (uint32_t *)HPET_MAIN_COUNTER_ADDRESS(
644 hip->logical_address);
645
646 address[0] = (uint32_t)(l & 0xFFFFFFFF);
647 }
648 }
649
650 /*
651 * Add the interrupt handler for I/O APIC interrupt number (interrupt line).
652 *
653 * The I/O APIC line (vector) is programmed in ioapic_init_intr() called
654 * from apic_picinit() psm_ops apic_ops entry point after we return from
655 * apic_init() psm_ops entry point.
656 */
657 static uint32_t
658 hpet_install_interrupt_handler(uint_t (*func)(char *), int vector)
659 {
660 uint32_t retval;
661
662 retval = add_avintr(NULL, CBE_HIGH_PIL, (avfunc)func, "HPET Timer",
663 vector, NULL, NULL, NULL, NULL);
664 if (retval == 0) {
665 cmn_err(CE_WARN, "!hpet_acpi: add_avintr() failed");
666 return (AE_BAD_PARAMETER);
667 }
668 return (AE_OK);
669 }
|
37
38 static int hpet_init_proxy(int *hpet_vect, iflag_t *hpet_flags);
39 static boolean_t hpet_install_proxy(void);
40 static boolean_t hpet_callback(int code);
41 static boolean_t hpet_cpr(int code);
42 static boolean_t hpet_resume(void);
43 static void hpet_cst_callback(uint32_t code);
44 static boolean_t hpet_deep_idle_config(int code);
45 static int hpet_validate_table(ACPI_TABLE_HPET *hpet_table);
46 static boolean_t hpet_checksum_table(unsigned char *table, unsigned int len);
47 static void *hpet_memory_map(ACPI_TABLE_HPET *hpet_table);
48 static int hpet_start_main_counter(hpet_info_t *hip);
49 static int hpet_stop_main_counter(hpet_info_t *hip);
50 static uint64_t hpet_read_main_counter_value(hpet_info_t *hip);
51 static uint64_t hpet_set_leg_rt_cnf(hpet_info_t *hip, uint32_t new_value);
52 static uint64_t hpet_read_gen_cap(hpet_info_t *hip);
53 static uint64_t hpet_read_gen_config(hpet_info_t *hip);
54 static uint64_t hpet_read_gen_intrpt_stat(hpet_info_t *hip);
55 static uint64_t hpet_read_timer_N_config(hpet_info_t *hip, uint_t n);
56 static hpet_TN_conf_cap_t hpet_convert_timer_N_config(uint64_t conf);
57 static void hpet_write_gen_config(hpet_info_t *hip, uint64_t l);
58 static void hpet_write_gen_intrpt_stat(hpet_info_t *hip, uint64_t l);
59 static void hpet_write_timer_N_config(hpet_info_t *hip, uint_t n, uint64_t l);
60 static void hpet_write_timer_N_comp(hpet_info_t *hip, uint_t n, uint64_t l);
61 static void hpet_disable_timer(hpet_info_t *hip, uint32_t timer_n);
62 static void hpet_enable_timer(hpet_info_t *hip, uint32_t timer_n);
63 static int hpet_get_IOAPIC_intr_capable_timer(hpet_info_t *hip);
64 static int hpet_timer_available(uint32_t allocated_timers, uint32_t n);
65 static void hpet_timer_alloc(uint32_t *allocated_timers, uint32_t n);
66 static void hpet_timer_set_up(hpet_info_t *hip, uint32_t timer_n,
67 uint32_t interrupt);
68 static uint_t hpet_isr(char *arg);
69 static uint32_t hpet_install_interrupt_handler(uint_t (*func)(char *),
70 int vector);
71 static void hpet_uninstall_interrupt_handler(void);
72 static void hpet_expire_all(void);
73 static boolean_t hpet_guaranteed_schedule(hrtime_t required_wakeup_time);
74 static boolean_t hpet_use_hpet_timer(hrtime_t *expire);
75 static void hpet_use_lapic_timer(hrtime_t expire);
76 static void hpet_init_proxy_data(void);
77
78 /*
79 * hpet_state_lock is used to synchronize disabling/enabling deep c-states
80 * and to synchronize suspend/resume.
81 */
82 static kmutex_t hpet_state_lock;
503 hpet_convert_timer_N_config(uint64_t conf)
504 {
505 hpet_TN_conf_cap_t cc = { 0 };
506
507 cc.int_route_cap = HPET_TIMER_N_INT_ROUTE_CAP(conf);
508 cc.fsb_int_del_cap = HPET_TIMER_N_FSB_INT_DEL_CAP(conf);
509 cc.fsb_int_en_cnf = HPET_TIMER_N_FSB_EN_CNF(conf);
510 cc.int_route_cnf = HPET_TIMER_N_INT_ROUTE_CNF(conf);
511 cc.mode32_cnf = HPET_TIMER_N_MODE32_CNF(conf);
512 cc.val_set_cnf = HPET_TIMER_N_VAL_SET_CNF(conf);
513 cc.size_cap = HPET_TIMER_N_SIZE_CAP(conf);
514 cc.per_int_cap = HPET_TIMER_N_PER_INT_CAP(conf);
515 cc.type_cnf = HPET_TIMER_N_TYPE_CNF(conf);
516 cc.int_enb_cnf = HPET_TIMER_N_INT_ENB_CNF(conf);
517 cc.int_type_cnf = HPET_TIMER_N_INT_TYPE_CNF(conf);
518
519 return (cc);
520 }
521
522 static uint64_t
523 hpet_read_main_counter_value(hpet_info_t *hip)
524 {
525 uint64_t value;
526 uint32_t *counter;
527 uint32_t high1, high2, low;
528
529 counter = (uint32_t *)HPET_MAIN_COUNTER_ADDRESS(hip->logical_address);
530
531 /*
532 * 32-bit main counters
533 */
534 if (hip->gen_cap.count_size_cap == 0) {
535 value = (uint64_t)*counter;
536 hip->main_counter_value = value;
537 return (value);
538 }
539
540 /*
541 * HPET spec claims a 64-bit read can be split into two 32-bit reads
542 * by the hardware connection to the HPET.
543 */
544 high2 = counter[1];
545 do {
546 high1 = high2;
547 low = counter[0];
548 high2 = counter[1];
549 } while (high2 != high1);
550
551 value = ((uint64_t)high1 << 32) | low;
552 hip->main_counter_value = value;
553 return (value);
554 }
555
556 static void
557 hpet_write_gen_config(hpet_info_t *hip, uint64_t l)
558 {
559 *(uint64_t *)HPET_GEN_CONFIG_ADDRESS(hip->logical_address) = l;
560 }
561
562 static void
563 hpet_write_gen_intrpt_stat(hpet_info_t *hip, uint64_t l)
564 {
565 *(uint64_t *)HPET_GEN_INTR_STAT_ADDRESS(hip->logical_address) = l;
566 }
567
568 static void
569 hpet_write_timer_N_config(hpet_info_t *hip, uint_t n, uint64_t l)
570 {
571 if (hip->timer_n_config[n].size_cap == 1)
572 *(uint64_t *)HPET_TIMER_N_CONF_ADDRESS(
573 hip->logical_address, n) = l;
574 else
575 *(uint32_t *)HPET_TIMER_N_CONF_ADDRESS(
576 hip->logical_address, n) = (uint32_t)(0xFFFFFFFF & l);
585 static void
586 hpet_disable_timer(hpet_info_t *hip, uint32_t timer_n)
587 {
588 uint64_t l;
589
590 l = hpet_read_timer_N_config(hip, timer_n);
591 l &= ~HPET_TIMER_N_INT_ENB_CNF_BIT;
592 hpet_write_timer_N_config(hip, timer_n, l);
593 }
594
595 static void
596 hpet_enable_timer(hpet_info_t *hip, uint32_t timer_n)
597 {
598 uint64_t l;
599
600 l = hpet_read_timer_N_config(hip, timer_n);
601 l |= HPET_TIMER_N_INT_ENB_CNF_BIT;
602 hpet_write_timer_N_config(hip, timer_n, l);
603 }
604
605 /*
606 * Add the interrupt handler for I/O APIC interrupt number (interrupt line).
607 *
608 * The I/O APIC line (vector) is programmed in ioapic_init_intr() called
609 * from apic_picinit() psm_ops apic_ops entry point after we return from
610 * apic_init() psm_ops entry point.
611 */
612 static uint32_t
613 hpet_install_interrupt_handler(uint_t (*func)(char *), int vector)
614 {
615 uint32_t retval;
616
617 retval = add_avintr(NULL, CBE_HIGH_PIL, (avfunc)func, "HPET Timer",
618 vector, NULL, NULL, NULL, NULL);
619 if (retval == 0) {
620 cmn_err(CE_WARN, "!hpet_acpi: add_avintr() failed");
621 return (AE_BAD_PARAMETER);
622 }
623 return (AE_OK);
624 }
|