* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "thermal_device_mitigation.h"
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <fstream>
#include <unistd.h>
#include "hdf_base.h"
#include "securec.h"
#include "hdf_log.h"
#include "thermal_log.h"
#include "thermal_hdf_config.h"
#define DRIVERS_PERIPHERAL_THERMAL_FDSAN_TAG 0XD002943
#define HDF_LOG_TAG ThermalDeviceMitigation
namespace OHOS {
namespace HDI {
namespace Thermal {
namespace V1_1 {
namespace {
const int32_t MAX_PATH = 256;
const int32_t MAX_BUF_PATH = 256;
const std::string SIM_CPU_FREQ_PATH = "/data/service/el0/thermal/cooling/cpu/freq";
const std::string GPU_FREQ_PATH = "/data/service/el0/thermal/cooling/gpu/freq";
const std::string SIM_BATTERY_CURRENT_PATH = "/data/service/el0/thermal/cooling/battery/current";
const std::string BATTERY_VOLTAGE_PATH = "/data/service/el0/thermal/cooling/battery/voltage";
const std::string ACTUAL_BATTERY_CURRENT_PATH = "/sys/class/power_supply/battery/input_current_limited";
const int32_t NUM_ZERO = 0;
}
int32_t ThermalDeviceMitigation::WriteSysfsFd(int32_t fd, std::string buf, size_t bytesSize)
{
ssize_t pos = 0;
do {
ssize_t recever = write(fd, buf.c_str() + (size_t) pos, bytesSize - (size_t)pos);
if (recever < NUM_ZERO) {
return recever;
}
pos += recever;
} while ((ssize_t)bytesSize > pos);
return (int32_t)bytesSize;
}
int32_t ThermalDeviceMitigation::OpenSysfsFile(std::string filePath, int32_t flags)
{
int32_t ret;
constexpr uint64_t FDSAN_PARAM = 0;
if (filePath.empty()) {
return HDF_ERR_INVALID_PARAM;
}
ret = open(filePath.c_str(), flags);
if (ret < NUM_ZERO) {
THERMAL_HILOGE(COMP_HDI, "failed to open file");
return ret;
}
fdsan_exchange_owner_tag(ret, FDSAN_PARAM, DRIVERS_PERIPHERAL_THERMAL_FDSAN_TAG);
return ret;
}
int32_t ThermalDeviceMitigation::WriteSysfsFile(std::string filePath, std::string buf, size_t bytesSize)
{
std::fstream file(filePath.c_str(), std::ios::out | std::ios::trunc);
file.close();
int32_t fd = OpenSysfsFile(filePath.c_str(), O_RDWR);
if (fd < NUM_ZERO) {
THERMAL_HILOGE(COMP_HDI, "failed to open SysfsFile");
return HDF_ERR_IO;
}
int32_t ret = WriteSysfsFd(fd, buf.c_str(), bytesSize);
fdsan_close_with_tag(fd, DRIVERS_PERIPHERAL_THERMAL_FDSAN_TAG);
return ret;
}
int32_t ThermalDeviceMitigation::SetFlag(bool flag)
{
flag_ = flag;
return HDF_SUCCESS;
}
int32_t ThermalDeviceMitigation::ExecuteCpuRequest(uint32_t freq, const std::string &path)
{
int32_t ret = HDF_FAILURE;
char freqBuf[MAX_PATH] = {0};
char nodeBuf[MAX_BUF_PATH] = {0};
if (access(path.c_str(), 0) != NUM_ZERO) {
return ret;
}
std::lock_guard<std::mutex> lock(mutex_);
if (snprintf_s(nodeBuf, MAX_BUF_PATH, sizeof(nodeBuf) - 1, "%s", path.c_str()) < EOK) {
return ret;
}
if (snprintf_s(freqBuf, MAX_PATH, sizeof(freqBuf) - 1, "%u", freq) < EOK) {
return ret;
}
if (WriteSysfsFile(nodeBuf, freqBuf, strlen(freqBuf)) > NUM_ZERO) {
THERMAL_HILOGI(COMP_HDI, "Set freq to %{public}d", freq);
ret = HDF_SUCCESS;
} else {
THERMAL_HILOGE(COMP_HDI, "failed to set freq");
ret = HDF_FAILURE;
}
return ret;
}
int32_t ThermalDeviceMitigation::CpuRequest(uint32_t freq)
{
int32_t ret = ExecuteCpuRequest(freq, SIM_CPU_FREQ_PATH);
if (ret != HDF_SUCCESS) {
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
int32_t ThermalDeviceMitigation::ChargerRequest(uint32_t current)
{
int32_t ret = ExecuteChargerRequest(current, ACTUAL_BATTERY_CURRENT_PATH);
if (ret != HDF_SUCCESS) {
THERMAL_HILOGE(COMP_HDI, "failed to really set current");
}
ret = ExecuteChargerRequest(current, SIM_BATTERY_CURRENT_PATH);
if (ret != HDF_SUCCESS) {
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
int32_t ThermalDeviceMitigation::GpuRequest(uint32_t freq)
{
int32_t ret = HDF_FAILURE;
char freqBuf[MAX_PATH] = {0};
char nodeBuf[MAX_BUF_PATH] = {0};
std::lock_guard<std::mutex> lock(mutex_);
ret = snprintf_s(nodeBuf, MAX_BUF_PATH, sizeof(nodeBuf) - 1, "%s", GPU_FREQ_PATH.c_str());
if (ret < EOK) {
return ret;
}
ret = snprintf_s(freqBuf, MAX_PATH, sizeof(freqBuf) - 1, "%u", freq);
if (ret < EOK) {
return ret;
}
if (WriteSysfsFile(nodeBuf, freqBuf, strlen(freqBuf)) > NUM_ZERO) {
THERMAL_HILOGI(COMP_HDI, "Set freq to %{public}d", freq);
ret = HDF_SUCCESS;
} else {
THERMAL_HILOGE(COMP_HDI, "failed to set freq");
ret = HDF_FAILURE;
}
return ret;
}
int32_t ThermalDeviceMitigation::ExecuteChargerRequest(uint32_t current, const std::string &path)
{
int32_t ret = HDF_FAILURE;
char currentBuf[MAX_PATH] = {0};
char nodeBuf[MAX_BUF_PATH] = {0};
if (access(path.c_str(), 0) != NUM_ZERO) {
return ret;
}
std::lock_guard<std::mutex> lock(mutex_);
ret = snprintf_s(nodeBuf, MAX_BUF_PATH, sizeof(nodeBuf) - 1, "%s", path.c_str());
if (ret < EOK) {
return ret;
}
ret = snprintf_s(currentBuf, MAX_PATH, sizeof(currentBuf) - 1, "%u%s", current, "\n");
if (ret < EOK) {
return ret;
}
if (WriteSysfsFile(nodeBuf, currentBuf, strlen(currentBuf)) > NUM_ZERO) {
THERMAL_HILOGI(COMP_HDI, "Set current to %{public}d", current);
ret = HDF_SUCCESS;
} else {
THERMAL_HILOGE(COMP_HDI, "failed to set current");
ret = HDF_FAILURE;
}
return ret;
}
int32_t ThermalDeviceMitigation::BatteryCurrentRequest(uint32_t current)
{
int32_t ret = HDF_FAILURE;
char currentBuf[MAX_PATH] = {0};
char nodeBuf[MAX_BUF_PATH] = {0};
std::lock_guard<std::mutex> lock(mutex_);
ret = snprintf_s(nodeBuf, MAX_BUF_PATH, sizeof(nodeBuf) - 1, "%s", SIM_BATTERY_CURRENT_PATH.c_str());
if (ret < EOK) {
return ret;
}
ret = snprintf_s(currentBuf, MAX_PATH, sizeof(currentBuf) - 1, "%u", current);
if (ret < EOK) {
return ret;
}
if (WriteSysfsFile(nodeBuf, currentBuf, strlen(currentBuf)) > NUM_ZERO) {
THERMAL_HILOGI(COMP_HDI, "Set current to %{public}d", current);
ret = HDF_SUCCESS;
} else {
THERMAL_HILOGE(COMP_HDI, "failed to set current");
ret = HDF_FAILURE;
}
return ret;
}
int32_t ThermalDeviceMitigation::BatteryVoltageRequest(uint32_t voltage)
{
int32_t ret = HDF_FAILURE;
char voltageBuf[MAX_PATH] = {0};
char voltageNode[MAX_BUF_PATH] = {0};
std::lock_guard<std::mutex> lock(mutex_);
ret = snprintf_s(voltageNode, MAX_BUF_PATH, sizeof(voltageNode) - 1, "%s", BATTERY_VOLTAGE_PATH.c_str());
if (ret < EOK) {
return ret;
}
ret = snprintf_s(voltageBuf, MAX_PATH, sizeof(voltageBuf) - 1, "%u", voltage);
if (ret < EOK) {
return ret;
}
if (WriteSysfsFile(voltageNode, voltageBuf, strlen(voltageBuf)) > NUM_ZERO) {
THERMAL_HILOGI(COMP_HDI, "Set current to %{public}d", voltage);
ret = HDF_SUCCESS;
} else {
THERMAL_HILOGE(COMP_HDI, "failed to set current");
ret = HDF_FAILURE;
}
return ret;
}
int32_t ThermalDeviceMitigation::IsolateCpu(int32_t num)
{
int32_t ret = HDF_FAILURE;
char valueBuf[MAX_PATH] = {0};
char isolateCpuPath[MAX_BUF_PATH] = {0};
std::string type = "soc";
std::string path;
ret = ThermalHdfConfig::GetInstance().GetIsolateCpuNodePath(flag_, type, path);
if (ret != HDF_SUCCESS) {
THERMAL_HILOGE(COMP_HDI, "get Isolate Cpu config path is null");
return HDF_FAILURE;
}
ret = snprintf_s(isolateCpuPath, MAX_BUF_PATH, sizeof(isolateCpuPath) - 1, "%s", path.c_str());
if (ret < EOK) {
return ret;
}
ret = snprintf_s(valueBuf, MAX_PATH, sizeof(valueBuf) - 1, "%d", num);
if (ret < EOK) {
return ret;
}
std::lock_guard<std::mutex> lock(mutex_);
if (WriteSysfsFile(isolateCpuPath, valueBuf, strlen(valueBuf)) > NUM_ZERO) {
THERMAL_HILOGI(COMP_HDI, "isolate cpu %{public}d", num);
ret = HDF_SUCCESS;
} else {
THERMAL_HILOGE(COMP_HDI, "failed to isolate cpu");
ret = HDF_FAILURE;
}
return ret;
}
}
}
}
}