xref: /netbsd-src/sys/arch/arm/acpi/acpi_cpu_md.c (revision 30d28f20005de11b20499fed000071fb0a455337)
1 /* $NetBSD: acpi_cpu_md.c,v 1.1 2020/12/07 10:57:41 jmcneill Exp $ */
2 
3 /*-
4  * Copyright (c) 2020 Jared McNeill <jmcneill@invisible.ca>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: acpi_cpu_md.c,v 1.1 2020/12/07 10:57:41 jmcneill Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/cpu.h>
35 #include <sys/cpufreq.h>
36 #include <sys/device.h>
37 #include <sys/sysctl.h>
38 
39 #include <dev/acpi/acpica.h>
40 #include <dev/acpi/acpivar.h>
41 #include <dev/acpi/acpi_cpu.h>
42 #include <dev/acpi/acpi_util.h>
43 
44 static struct sysctllog *acpicpu_log = NULL;
45 
46 /*
47  * acpicpu_md_match --
48  *
49  * 	Match against an ACPI processor device node (either a device
50  * 	with HID "ACPI0007" or a processor node) and return a pointer
51  * 	to the corresponding CPU device's 'cpu_info' struct.
52  *
53  */
54 struct cpu_info *
acpicpu_md_match(device_t parent,cfdata_t cf,void * aux)55 acpicpu_md_match(device_t parent, cfdata_t cf, void *aux)
56 {
57 	struct acpi_attach_args * const aa = aux;
58 
59 	return acpi_match_cpu_handle(aa->aa_node->ad_handle);
60 }
61 
62 /*
63  * acpicpu_md_attach --
64  *
65  * 	Return a pointer to the CPU device's 'cpu_info' struct
66  * 	corresponding with this device.
67  *
68  */
69 struct cpu_info *
acpicpu_md_attach(device_t parent,device_t self,void * aux)70 acpicpu_md_attach(device_t parent, device_t self, void *aux)
71 {
72 	struct acpi_attach_args * const aa = aux;
73 
74 	return acpi_match_cpu_handle(aa->aa_node->ad_handle);
75 }
76 
77 /*
78  * acpicpu_md_flags --
79  *
80  * 	Return a bitmask of ACPICPU_FLAG_* platform specific quirks.
81  *
82  */
83 uint32_t
acpicpu_md_flags(void)84 acpicpu_md_flags(void)
85 {
86 	return 0;
87 }
88 
89 /*
90  * acpicpu_md_cstate_start --
91  *
92  * 	Not implemented.
93  *
94  */
95 int
acpicpu_md_cstate_start(struct acpicpu_softc * sc)96 acpicpu_md_cstate_start(struct acpicpu_softc *sc)
97 {
98 	return EINVAL;
99 }
100 
101 /*
102  * acpicpu_md_cstate_stop --
103  *
104  * 	Not implemented.
105  *
106  */
107 int
acpicpu_md_cstate_stop(void)108 acpicpu_md_cstate_stop(void)
109 {
110 	return EALREADY;
111 }
112 
113 /*
114  * acpicpu_md_cstate_enter --
115  *
116  * 	Not implemented.
117  *
118  */
119 void
acpicpu_md_cstate_enter(int method,int state)120 acpicpu_md_cstate_enter(int method, int state)
121 {
122 }
123 
124 /*
125  * acpicpu_md_pstate_init --
126  *
127  * 	MD initialization for P-state support. Nothing to do here.
128  *
129  */
130 int
acpicpu_md_pstate_init(struct acpicpu_softc * sc)131 acpicpu_md_pstate_init(struct acpicpu_softc *sc)
132 {
133 	return 0;
134 }
135 
136 /*
137  * acpicpu_md_pstate_sysctl_current --
138  *
139  * 	sysctl(9) callback for retrieving the current CPU frequency.
140  *
141  */
142 static int
acpicpu_md_pstate_sysctl_current(SYSCTLFN_ARGS)143 acpicpu_md_pstate_sysctl_current(SYSCTLFN_ARGS)
144 {
145 	struct sysctlnode node;
146 	uint32_t freq;
147 	int error;
148 
149 	freq = cpufreq_get(curcpu());
150 	if (freq == 0)
151 		return ENXIO;
152 
153 	node = *rnode;
154 	node.sysctl_data = &freq;
155 
156 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
157 	if (error || newp == NULL)
158 		return error;
159 
160 	return 0;
161 }
162 
163 /*
164  * acpicpu_md_pstate_sysctl_target --
165  *
166  * 	sysctl(9) callback for setting the target CPU frequency.
167  *
168  */
169 static int
acpicpu_md_pstate_sysctl_target(SYSCTLFN_ARGS)170 acpicpu_md_pstate_sysctl_target(SYSCTLFN_ARGS)
171 {
172 	struct sysctlnode node;
173 	uint32_t freq;
174 	int error;
175 
176 	freq = cpufreq_get(curcpu());
177 	if (freq == 0)
178 		return ENXIO;
179 
180 	node = *rnode;
181 	node.sysctl_data = &freq;
182 
183 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
184 	if (error || newp == NULL)
185 		return error;
186 
187 	cpufreq_set_all(freq);
188 
189 	return 0;
190 }
191 
192 /*
193  * acpicpu_md_pstate_sysctl_available --
194  *
195  * 	sysctl(9) callback for returning a list of supported CPU frequencies.
196  *
197  */
198 static int
acpicpu_md_pstate_sysctl_available(SYSCTLFN_ARGS)199 acpicpu_md_pstate_sysctl_available(SYSCTLFN_ARGS)
200 {
201 	struct acpicpu_softc * const sc = rnode->sysctl_data;
202 	struct sysctlnode node;
203 	char buf[1024];
204 	size_t len;
205 	uint32_t i;
206 	int error;
207 
208 	memset(buf, 0, sizeof(buf));
209 
210 	mutex_enter(&sc->sc_mtx);
211 	for (len = 0, i = sc->sc_pstate_max; i < sc->sc_pstate_count; i++) {
212 		if (sc->sc_pstate[i].ps_freq == 0)
213 			continue;
214 		if (len >= sizeof(buf))
215 			break;
216 		len += snprintf(buf + len, sizeof(buf) - len, "%u%s",
217 		    sc->sc_pstate[i].ps_freq,
218 		    i < (sc->sc_pstate_count - 1) ? " " : "");
219 	}
220 	mutex_exit(&sc->sc_mtx);
221 
222 	node = *rnode;
223 	node.sysctl_data = buf;
224 
225 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
226 	if (error || newp == NULL)
227 		return error;
228 
229 	return 0;
230 }
231 
232 /*
233  * acpicpu_md_pstate_start --
234  *
235  * 	MD startup for P-state support. Create sysctls here.
236  *
237  */
238 int
acpicpu_md_pstate_start(struct acpicpu_softc * sc)239 acpicpu_md_pstate_start(struct acpicpu_softc *sc)
240 {
241 	const struct sysctlnode *mnode, *cnode, *fnode, *node;
242 	int error;
243 
244 	error = sysctl_createv(&acpicpu_log, 0, NULL, &mnode,
245 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
246 	    NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
247 	if (error) {
248 		goto teardown;
249 	}
250 
251 	error = sysctl_createv(&acpicpu_log, 0, &mnode, &cnode,
252 	    0, CTLTYPE_NODE, "cpu", NULL,
253 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
254 	if (error) {
255 		goto teardown;
256 	}
257 
258 	error = sysctl_createv(&acpicpu_log, 0, &cnode, &fnode,
259 	    0, CTLTYPE_NODE, "frequency", NULL,
260 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
261 	if (error) {
262 		goto teardown;
263 	}
264 
265 	error = sysctl_createv(&acpicpu_log, 0, &fnode, &node,
266 	    CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL,
267 	    acpicpu_md_pstate_sysctl_target, 0, NULL, 0, CTL_CREATE, CTL_EOL);
268 	if (error) {
269 		goto teardown;
270 	}
271 
272 	error = sysctl_createv(&acpicpu_log, 0, &fnode, &node,
273 	    CTLFLAG_READONLY, CTLTYPE_INT, "current", NULL,
274 	    acpicpu_md_pstate_sysctl_current, 0, NULL, 0, CTL_CREATE, CTL_EOL);
275 	if (error) {
276 		goto teardown;
277 	}
278 
279 	error = sysctl_createv(&acpicpu_log, 0, &fnode, &node,
280 	    CTLFLAG_READONLY, CTLTYPE_STRING, "available", NULL,
281 	    acpicpu_md_pstate_sysctl_available, 0, (void *)sc, 0, CTL_CREATE,
282 	    CTL_EOL);
283 	if (error) {
284 		goto teardown;
285 	}
286 
287 	return 0;
288 
289 teardown:
290 	if (acpicpu_log != NULL) {
291 		sysctl_teardown(&acpicpu_log);
292 		acpicpu_log = NULL;
293 	}
294 
295 	return error;
296 }
297 
298 /*
299  * acpicpu_md_pstate_stop --
300  *
301  * 	MD shutdown for P-state support. Destroy sysctls here.
302  *
303  */
304 int
acpicpu_md_pstate_stop(void)305 acpicpu_md_pstate_stop(void)
306 {
307 	if (acpicpu_log != NULL) {
308 		sysctl_teardown(&acpicpu_log);
309 		acpicpu_log = NULL;
310 	}
311 
312 	return 0;
313 }
314 
315 /*
316  * acpicpu_md_pstate_get --
317  *
318  * 	Fixed hardware access method for getting current processor P-state.
319  * 	Not implemented.
320  *
321  */
322 int
acpicpu_md_pstate_get(struct acpicpu_softc * sc,uint32_t * freq)323 acpicpu_md_pstate_get(struct acpicpu_softc *sc, uint32_t *freq)
324 {
325 	return EINVAL;
326 }
327 
328 /*
329  * acpicpu_md_pstate_set --
330  *
331  * 	Fixed hardware access method for setting current processor P-state.
332  * 	Not implemented.
333  *
334  */
335 int
acpicpu_md_pstate_set(struct acpicpu_pstate * ps)336 acpicpu_md_pstate_set(struct acpicpu_pstate *ps)
337 {
338 	return EINVAL;
339 }
340 
341 /*
342  * acpicpu_md_tstate_get --
343  *
344  * 	Fixed hardware access method for getting current processor T-state.
345  * 	Not implemented.
346  *
347  */
348 int
acpicpu_md_tstate_get(struct acpicpu_softc * sc,uint32_t * percent)349 acpicpu_md_tstate_get(struct acpicpu_softc *sc, uint32_t *percent)
350 {
351 	return EINVAL;
352 }
353 
354 /*
355  * acpicpu_md_tstate_set --
356  *
357  * 	Fixed hardware access method for setting current processor T-state.
358  * 	Not implemented.
359  *
360  */
361 int
acpicpu_md_tstate_set(struct acpicpu_tstate * ts)362 acpicpu_md_tstate_set(struct acpicpu_tstate *ts)
363 {
364 	return EINVAL;
365 }
366