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