1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
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 "proc_fs.h"
17 #include "mmc_corex.h"
18 #include "mmc_sd.h"
19
20 #define MCI_PARENT "mci"
21 #define MCI_STATS_PROC "mci_info"
22
23 #define CLOCK_UINT_MAX_NUM 4
24 #define HIMCI_HOST_NUM 3
25
26 static struct ProcDirEntry *g_procMciDir = NULL;
27
ProcGetMmcCardUnplugged(struct MmcCntlr * mmc)28 static bool ProcGetMmcCardUnplugged(struct MmcCntlr *mmc)
29 {
30 if (mmc->caps.bits.nonremovable == 0) {
31 /*
32 * removable, for sd cards only.
33 * slots for sd cards can detect if the card is plugged.
34 */
35 return (MmcCntlrDevPluged(mmc) == false);
36 } else {
37 /* slots for sdio or emmc can't detect if the card is plugged in hardware. */
38 return (mmc->curDev == NULL);
39 }
40 }
41
ProcStatsCardPluggedPrint(struct MmcCntlr * mmc,struct SeqBuf * s)42 static int32_t ProcStatsCardPluggedPrint(struct MmcCntlr *mmc, struct SeqBuf *s)
43 {
44 int32_t status;
45
46 if (ProcGetMmcCardUnplugged(mmc) == true) {
47 status = LosBufPrintf(s, ": unplugged_disconnected\n");
48 if (status != 0) {
49 return HDF_FAILURE;
50 }
51 return HDF_ERR_NOT_SUPPORT;
52 }
53
54 status = LosBufPrintf(s, ": plugged");
55 if (status != 0) {
56 return HDF_FAILURE;
57 }
58 return HDF_SUCCESS;
59 }
60
ProcStatsCardConnectedPrint(struct MmcDevice * card,struct SeqBuf * s)61 static int32_t ProcStatsCardConnectedPrint(struct MmcDevice *card, struct SeqBuf *s)
62 {
63 int32_t status;
64
65 if ((card == NULL) || card->state.bits.present == 0) {
66 status = LosBufPrintf(s, "_disconnected\n");
67 return HDF_FAILURE;
68 }
69
70 status = LosBufPrintf(s, "_connected\n");
71 if (status != 0) {
72 return HDF_FAILURE;
73 }
74 return HDF_SUCCESS;
75 }
76
ProcGetCardType(enum MmcDevType type)77 static char *ProcGetCardType(enum MmcDevType type)
78 {
79 static char *cardTypeStr[MMC_DEV_INVALID + 1] = {
80 "EMMC card",
81 "SD card",
82 "SDIO card",
83 "SD combo (IO+mem) card",
84 "unknown"
85 };
86
87 if (type >= MMC_DEV_INVALID) {
88 return cardTypeStr[MMC_DEV_INVALID];
89 } else {
90 return cardTypeStr[type];
91 }
92 }
93
ProcStatsCardTypePrint(struct MmcDevice * card,struct SeqBuf * s)94 static int32_t ProcStatsCardTypePrint(struct MmcDevice *card, struct SeqBuf *s)
95 {
96 int32_t status;
97 const char *type = NULL;
98
99 status = LosBufPrintf(s, "\tType: %s", ProcGetCardType(card->type));
100 if (status != 0) {
101 return HDF_FAILURE;
102 }
103 if (card->state.bits.blockAddr > 0) {
104 type = "SDHC";
105 if (card->state.bits.sdxc > 0) {
106 type = "SDXC";
107 }
108 status = LosBufPrintf(s, "(%s)\n", type);
109 if (status != HDF_SUCCESS) {
110 return HDF_FAILURE;
111 }
112 } else {
113 status = LosBufPrintf(s, "\n");
114 if (status != HDF_SUCCESS) {
115 return HDF_FAILURE;
116 }
117 }
118 return HDF_SUCCESS;
119 }
120
ProcAnalyzeClockScale(uint32_t clock,uint32_t * val)121 static uint32_t ProcAnalyzeClockScale(uint32_t clock, uint32_t *val)
122 {
123 uint32_t scale = 0;
124 uint32_t tmp = clock;
125
126 *val = tmp;
127 while (tmp > 0) {
128 tmp = tmp / 1000;
129 if (tmp > 0 && scale < (CLOCK_UINT_MAX_NUM - 1)) {
130 *val = tmp;
131 scale++;
132 }
133 }
134 return scale;
135 }
136
ProcStatsUhsPrint(struct MmcDevice * card,struct SeqBuf * s)137 static int32_t ProcStatsUhsPrint(struct MmcDevice *card, struct SeqBuf *s)
138 {
139 int32_t status;
140 struct SdDevice *dev = (struct SdDevice *)card;
141 const char *busSpeedMode = "";
142 static char *speedsOfUHS[] = {
143 "SDR12 ", "SDR25 ", "SDR50 ", "SDR104 ", "DDR50 "
144 };
145
146 if (card->type == MMC_DEV_SD || card->type == MMC_DEV_COMBO) {
147 if (card->state.bits.uhs > 0 &&
148 dev->busSpeedMode < (sizeof(speedsOfUHS) / sizeof(speedsOfUHS[0]))) {
149 busSpeedMode = speedsOfUHS[dev->busSpeedMode];
150 }
151 }
152 status = LosBufPrintf(s, "\tMode: %s%s%s%s\n",
153 (card->state.bits.uhs > 0) ? "UHS " : ((card->state.bits.highSpeed > 0) ? "HS " : ""),
154 (card->state.bits.hs200 > 0) ? "HS200 " :
155 ((card->state.bits.hs400 > 0 || card->state.bits.hs400es > 0) ? "HS400 " : ""),
156 (card->state.bits.ddrMode > 0) ? "DDR" : "",
157 busSpeedMode);
158 if (status != 0) {
159 return HDF_FAILURE;
160 }
161
162 return HDF_SUCCESS;
163 }
164
ProcStatsSpeedPrint(struct MmcDevice * card,struct SeqBuf * s)165 static int32_t ProcStatsSpeedPrint(struct MmcDevice *card, struct SeqBuf *s)
166 {
167 int32_t status;
168 uint32_t speedClass = 0;
169 uint32_t uhsSpeedGrade = 0;
170 static char *speed = NULL;
171 struct SdDevice *dev = (struct SdDevice *)card;
172
173 if (card->type == MMC_DEV_SD || card->type == MMC_DEV_COMBO) {
174 speedClass = dev->reg.ssr.speedClass;
175 uhsSpeedGrade = dev->reg.ssr.uhsSpeedGrade;
176 }
177
178 if (speedClass > SD_SSR_SPEED_CLASS_4) {
179 status = LosBufPrintf(s, "\tSpeed Class: Class Reserved\n");
180 } else {
181 if (speedClass == SD_SSR_SPEED_CLASS_4) {
182 speedClass = SD_SSR_SPEED_CLASS_4_VAL;
183 } else {
184 speedClass *= (SD_SSR_SPEED_CLASS_1_VAL / SD_SSR_SPEED_CLASS_1);
185 }
186 status = LosBufPrintf(s, "\tSpeed Class: Class %d\n", speedClass);
187 }
188 if (status != 0) {
189 return HDF_FAILURE;
190 }
191
192 if (uhsSpeedGrade == SD_SSR_UHS_SPEED_GRADE_0) {
193 speed = "Less than 10MB/sec(0h)";
194 } else if (uhsSpeedGrade == SD_SSR_UHS_SPEED_GRADE_1) {
195 speed = "10MB/sec and above(1h)";
196 } else if (uhsSpeedGrade == SD_SSR_UHS_SPEED_GRADE_3) {
197 speed = "30MB/sec and above(3h)";
198 } else {
199 speed = "Reserved";
200 }
201 status = LosBufPrintf(s, "\tUhs Speed Grade: %s\n", speed);
202 if (status != 0) {
203 return HDF_FAILURE;
204 }
205 return HDF_SUCCESS;
206 }
207
ProcStatsClkPrint(uint32_t clock,struct SeqBuf * s)208 static int32_t ProcStatsClkPrint(uint32_t clock, struct SeqBuf *s)
209 {
210 int32_t status;
211 uint32_t clockScale;
212 uint32_t clockValue = 0;
213 static char *clockUnit[CLOCK_UINT_MAX_NUM] = {
214 "Hz",
215 "KHz",
216 "MHz",
217 "GHz"
218 };
219
220 clockScale = ProcAnalyzeClockScale(clock, &clockValue);
221 status = LosBufPrintf(s, "\tHost work clock: %d%s\n", clockValue, clockUnit[clockScale]);
222 if (status != 0) {
223 return HDF_FAILURE;
224 }
225
226 status = LosBufPrintf(s, "\tCard support clock: %d%s\n", clockValue, clockUnit[clockScale]);
227 if (status != 0) {
228 return HDF_FAILURE;
229 }
230
231 status = LosBufPrintf(s, "\tCard work clock: %d%s\n", clockValue, clockUnit[clockScale]);
232 if (status != 0) {
233 return HDF_FAILURE;
234 }
235 return HDF_SUCCESS;
236 }
237
ProcStatsCidPrint(struct MmcDevice * card,struct SeqBuf * s)238 static int32_t ProcStatsCidPrint(struct MmcDevice *card, struct SeqBuf *s)
239 {
240 int32_t status;
241
242 status = LosBufPrintf(s, "\tCard cid: %08x%08x%08x%08x\n",
243 card->reg.rawCid[0], card->reg.rawCid[1], card->reg.rawCid[2], card->reg.rawCid[3]);
244 if (status != 0) {
245 return HDF_FAILURE;
246 }
247 return HDF_SUCCESS;
248 }
249
ProcStatsCardInfoPrint(struct MmcCntlr * mmc,struct SeqBuf * s)250 static int32_t ProcStatsCardInfoPrint(struct MmcCntlr *mmc, struct SeqBuf *s)
251 {
252 struct MmcDevice *card = NULL;
253 int32_t status;
254
255 status = ProcStatsCardPluggedPrint(mmc, s);
256 if (status != HDF_SUCCESS) {
257 if (status == HDF_ERR_NOT_SUPPORT) {
258 return HDF_SUCCESS;
259 }
260 return HDF_FAILURE;
261 }
262
263 card = mmc->curDev;
264 if (card == NULL) {
265 return HDF_SUCCESS;
266 }
267 status = ProcStatsCardConnectedPrint(card, s);
268 if (status != HDF_SUCCESS) {
269 return status;
270 }
271 status = ProcStatsCardTypePrint(card, s);
272 if (status != HDF_SUCCESS) {
273 return status;
274 }
275 status = ProcStatsUhsPrint(card, s);
276 if (status != HDF_SUCCESS) {
277 return status;
278 }
279 status = ProcStatsSpeedPrint(card, s);
280 if (status != HDF_SUCCESS) {
281 return status;
282 }
283 status = ProcStatsClkPrint(card->workPara.clock, s);
284 if (status != HDF_SUCCESS) {
285 return status;
286 }
287 status = LosBufPrintf(s, "\tCard error count: 0\n");
288 if (status != 0) {
289 return HDF_FAILURE;
290 }
291 status = ProcStatsCidPrint(card, s);
292 if (status != HDF_SUCCESS) {
293 return HDF_FAILURE;
294 }
295 return HDF_SUCCESS;
296 }
297
ProcStatsSeqPrint(struct SeqBuf * s)298 static int32_t ProcStatsSeqPrint(struct SeqBuf *s)
299 {
300 int32_t status;
301 uint32_t hostId;
302 struct MmcCntlr *mmc = NULL;
303
304 for (hostId = 0; hostId < HIMCI_HOST_NUM; hostId++) {
305 mmc = MmcCntlrGetByNr(hostId);
306 if (mmc == NULL || mmc->priv == NULL) {
307 status = LosBufPrintf(s, "\nMCI%d: invalid\n", hostId);
308 if (status != 0) {
309 return HDF_FAILURE;
310 }
311 continue;
312 }
313 status = LosBufPrintf(s, "\nMCI%d", hostId);
314 if (status != 0) {
315 return HDF_FAILURE;
316 }
317 status = ProcStatsCardInfoPrint(mmc, s);
318 if (status != 0) {
319 return HDF_FAILURE;
320 }
321 }
322 return HDF_SUCCESS;
323 }
324
ProcMciShow(struct SeqBuf * m,void * v)325 static int32_t ProcMciShow(struct SeqBuf *m, void *v)
326 {
327 (void)v;
328 return ProcStatsSeqPrint(m);
329 }
330
331 static const struct ProcFileOperations g_mciProcFops = {
332 .read = ProcMciShow,
333 };
334
ProcMciInit(void)335 int32_t ProcMciInit(void)
336 {
337 struct ProcDirEntry *handle = NULL;
338
339 g_procMciDir = ProcMkdir(MCI_PARENT, NULL);
340 if (g_procMciDir == NULL) {
341 HDF_LOGE("create directory error!");
342 return HDF_FAILURE;
343 }
344
345 handle = CreateProcEntry(MCI_STATS_PROC, 0, (struct ProcDirEntry *)g_procMciDir);
346 if (handle == NULL) {
347 HDF_LOGE("create mount pointer error!");
348 return HDF_FAILURE;
349 }
350
351 handle->procFileOps = &g_mciProcFops;
352 return HDF_SUCCESS;
353 }
354