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