Home | History | Annotate | Line # | Download | only in acpi
      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 (at) 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 *
     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 *
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    362 acpicpu_md_tstate_set(struct acpicpu_tstate *ts)
    363 {
    364 	return EINVAL;
    365 }
    366