1 /*
2  * Copyright (c) 2017 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: qdf_cpuhp
21  * This file provides OS dependent QDF CPU hotplug APIs
22  */
23 
24 #include "i_qdf_cpuhp.h"
25 #include "qdf_trace.h"
26 #include "linux/cpu.h"
27 #include "linux/notifier.h"
28 #include "linux/version.h"
29 
30 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)
31 #include "linux/cpuhotplug.h"
32 #endif
33 
34 static __qdf_cpuhp_emit __qdf_cpuhp_on_up;
35 static __qdf_cpuhp_emit __qdf_cpuhp_on_down;
36 
37 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
qdf_cpuhp_legacy_handler(struct notifier_block * block,unsigned long state,void * hcpu)38 static int qdf_cpuhp_legacy_handler(struct notifier_block *block,
39 				    unsigned long state,
40 				    void *hcpu)
41 {
42 	unsigned long cpu = (unsigned long)hcpu;
43 
44 	switch (state) {
45 	case CPU_ONLINE:
46 		__qdf_cpuhp_on_up(cpu);
47 		break;
48 
49 	case CPU_DOWN_PREPARE:
50 	case CPU_DOWN_PREPARE_FROZEN:
51 		__qdf_cpuhp_on_down(cpu);
52 		break;
53 
54 	default:
55 		break;
56 	}
57 
58 	return NOTIFY_OK;
59 }
60 
61 static struct notifier_block qdf_cpuhp_notifier_block = {
62 	.notifier_call = qdf_cpuhp_legacy_handler,
63 };
64 
qdf_cpuhp_register_callbacks(void)65 static inline void qdf_cpuhp_register_callbacks(void)
66 {
67 	register_hotcpu_notifier(&qdf_cpuhp_notifier_block);
68 }
69 
qdf_cpuhp_unregister_callbacks(void)70 static inline void qdf_cpuhp_unregister_callbacks(void)
71 {
72 	unregister_hotcpu_notifier(&qdf_cpuhp_notifier_block);
73 }
74 #else
75 static enum cpuhp_state registered_hotplug_state;
76 
qdf_cpuhp_up_handler(unsigned int cpu)77 static int qdf_cpuhp_up_handler(unsigned int cpu)
78 {
79 	__qdf_cpuhp_on_up(cpu);
80 
81 	return 0;
82 }
83 
qdf_cpuhp_down_handler(unsigned int cpu)84 static int qdf_cpuhp_down_handler(unsigned int cpu)
85 {
86 	__qdf_cpuhp_on_down(cpu);
87 
88 	return 0;
89 }
90 
qdf_cpuhp_register_callbacks(void)91 static inline void qdf_cpuhp_register_callbacks(void)
92 {
93 	registered_hotplug_state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
94 						     "wlan/qca-qdf:online",
95 						     qdf_cpuhp_up_handler,
96 						     qdf_cpuhp_down_handler);
97 }
98 
qdf_cpuhp_unregister_callbacks(void)99 static inline void qdf_cpuhp_unregister_callbacks(void)
100 {
101 	QDF_BUG(registered_hotplug_state);
102 	if (registered_hotplug_state)
103 		cpuhp_remove_state(registered_hotplug_state);
104 }
105 #endif /* KERNEL_VERSION(4, 6, 0) */
106 
__qdf_cpuhp_os_init(__qdf_cpuhp_emit on_up,__qdf_cpuhp_emit on_down)107 void __qdf_cpuhp_os_init(__qdf_cpuhp_emit on_up, __qdf_cpuhp_emit on_down)
108 {
109 	__qdf_cpuhp_on_up = on_up;
110 	__qdf_cpuhp_on_down = on_down;
111 
112 	qdf_cpuhp_register_callbacks();
113 }
114 
__qdf_cpuhp_os_deinit(void)115 void __qdf_cpuhp_os_deinit(void)
116 {
117 	qdf_cpuhp_unregister_callbacks();
118 }
119 
120