1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4
5 #include <assert.h>
6 #include <hyptypes.h>
7
8 #include <hypregisters.h>
9
10 #include <compiler.h>
11 #include <cpulocal.h>
12 #include <irq.h>
13 #include <object.h>
14 #include <panic.h>
15 #include <partition.h>
16 #include <partition_alloc.h>
17 #include <preempt.h>
18 #include <trace.h>
19
20 #include <events/platform.h>
21
22 #include <asm/barrier.h>
23 #include <asm/sysregs.h>
24 #include <asm/system_registers.h>
25
26 #include "event_handlers.h"
27 #include "platform_pmu.h"
28
29 static hwirq_t *pmu_hwirq;
30 CPULOCAL_DECLARE_STATIC(bool, pmu_irq_active);
31
32 void
platform_pmu_handle_boot_cpu_cold_init(void)33 platform_pmu_handle_boot_cpu_cold_init(void)
34 {
35 // Disable all the interrupts at the startup
36 sysreg64_write(PMINTENCLR_EL1, ~0UL);
37 CPULOCAL(pmu_irq_active) = false;
38
39 if (pmu_hwirq != NULL) {
40 irq_enable_local(pmu_hwirq);
41 }
42 }
43
44 void
platform_pmu_handle_boot_hypervisor_start(void)45 platform_pmu_handle_boot_hypervisor_start(void)
46 {
47 // Create the PMU IRQ
48 hwirq_create_t params = {
49 .irq = PLATFORM_PMU_IRQ,
50 .action = HWIRQ_ACTION_PMU,
51 };
52
53 hwirq_ptr_result_t ret =
54 partition_allocate_hwirq(partition_get_private(), params);
55
56 if (ret.e != OK) {
57 panic("Failed to create PMU IRQ");
58 }
59
60 if (object_activate_hwirq(ret.r) != OK) {
61 panic("Failed to activate PMU IRQ");
62 }
63
64 pmu_hwirq = ret.r;
65
66 irq_enable_local(pmu_hwirq);
67 }
68
69 bool
platform_pmu_is_hw_irq_pending(void)70 platform_pmu_is_hw_irq_pending(void)
71 {
72 uint64_t pmovsset, pmintenset;
73
74 sysreg64_read_ordered(PMINTENSET_EL1, pmintenset, asm_ordering);
75 sysreg64_read_ordered(PMOVSSET_EL0, pmovsset, asm_ordering);
76
77 return (pmovsset & pmintenset) != 0U;
78 }
79
80 void
platform_pmu_hw_irq_deactivate(void)81 platform_pmu_hw_irq_deactivate(void)
82 {
83 if (CPULOCAL(pmu_irq_active)) {
84 CPULOCAL(pmu_irq_active) = false;
85 irq_deactivate(pmu_hwirq);
86 }
87 }
88
89 error_t
arm_pmu_handle_power_cpu_suspend(void)90 arm_pmu_handle_power_cpu_suspend(void)
91 {
92 platform_pmu_hw_irq_deactivate();
93
94 return OK;
95 }
96
97 bool
platform_pmu_handle_irq_received(void)98 platform_pmu_handle_irq_received(void)
99 {
100 bool deactivate = true;
101
102 if (platform_pmu_is_hw_irq_pending()) {
103 CPULOCAL(pmu_irq_active) = true;
104 trigger_platform_pmu_counter_overflow_event();
105
106 // Leave the IRQ active until the guest has cleared the
107 // corresponding overflow flag.
108 deactivate = false;
109 } else {
110 TRACE(DEBUG, INFO, "Spurious PMU IRQ");
111 }
112
113 return deactivate;
114 }
115