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 44static 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 */ 54struct cpu_info * 55acpicpu_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 */ 69struct cpu_info * 70acpicpu_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 */ 83uint32_t 84acpicpu_md_flags(void) 85{ 86 return 0; 87} 88 89/* 90 * acpicpu_md_cstate_start -- 91 * 92 * Not implemented. 93 * 94 */ 95int 96acpicpu_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 */ 107int 108acpicpu_md_cstate_stop(void) 109{ 110 return EALREADY; 111} 112 113/* 114 * acpicpu_md_cstate_enter -- 115 * 116 * Not implemented. 117 * 118 */ 119void 120acpicpu_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 */ 130int 131acpicpu_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 */ 142static int 143acpicpu_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 */ 169static int 170acpicpu_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 */ 198static int 199acpicpu_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 */ 238int 239acpicpu_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 289teardown: 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 */ 304int 305acpicpu_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 */ 322int 323acpicpu_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 */ 335int 336acpicpu_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 */ 348int 349acpicpu_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 */ 361int 362acpicpu_md_tstate_set(struct acpicpu_tstate *ts) 363{ 364 return EINVAL; 365} 366