• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "WriteBooster.h"
18 #include "Utils.h"
19 #include "VoldUtil.h"
20 
21 #include <android-base/file.h>
22 #include <android-base/logging.h>
23 #include <android-base/parseint.h>
24 #include <android-base/result.h>
25 #include <android-base/strings.h>
26 
27 using android::base::ReadFileToString;
28 using android::base::WriteStringToFile;
29 
30 namespace android {
31 namespace vold {
32 
33 template <typename T>
readHexValue(const std::string_view path)34 static android::base::Result<T> readHexValue(const std::string_view path) {
35     std::string sysfs_path = GetUfsHostControllerSysfsPath();
36     if (sysfs_path.empty()) {
37         return android::base::Error();
38     }
39 
40     std::string fullpath = sysfs_path + "/" + std::string(path);
41     std::string s;
42 
43     if (!ReadFileToString(fullpath, &s)) {
44         PLOG(WARNING) << "Reading failed for " << fullpath;
45         return android::base::Error();
46     }
47 
48     s = android::base::Trim(s);
49     T out;
50     if (!android::base::ParseUint(s, &out)) {
51         PLOG(WARNING) << "Parsing of " << fullpath << " failed. Content: " << s;
52         return android::base::Error();
53     }
54 
55     return out;
56 }
57 
GetWriteBoosterBufferSize()58 int32_t GetWriteBoosterBufferSize() {
59     /* wb_cur_buf: in unit of allocation_unit_size (field width is 4 bytes)
60      * allocation_unit_size: in unit of segments (field width is 1 bytes)
61      * segment_size: in unit of 512 bytes (field width is 4 bytes)
62      * raw_device_capacity: in unit of 512 bytes (field width is 8 bytes)
63      */
64     auto allocation_unit_size = readHexValue<uint8_t>("geometry_descriptor/allocation_unit_size");
65     if (!allocation_unit_size.ok()) {
66         return -1;
67     }
68 
69     auto segment_size = readHexValue<uint32_t>("geometry_descriptor/segment_size");
70     if (!segment_size.ok()) {
71         return -1;
72     }
73 
74     auto wb_cur_buf = readHexValue<uint32_t>("attributes/wb_cur_buf");
75     if (!wb_cur_buf.ok()) {
76         return -1;
77     }
78 
79     auto raw_device_capacity = readHexValue<uint64_t>("geometry_descriptor/raw_device_capacity");
80     if (!raw_device_capacity.ok()) {
81         return -1;
82     }
83 
84     if (allocation_unit_size.value() == 0) {
85         LOG(DEBUG) << "Zero allocation_unit_size is invalid.";
86         return -1;
87     }
88 
89     if (segment_size.value() == 0) {
90         LOG(DEBUG) << "Zero segment_size is invalid.";
91         return -1;
92     }
93 
94     uint64_t wb_cur_buf_allocation_units =
95             static_cast<uint64_t>(wb_cur_buf.value()) * segment_size.value();
96 
97     if (wb_cur_buf_allocation_units >
98         (raw_device_capacity.value() / allocation_unit_size.value())) {
99         LOG(DEBUG) << "invalid wb_cur_buff > raw_device_capacity ";
100         return -1;
101     }
102 
103     /* The allocation_unit_size is represented in the number of sectors.
104      * Since the sector size is 512 bytes, the allocation_unit_size in MiB can be calculated as
105      * follows: allocation_unit_size in MiB = (allocation_unit_size * 512) / 1024 / 1024 =
106      * allocation_unit_size / 2048
107      */
108     uint64_t wb_cur_buf_mib = wb_cur_buf_allocation_units * allocation_unit_size.value() / 2048ULL;
109 
110     if (wb_cur_buf_mib > INT32_MAX) {
111         LOG(DEBUG) << "wb_cur_buff overflow";
112         return -1;
113     }
114 
115     /* return in unit of MiB */
116     return static_cast<int32_t>(wb_cur_buf_mib);
117 }
118 
119 /*
120  * Returns the WriteBooster buffer's remaining capacity as a percentage (0-100).
121  */
GetWriteBoosterBufferAvailablePercent()122 int32_t GetWriteBoosterBufferAvailablePercent() {
123     /*
124      * wb_avail_buf is in unit of 10% granularity.
125      * 00h: 0% buffer remains.
126      * 01h~09h: 10%~90% buffer remains
127      * 0Ah: 100% buffer remains
128      * Others : Reserved
129      */
130     auto out = readHexValue<uint8_t>("attributes/wb_avail_buf");
131     if (!out.ok()) {
132         return -1;
133     }
134 
135     if (out.value() > 10) {
136         PLOG(WARNING) << "Invalid wb_avail_buf (" << out.value() << ")";
137         return -1;
138     }
139 
140     return static_cast<int32_t>(out.value() * 10);
141 }
142 
SetWriteBoosterBufferFlush(bool enable)143 bool SetWriteBoosterBufferFlush(bool enable) {
144     std::string path = GetUfsHostControllerSysfsPath();
145     if (path.empty()) {
146         return false;
147     }
148 
149     path += "/enable_wb_buf_flush";
150 
151     std::string s = enable ? "1" : "0";
152 
153     LOG(DEBUG) << "Toggle WriteBoosterBufferFlush to " << s;
154     if (!WriteStringToFile(s, std::string(path))) {
155         PLOG(WARNING) << "Failed to set WriteBoosterBufferFlush to " << s << " on " << path;
156         return false;
157     }
158     return true;
159 }
160 
SetWriteBoosterBufferOn(bool enable)161 bool SetWriteBoosterBufferOn(bool enable) {
162     std::string path = GetUfsHostControllerSysfsPath();
163     if (path.empty()) {
164         return false;
165     }
166 
167     path += "/wb_on";
168 
169     std::string s = enable ? "1" : "0";
170 
171     LOG(DEBUG) << "Toggle WriteBoosterBufferOn to " << s;
172     if (!WriteStringToFile(s, std::string(path))) {
173         PLOG(WARNING) << "Failed to set WriteBoosterBufferOn to " << s << " on " << path;
174         return false;
175     }
176     return true;
177 }
178 
179 /**
180  * Returns WriteBooster buffer lifetime as a percentage (0-100).
181  *
182  */
GetWriteBoosterLifeTimeEstimate()183 int32_t GetWriteBoosterLifeTimeEstimate() {
184     /*
185      * wb_life_time_est returns as follows:
186      * 00h: Information not available (WriteBooster Buffer is disabled)
187      * 01h: 0% - 10% WriteBooster Buffer life time used
188      * 02h-09h: 10% - 90% WriteBooster Buffer life time used
189      * 0Ah: 90% - 100% WriteBooster Buffer life time used
190      * 0Bh: Exceeded its maximum estimated WriteBooster Buffer life time
191      *      (write commands are processed as if WriteBooster feature was
192      *       disabled)
193      * Others: Reserved
194      */
195     auto out = readHexValue<uint8_t>("attributes/wb_life_time_est");
196     if (!out.ok()) {
197         return -1;
198     }
199 
200     if (out.value() == 0) {
201         PLOG(WARNING) << "WriteBooster is disabled.";
202         return -1;
203     }
204 
205     if (out.value() > 11) {
206         PLOG(WARNING) << "Invalid wb_life_time_est (" << out.value() << ")";
207         return -1;
208     }
209 
210     return static_cast<int32_t>(10 * (out.value() - 1));
211 }
212 
213 }  // namespace vold
214 }  // namespace android
215