blob: 737a7bf653864517ee0d5e70e21fa25e39b0a245 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "performance-domain.h"
#include <fuchsia/device/llcpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fdio.h>
#include <iostream>
using fuchsia_device::wire::kMaxDevicePerformanceStates;
std::variant<zx_status_t, CpuPerformanceDomain> CpuPerformanceDomain::CreateFromPath(
const std::string& path) {
// Obtain a channel to the service.
zx::channel cpu_local, cpu_remote, device_local, device_remote;
zx_status_t st = zx::channel::create(0, &cpu_local, &cpu_remote);
if (st != ZX_OK) {
return st;
}
st = fdio_service_connect(path.c_str(), cpu_remote.release());
if (st != ZX_OK) {
return st;
}
st = zx::channel::create(0, &device_local, &device_remote);
if (st != ZX_OK) {
return st;
}
st = fdio_service_connect(path.c_str(), device_remote.release());
if (st != ZX_OK) {
return st;
}
fidl::WireSyncClient<cpuctrl::Device> cpu_client(std::move(cpu_local));
fidl::WireSyncClient<fuchsia_device::Controller> device_client(std::move(device_local));
CpuPerformanceDomain result(std::move(cpu_client), std::move(device_client));
return result;
}
std::pair<zx_status_t, uint64_t> CpuPerformanceDomain::GetNumLogicalCores() {
auto resp = cpu_client_.GetNumLogicalCores();
return std::make_pair(resp.status(), resp.status() == ZX_OK ? resp.value().count : 0);
}
std::tuple<zx_status_t, uint64_t, cpuctrl::wire::CpuPerformanceStateInfo>
CpuPerformanceDomain::GetCurrentPerformanceState() {
constexpr cpuctrl::wire::CpuPerformanceStateInfo kEmptyPstate = {
.frequency_hz = cpuctrl::wire::kFrequencyUnknown,
.voltage_uv = cpuctrl::wire::kVoltageUnknown,
};
auto resp = device_client_.GetCurrentPerformanceState();
if (resp.status() != ZX_OK) {
return std::make_tuple(resp.status(), 0, kEmptyPstate);
}
const auto& pstates = GetPerformanceStates();
uint64_t current_pstate = resp.value().out_state;
cpuctrl::wire::CpuPerformanceStateInfo pstate_result = kEmptyPstate;
if (current_pstate >= pstates.size()) {
std::cerr << "No description for current pstate." << std::endl;
} else {
pstate_result = pstates[current_pstate];
}
return std::make_tuple(ZX_OK, current_pstate, pstate_result);
}
const std::vector<cpuctrl::wire::CpuPerformanceStateInfo>&
CpuPerformanceDomain::GetPerformanceStates() {
// If we've already fetched this in the past, there's no need to fetch again.
if (!cached_pstates_.empty()) {
return cached_pstates_;
}
for (uint32_t i = 0; i < kMaxDevicePerformanceStates; i++) {
auto resp = cpu_client_.GetPerformanceStateInfo(i);
if (resp.status() != ZX_OK || resp->result.is_err()) {
continue;
}
cached_pstates_.push_back(resp.value().result.response().info);
}
return cached_pstates_;
}
zx_status_t CpuPerformanceDomain::SetPerformanceState(uint32_t new_performance_state) {
if (new_performance_state >= kMaxDevicePerformanceStates) {
return ZX_ERR_OUT_OF_RANGE;
}
auto result = device_client_.SetPerformanceState(new_performance_state);
if (result.status() != ZX_OK) {
return result.status();
}
if (result.value().status != ZX_OK) {
return result.value().status;
}
if (result.value().out_state != new_performance_state) {
return ZX_ERR_INTERNAL;
}
return ZX_OK;
}