#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: acpi_cpu_md.c,v 1.1 2020/12/07 10:57:41 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/cpufreq.h>
#include <sys/device.h>
#include <sys/sysctl.h>
#include <dev/acpi/acpica.h>
#include <dev/acpi/acpivar.h>
#include <dev/acpi/acpi_cpu.h>
#include <dev/acpi/acpi_util.h>
static struct sysctllog *acpicpu_log = NULL;
struct cpu_info *
acpicpu_md_match(device_t parent, cfdata_t cf, void *aux)
{
struct acpi_attach_args * const aa = aux;
return acpi_match_cpu_handle(aa->aa_node->ad_handle);
}
struct cpu_info *
acpicpu_md_attach(device_t parent, device_t self, void *aux)
{
struct acpi_attach_args * const aa = aux;
return acpi_match_cpu_handle(aa->aa_node->ad_handle);
}
uint32_t
acpicpu_md_flags(void)
{
return 0;
}
int
acpicpu_md_cstate_start(struct acpicpu_softc *sc)
{
return EINVAL;
}
int
acpicpu_md_cstate_stop(void)
{
return EALREADY;
}
void
acpicpu_md_cstate_enter(int method, int state)
{
}
int
acpicpu_md_pstate_init(struct acpicpu_softc *sc)
{
return 0;
}
static int
acpicpu_md_pstate_sysctl_current(SYSCTLFN_ARGS)
{
struct sysctlnode node;
uint32_t freq;
int error;
freq = cpufreq_get(curcpu());
if (freq == 0)
return ENXIO;
node = *rnode;
node.sysctl_data = &freq;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
return error;
return 0;
}
static int
acpicpu_md_pstate_sysctl_target(SYSCTLFN_ARGS)
{
struct sysctlnode node;
uint32_t freq;
int error;
freq = cpufreq_get(curcpu());
if (freq == 0)
return ENXIO;
node = *rnode;
node.sysctl_data = &freq;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
return error;
cpufreq_set_all(freq);
return 0;
}
static int
acpicpu_md_pstate_sysctl_available(SYSCTLFN_ARGS)
{
struct acpicpu_softc * const sc = rnode->sysctl_data;
struct sysctlnode node;
char buf[1024];
size_t len;
uint32_t i;
int error;
memset(buf, 0, sizeof(buf));
mutex_enter(&sc->sc_mtx);
for (len = 0, i = sc->sc_pstate_max; i < sc->sc_pstate_count; i++) {
if (sc->sc_pstate[i].ps_freq == 0)
continue;
if (len >= sizeof(buf))
break;
len += snprintf(buf + len, sizeof(buf) - len, "%u%s",
sc->sc_pstate[i].ps_freq,
i < (sc->sc_pstate_count - 1) ? " " : "");
}
mutex_exit(&sc->sc_mtx);
node = *rnode;
node.sysctl_data = buf;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
return error;
return 0;
}
int
acpicpu_md_pstate_start(struct acpicpu_softc *sc)
{
const struct sysctlnode *mnode, *cnode, *fnode, *node;
int error;
error = sysctl_createv(&acpicpu_log, 0, NULL, &mnode,
CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
if (error) {
goto teardown;
}
error = sysctl_createv(&acpicpu_log, 0, &mnode, &cnode,
0, CTLTYPE_NODE, "cpu", NULL,
NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
if (error) {
goto teardown;
}
error = sysctl_createv(&acpicpu_log, 0, &cnode, &fnode,
0, CTLTYPE_NODE, "frequency", NULL,
NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
if (error) {
goto teardown;
}
error = sysctl_createv(&acpicpu_log, 0, &fnode, &node,
CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL,
acpicpu_md_pstate_sysctl_target, 0, NULL, 0, CTL_CREATE, CTL_EOL);
if (error) {
goto teardown;
}
error = sysctl_createv(&acpicpu_log, 0, &fnode, &node,
CTLFLAG_READONLY, CTLTYPE_INT, "current", NULL,
acpicpu_md_pstate_sysctl_current, 0, NULL, 0, CTL_CREATE, CTL_EOL);
if (error) {
goto teardown;
}
error = sysctl_createv(&acpicpu_log, 0, &fnode, &node,
CTLFLAG_READONLY, CTLTYPE_STRING, "available", NULL,
acpicpu_md_pstate_sysctl_available, 0, (void *)sc, 0, CTL_CREATE,
CTL_EOL);
if (error) {
goto teardown;
}
return 0;
teardown:
if (acpicpu_log != NULL) {
sysctl_teardown(&acpicpu_log);
acpicpu_log = NULL;
}
return error;
}
int
acpicpu_md_pstate_stop(void)
{
if (acpicpu_log != NULL) {
sysctl_teardown(&acpicpu_log);
acpicpu_log = NULL;
}
return 0;
}
int
acpicpu_md_pstate_get(struct acpicpu_softc *sc, uint32_t *freq)
{
return EINVAL;
}
int
acpicpu_md_pstate_set(struct acpicpu_pstate *ps)
{
return EINVAL;
}
int
acpicpu_md_tstate_get(struct acpicpu_softc *sc, uint32_t *percent)
{
return EINVAL;
}
int
acpicpu_md_tstate_set(struct acpicpu_tstate *ts)
{
return EINVAL;
}