1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "thermal_device_mitigation.h"
17
18#include <cstdio>
19#include <cstdlib>
20#include <fcntl.h>
21#include <fstream>
22#include <unistd.h>
23
24#include "hdf_base.h"
25#include "securec.h"
26#include "hdf_log.h"
27#include "thermal_log.h"
28#include "thermal_hdf_config.h"
29
30#define HDF_LOG_TAG ThermalDeviceMitigation
31
32namespace OHOS {
33namespace HDI {
34namespace Thermal {
35namespace V1_1 {
36namespace {
37const int32_t MAX_PATH = 256;
38const int32_t MAX_BUF_PATH = 256;
39const std::string SIM_CPU_FREQ_PATH = "/data/service/el0/thermal/cooling/cpu/freq";
40const std::string GPU_FREQ_PATH = "/data/service/el0/thermal/cooling/gpu/freq";
41const std::string BATTERY_CHARGER_CURRENT_PATH = "/data/service/el0/thermal/cooling/charger/current";
42const std::string SIM_BATTERY_CURRENT_PATH = "/data/service/el0/thermal/cooling/battery/current";
43const std::string BATTERY_VOLTAGE_PATH = "/data/service/el0/thermal/cooling/battery/voltage";
44const std::string ACTUAL_BATTERY_CURRENT_PATH = "/sys/class/power_supply/battery/input_current_limited";
45const int32_t NUM_ZERO = 0;
46}
47int32_t ThermalDeviceMitigation::WriteSysfsFd(int32_t fd, std::string buf, size_t bytesSize)
48{
49    ssize_t pos = 0;
50    do {
51        ssize_t recever = write(fd, buf.c_str() + (size_t) pos, bytesSize - (size_t)pos);
52        if (recever < NUM_ZERO) {
53            return recever;
54        }
55        pos += recever;
56    } while ((ssize_t)bytesSize > pos);
57
58    return (int32_t)bytesSize;
59}
60
61int32_t ThermalDeviceMitigation::OpenSysfsFile(std::string filePath, int32_t flags)
62{
63    int32_t ret;
64
65    if (filePath.empty()) {
66        return HDF_ERR_INVALID_PARAM;
67    }
68
69    ret = open(filePath.c_str(), flags);
70    if (ret < NUM_ZERO) {
71        THERMAL_HILOGE(COMP_HDI, "failed to open file");
72        return ret;
73    }
74    return ret;
75}
76
77int32_t ThermalDeviceMitigation::WriteSysfsFile(std::string filePath, std::string buf, size_t bytesSize)
78{
79    std::fstream file(filePath.c_str(), std::ios::out | std::ios::trunc);
80    file.close();
81    int32_t fd = OpenSysfsFile(filePath.c_str(), O_RDWR);
82    if (fd < NUM_ZERO) {
83        THERMAL_HILOGE(COMP_HDI, "failed to open SysfsFile");
84        return HDF_ERR_IO;
85    }
86    int32_t ret = WriteSysfsFd(fd, buf.c_str(), bytesSize);
87    close(fd);
88    return ret;
89}
90
91int32_t ThermalDeviceMitigation::SetFlag(bool flag)
92{
93    flag_ = flag;
94    return HDF_SUCCESS;
95}
96
97int32_t ThermalDeviceMitigation::ExecuteCpuRequest(uint32_t freq, const std::string &path)
98{
99    int32_t ret = HDF_FAILURE;
100    char freqBuf[MAX_PATH] = {0};
101    char nodeBuf[MAX_BUF_PATH] = {0};
102    if (access(path.c_str(), 0) != NUM_ZERO) {
103        return ret;
104    }
105    std::lock_guard<std::mutex> lock(mutex_);
106    if (snprintf_s(nodeBuf, MAX_BUF_PATH, sizeof(nodeBuf) - 1, "%s", path.c_str()) < EOK) {
107        return ret;
108    }
109    if (snprintf_s(freqBuf, MAX_PATH, sizeof(freqBuf) - 1, "%u", freq) < EOK) {
110        return ret;
111    }
112    if (WriteSysfsFile(nodeBuf, freqBuf, strlen(freqBuf)) > NUM_ZERO) {
113        THERMAL_HILOGI(COMP_HDI, "Set freq to %{public}d", freq);
114        ret = HDF_SUCCESS;
115    } else {
116        THERMAL_HILOGE(COMP_HDI, "failed to set freq");
117        ret = HDF_FAILURE;
118    }
119    return ret;
120}
121
122int32_t ThermalDeviceMitigation::CpuRequest(uint32_t freq)
123{
124    int32_t ret = ExecuteCpuRequest(freq, SIM_CPU_FREQ_PATH);
125    if (ret != HDF_SUCCESS) {
126        return HDF_FAILURE;
127    }
128    return HDF_SUCCESS;
129}
130
131int32_t ThermalDeviceMitigation::ChargerRequest(uint32_t current)
132{
133    int32_t ret = ExecuteChargerRequest(current, ACTUAL_BATTERY_CURRENT_PATH);
134    if (ret != HDF_SUCCESS) {
135        THERMAL_HILOGE(COMP_HDI, "failed to really set current");
136    }
137    ret = ExecuteChargerRequest(current, SIM_BATTERY_CURRENT_PATH);
138    if (ret != HDF_SUCCESS) {
139        return HDF_FAILURE;
140    }
141    return HDF_SUCCESS;
142}
143
144int32_t ThermalDeviceMitigation::GpuRequest(uint32_t freq)
145{
146    int32_t ret = HDF_FAILURE;
147    char freqBuf[MAX_PATH] = {0};
148    char nodeBuf[MAX_BUF_PATH] = {0};
149
150    std::lock_guard<std::mutex> lock(mutex_);
151    ret = snprintf_s(nodeBuf, MAX_BUF_PATH, sizeof(nodeBuf) - 1, "%s", GPU_FREQ_PATH.c_str());
152    if (ret < EOK) {
153        return ret;
154    }
155    ret = snprintf_s(freqBuf, MAX_PATH, sizeof(freqBuf) - 1, "%u", freq);
156    if (ret < EOK) {
157        return ret;
158    }
159    if (WriteSysfsFile(nodeBuf, freqBuf, strlen(freqBuf)) > NUM_ZERO) {
160        THERMAL_HILOGI(COMP_HDI, "Set freq to %{public}d", freq);
161        ret = HDF_SUCCESS;
162    } else {
163        THERMAL_HILOGE(COMP_HDI, "failed to set freq");
164        ret = HDF_FAILURE;
165    }
166    return ret;
167}
168
169int32_t ThermalDeviceMitigation::ExecuteChargerRequest(uint32_t current, const std::string &path)
170{
171    int32_t ret = HDF_FAILURE;
172    char currentBuf[MAX_PATH] = {0};
173    char nodeBuf[MAX_BUF_PATH] = {0};
174    if (access(path.c_str(), 0) != NUM_ZERO) {
175        return ret;
176    }
177
178    std::lock_guard<std::mutex> lock(mutex_);
179    ret = snprintf_s(nodeBuf, MAX_BUF_PATH, sizeof(nodeBuf) - 1, "%s", path.c_str());
180    if (ret < EOK) {
181        return ret;
182    }
183    ret = snprintf_s(currentBuf, MAX_PATH, sizeof(currentBuf) - 1, "%u%s", current, "\n");
184    if (ret < EOK) {
185        return ret;
186    }
187    if (WriteSysfsFile(nodeBuf, currentBuf, strlen(currentBuf)) > NUM_ZERO) {
188        THERMAL_HILOGI(COMP_HDI, "Set current to %{public}d", current);
189        ret = HDF_SUCCESS;
190    } else {
191        THERMAL_HILOGE(COMP_HDI, "failed to set current");
192        ret = HDF_FAILURE;
193    }
194    return ret;
195}
196
197int32_t ThermalDeviceMitigation::BatteryCurrentRequest(uint32_t current)
198{
199    int32_t ret = HDF_FAILURE;
200    char currentBuf[MAX_PATH] = {0};
201    char nodeBuf[MAX_BUF_PATH] = {0};
202
203    std::lock_guard<std::mutex> lock(mutex_);
204    ret = snprintf_s(nodeBuf, MAX_BUF_PATH, sizeof(nodeBuf) - 1, "%s", SIM_BATTERY_CURRENT_PATH.c_str());
205    if (ret < EOK) {
206        return ret;
207    }
208    ret = snprintf_s(currentBuf, MAX_PATH, sizeof(currentBuf) - 1, "%u", current);
209    if (ret < EOK) {
210        return ret;
211    }
212    if (WriteSysfsFile(nodeBuf, currentBuf, strlen(currentBuf)) > NUM_ZERO) {
213        THERMAL_HILOGI(COMP_HDI, "Set current to %{public}d", current);
214        ret = HDF_SUCCESS;
215    } else {
216        THERMAL_HILOGE(COMP_HDI, "failed to set current");
217        ret = HDF_FAILURE;
218    }
219    return ret;
220}
221
222int32_t ThermalDeviceMitigation::BatteryVoltageRequest(uint32_t voltage)
223{
224    int32_t ret = HDF_FAILURE;
225    char voltageBuf[MAX_PATH] = {0};
226    char voltageNode[MAX_BUF_PATH] = {0};
227
228    std::lock_guard<std::mutex> lock(mutex_);
229    ret = snprintf_s(voltageNode, MAX_BUF_PATH, sizeof(voltageNode) - 1, "%s", BATTERY_VOLTAGE_PATH.c_str());
230    if (ret < EOK) {
231        return ret;
232    }
233    ret = snprintf_s(voltageBuf, MAX_PATH, sizeof(voltageBuf) - 1, "%u", voltage);
234    if (ret < EOK) {
235        return ret;
236    }
237    if (WriteSysfsFile(voltageNode, voltageBuf, strlen(voltageBuf)) > NUM_ZERO) {
238        THERMAL_HILOGI(COMP_HDI, "Set current to %{public}d", voltage);
239        ret = HDF_SUCCESS;
240    } else {
241        THERMAL_HILOGE(COMP_HDI, "failed to set current");
242        ret = HDF_FAILURE;
243    }
244    return ret;
245}
246
247int32_t ThermalDeviceMitigation::IsolateCpu(int32_t num)
248{
249    int32_t ret = HDF_FAILURE;
250    char valueBuf[MAX_PATH] = {0};
251    char isolateCpuPath[MAX_BUF_PATH] = {0};
252    std::string type = "soc";
253    std::string path;
254
255    ret = ThermalHdfConfig::GetInstance().GetIsolateCpuNodePath(flag_, type, path);
256    if (ret != HDF_SUCCESS) {
257        THERMAL_HILOGE(COMP_HDI, "get Isolate Cpu config path is null");
258        return HDF_FAILURE;
259    }
260
261    ret = snprintf_s(isolateCpuPath, MAX_BUF_PATH, sizeof(isolateCpuPath) - 1, "%s", path.c_str());
262    if (ret < EOK) {
263        return ret;
264    }
265
266    ret = snprintf_s(valueBuf, MAX_PATH, sizeof(valueBuf) - 1, "%d", num);
267    if (ret < EOK) {
268        return ret;
269    }
270
271    std::lock_guard<std::mutex> lock(mutex_);
272    if (WriteSysfsFile(isolateCpuPath, valueBuf, strlen(valueBuf)) > NUM_ZERO) {
273        THERMAL_HILOGI(COMP_HDI, "isolate cpu %{public}d", num);
274        ret = HDF_SUCCESS;
275    } else {
276        THERMAL_HILOGE(COMP_HDI, "failed to isolate cpu");
277        ret = HDF_FAILURE;
278    }
279    return ret;
280}
281} // V1_1
282} // Thermal
283} // HDI
284} // OHOS
285