blob: a22845a28ffeed256b0214019889a54412d63bf0 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2014-2015 MediaTek Inc.
3 * Author: Chaotian.Jing <chaotian.jing@mediatek.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#include <linux/kernel.h>
15#include <linux/sched.h>
16#include <linux/kthread.h>
17#include <linux/delay.h>
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/proc_fs.h>
21#include <linux/string.h>
22#include <linux/uaccess.h>
23#include <linux/vmalloc.h>
24#include <linux/fs.h>
25#include <linux/seq_file.h>
26#include <linux/slab.h>
27#include <linux/time.h>
28#include <linux/random.h>
29
30#include <linux/mmc/card.h>
31#include <linux/mmc/core.h>
32#include <linux/mmc/host.h>
33#include <linux/mmc/mmc.h>
34#include <linux/mmc/sd.h>
35#include <linux/mmc/sdio.h>
36#include <linux/mmc/sdio_func.h>
37
38#include "../core/core.h"
39
40enum {
41 Read = 0,
42 Write = 1,
43 Hqa_read = 2,
44 Hqa_write = 3,
45 Reset = 4,
46 Stress_read = 5,
47 Stress_write = 6,
48 SDIO_read_fix_Tput = 7,
49 SDIO_write_fix_Tput = 8,
50};
51
52static struct mmc_host *host_arry[3];
53static int max_id;
54
55/**
56 * define some count timer.
57 */
58#define KAL_TIME_INTERVAL_DECLARATION() struct timeval __rTs, __rTe
59#define KAL_REC_TIME_START() do_gettimeofday(&__rTs)
60#define KAL_REC_TIME_END() do_gettimeofday(&__rTe)
61#define KAL_GET_TIME_INTERVAL() \
62((__rTe.tv_sec * USEC_PER_SEC + __rTe.tv_usec) - \
63(__rTs.tv_sec * USEC_PER_SEC + __rTs.tv_usec))
64
65#define SDIO_XFER_SIZE 0x40000
66
67/**
68 * sdio_proc_show dispaly the common cccr and cis.
69 */
70static int sdio_proc_show(struct seq_file *m, void *v)
71{
72 seq_puts(m, "\n=========================================\n");
73 seq_puts(m, "read cmd format:\n");
74 seq_puts(m, " echo hostid 0 0xReg 0xfunction > /proc/sdio\n");
75
76 seq_puts(m, "write cmd format:\n");
77 seq_puts(m, " echo hostid 1 0xReg 0xfunction 0xvalue > /proc/sdio\n");
78
79 seq_puts(m, "multi read cmd format:\n");
80 seq_puts(m, " echo hostid 2 0x13 0x0 > /proc/sdio\n");
81
82 seq_puts(m, "multi write cmd format:\n");
83 seq_puts(m, " echo hostid 3 0x13 0x0 0xvalue > /proc/sdio\n");
84 seq_puts(m, "Notice:value is the read result!\n");
85
86 seq_puts(m, "reset sdio cmd format:\n");
87 seq_puts(m, " echo hostid 4 0x0 0x0 > /proc/sdio\n");
88
89 seq_puts(m, "throughput read cmd format:\n");
90 seq_puts(m, " echo hostid 5 0xb0 0x1 > /proc/sdio\n");
91
92 seq_puts(m, "throughtput write cmd format:\n");
93 seq_puts(m, " echo hostid 6 0xb0 0x1 > /proc/sdio\n");
94
95 seq_puts(m, "target throughput read cmd format:\n");
96 seq_puts(m, " echo hostid 7 0xb0 0x1 0xT-put 0xcount > /proc/sdio\n");
97
98 seq_puts(m, "target throughtput write cmd format:\n");
99 seq_puts(m, " echo hostid 8 0xb0 0x1 0xT-put 0xcount > /proc/sdio\n");
100
101 seq_puts(m, "target throughtput write cmd format for desense (random pattern):\n");
102 seq_puts(m, " echo hostid 8 0xb0 0x1 0xT-put 0xcount 0x1 > /proc/sdio\n");
103
104 seq_puts(m, "=========================================\n");
105
106 return 0;
107}
108
109/**
110 * sdio_proc_write - read/write sdio function register.
111 */
112static ssize_t sdio_proc_write(struct file *file, const char *buf,
113 size_t count, loff_t *f_pos)
114{
115 struct mmc_host *host;
116 struct mmc_card *card;
117 struct sdio_func *func = NULL;
118 struct mmc_ios *ios;
119 char *cmd_buf, *str_hand;
120 unsigned char *fac_buf = NULL;
121 unsigned int id, cmd, addr, fn, value = 0, hqa_result, offset = 0;
122 unsigned int extra = 0;
123 unsigned char result;
124 int i = 0, ret, usec_sleep;
125 unsigned long count_r = 0, total = 0;
126
127 KAL_TIME_INTERVAL_DECLARATION();
128 __kernel_suseconds_t usec, r_usec;
129
130 cmd_buf = kzalloc((count + 1), GFP_KERNEL);
131 if (!cmd_buf)
132 return count;
133
134 str_hand = kzalloc(2, GFP_KERNEL);
135 if (!str_hand) {
136 kfree(cmd_buf);
137 return count;
138 }
139
140 ret = copy_from_user(cmd_buf, buf, count);
141 if (ret < 0)
142 goto end;
143
144 *(cmd_buf + count) = '\0';
145 ret = sscanf(cmd_buf, "%x %x %x %x %x %x %x",
146 &id, &cmd, &addr, &fn, &value, &offset, &extra);
147 if (ret == 0) {
148 ret = sscanf(cmd_buf, "%s", str_hand);
149 if (ret == 0)
150 pr_info("please enter cmd.\n");
151
152 goto end;
153 }
154
155 if (id < max_id && id >= 0) {
156 host = host_arry[id];
157 if (!host) {
158 pr_info("host %d NULL\n", id);
159 goto end;
160 }
161 } else {
162 pr_info("host %d number is invalid, max(%d)\n",
163 id, max_id - 1);
164 goto end;
165 }
166
167 WARN_ON(!host);
168 ios = &host->ios;
169 card = host->card;
170
171 func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL);
172 if (!func) {
173 kfree(cmd_buf);
174 kfree(str_hand);
175 return count;
176 }
177
178 /* Judge whether request fn is over the max functions. */
179 if (fn > card->sdio_funcs) {
180 dev_info(mmc_dev(host), "the fn is over the max sdio funcs.\n");
181 goto end;
182 }
183
184 if (fn) {
185 /**
186 * The test read/write api don't need more func
187 * information. So we just use the card & func->num
188 * to the new struct func.
189 */
190 if (card->sdio_func[fn - 1]) {
191 func->card = card;
192 func->num = card->sdio_func[fn - 1]->num;
193 func->tuples = card->sdio_func[fn - 1]->tuples;
194 func->tmpbuf = card->sdio_func[fn - 1]->tmpbuf;
195 hqa_result = card->sdio_func[fn - 1]->max_blksize;
196 func->max_blksize = hqa_result;
197 if ((cmd == Hqa_read) || (cmd == Hqa_write)) {
198 func->cur_blksize = 8;
199 } else if ((cmd == Stress_write) ||
200 (cmd == Stress_read) ||
201 (cmd == SDIO_read_fix_Tput) ||
202 (cmd == SDIO_write_fix_Tput)) {
203 func->cur_blksize = 0x200;
204 fac_buf = kmalloc(SDIO_XFER_SIZE, GFP_KERNEL);
205 if (!fac_buf) {
206 kfree(func);
207 goto end;
208 }
209 if (extra == 1) {
210 ret = wait_for_random_bytes();
211 if (ret)
212 dev_info(mmc_dev(host),
213 "wait random bytes fail.\n");
214 get_random_bytes(fac_buf,
215 SDIO_XFER_SIZE);
216 } else
217 memset(fac_buf, 0x5a, SDIO_XFER_SIZE);
218 } else {
219 func->cur_blksize = 1;
220 }
221 } else {
222 dev_info(mmc_dev(host), "func %d is null,.\n", fn);
223 }
224 } else {
225 /**
226 * function 0 should not need struct func.
227 * but the api need the parameter, so we create
228 * the a new func for function 0.
229 */
230 func->card = card;
231 func->tuples = card->tuples;
232 func->num = 0;
233 func->max_blksize = 16;
234 if ((cmd == Hqa_read) || (cmd == Hqa_write))
235 func->cur_blksize = 16;
236 else
237 func->cur_blksize = 1;
238
239 func->tmpbuf = kmalloc(func->cur_blksize, GFP_KERNEL);
240 if (!func->tmpbuf) {
241 kfree(func);
242 goto end;
243 }
244 memset(func->tmpbuf, 0, func->cur_blksize);
245 }
246
247 sdio_claim_host(func);
248
249 switch (cmd) {
250 case Read:
251 dev_info(mmc_dev(host), "read addr:%x, fn:%d.\n", addr, fn);
252 ret = 0;
253 if (fn == 0)
254 result = sdio_f0_readb(func, addr, &ret);
255 else
256 result = sdio_readb(func, addr, &ret);
257
258 if (ret)
259 dev_info(mmc_dev(host), "Read fail(%d).\n", ret);
260 else
261 dev_info(mmc_dev(host), "f%d reg(%x) is 0x%02x.\n",
262 func->num, addr, result);
263 break;
264 case Write:
265 dev_info(mmc_dev(host), "write addr:%x, value:%x, fn:%d.\n",
266 addr, (u8)value, fn);
267 ret = 0;
268 if (fn == 0)
269 /* (0xF0 - 0xFF) are permiited for func0 */
270 sdio_f0_writeb(func, (u8)value, addr, &ret);
271 else
272 sdio_writeb(func, (u8)value, addr, &ret);
273
274 if (ret)
275 dev_info(mmc_dev(host), "write fail(%d).\n", ret);
276 else
277 dev_info(mmc_dev(host), "write success(%d).\n", ret);
278
279 break;
280 case Hqa_read:
281 dev_info(mmc_dev(host), "read addr:%x, fn %d\n", addr, fn);
282 i = 0;
283 hqa_result = 0;
284 do {
285 ret = 0;
286 hqa_result = sdio_readl(func, addr, &ret);
287 if (ret)
288 dev_info(mmc_dev(host), "Read f%d reg(%x) fail(%d).\n",
289 func->num, addr, ret);
290 i = i + 1;
291 } while (i < 0x10000);
292 dev_info(mmc_dev(host), "Read result: 0x%02x.\n", hqa_result);
293 break;
294 case Hqa_write:
295 dev_info(mmc_dev(host), "write addr:%x, value:%x, fn %d\n",
296 addr, value, fn);
297 i = 0;
298 hqa_result = 0;
299 do {
300 ret = 0;
301 sdio_writel(func, value, addr, &ret);
302 if (ret)
303 dev_info(mmc_dev(host), "write f%d reg(%x) fail(%d).\n",
304 func->num, addr, ret);
305 i = i + 1;
306 } while (i < 0x10000);
307 dev_info(mmc_dev(host), "write success(%d).\n", ret);
308 break;
309 case Reset:
310 mmc_hw_reset(host);
311 break;
312 case Stress_read:
313 case Stress_write:
314 /* value is loop count, default 400 if not set */
315 if (value == 0)
316 value = 400;
317
318 i = 0;
319 total = 0;
320
321 KAL_REC_TIME_START();
322 do {
323 if (cmd == Stress_read)
324 ret = sdio_readsb(func, fac_buf,
325 addr, SDIO_XFER_SIZE);
326 else
327 ret = sdio_writesb(func, addr,
328 fac_buf, SDIO_XFER_SIZE);
329 if (ret)
330 count_r = count_r + 1;
331 else
332 total += SDIO_XFER_SIZE / 1024;
333 i = i + 1;
334 } while (i < value);
335 KAL_REC_TIME_END();
336 usec = KAL_GET_TIME_INTERVAL();
337 dev_info(mmc_dev(host),
338 "%s %lu Kbps, loop:%u, msec:%ld, err:%lx, buf:0x%08x...\n",
339 cmd == Stress_read ? "read":"write",
340 total / (usec / USEC_PER_MSEC) * 1024 * 8,
341 value, (usec / USEC_PER_MSEC), count_r,
342 *(unsigned int *)fac_buf);
343 break;
344 case SDIO_read_fix_Tput:
345 case SDIO_write_fix_Tput:
346 /* value is target T-put Mbps, offset is loop count */
347 if (value == 0 || offset == 0) {
348 dev_info(mmc_dev(host), "cmd:%d, err input\n",
349 cmd);
350 break;
351 }
352
353 i = 0;
354 r_usec = 0;
355 total = 0;
356
357 sdio_release_host(func);
358
359 do {
360 sdio_claim_host(func);
361
362 /* evaluate speed */
363 KAL_REC_TIME_START();
364 if (cmd == SDIO_read_fix_Tput)
365 ret = sdio_readsb(func, fac_buf,
366 addr, SDIO_XFER_SIZE);
367 else
368 ret = sdio_writesb(func, addr,
369 fac_buf, SDIO_XFER_SIZE);
370 KAL_REC_TIME_END();
371 usec = KAL_GET_TIME_INTERVAL();
372
373 sdio_release_host(func);
374
375 if (ret) {
376 dev_info(mmc_dev(host), "error.\n");
377 count_r = count_r + 1;
378 } else
379 total += (SDIO_XFER_SIZE / 1024);
380
381 /* calculate manual delay to target speed */
382 usec_sleep = SDIO_XFER_SIZE * 8 / value - usec;
383 if (usec_sleep > 0)
384 usleep_range(usec_sleep,
385 usec_sleep + 100);
386
387 KAL_REC_TIME_END();
388 r_usec += KAL_GET_TIME_INTERVAL();
389
390 i = i + 1;
391 } while (i < offset);
392
393 sdio_claim_host(func);
394
395 dev_info(mmc_dev(host),
396 "%s %lu Kbps(%u Mbps), msec:%ld, loop:%u, err:%lx, buf:0x%08x...\n",
397 cmd == SDIO_read_fix_Tput ? "read":"write",
398 total / (r_usec / USEC_PER_MSEC) * 1024 * 8,
399 value, r_usec / USEC_PER_MSEC, offset, count_r,
400 *(unsigned int *)fac_buf);
401 break;
402 default:
403 dev_info(mmc_dev(host), "cmd is not valid.\n");
404 break;
405 }
406
407 sdio_release_host(func);
408 kfree(func);
409
410end:
411 kfree(str_hand);
412 kfree(cmd_buf);
413 kfree(fac_buf);
414
415 return count;
416}
417
418/**
419 * open function show some stable information.
420 */
421static int sdio_proc_open(struct inode *inode, struct file *file)
422{
423 return single_open(file, sdio_proc_show, inode->i_private);
424}
425
426/**
427 * sdio pre is our own function.
428 * seq or single pre is the kernel function.
429 */
430static const struct file_operations sdio_proc_fops = {
431 .owner = THIS_MODULE,
432 .open = sdio_proc_open,
433 .release = single_release,
434 .write = sdio_proc_write,
435 .read = seq_read,
436 .llseek = seq_lseek,
437};
438
439int sdio_proc_init(struct mmc_host *host_init)
440{
441 struct proc_dir_entry *prEntry;
442 static int flag;
443
444 if (!strcmp(mmc_hostname(host_init), "mmc0")) {
445 host_arry[0] = host_init;
446 max_id = 1;
447 } else if (!strcmp(mmc_hostname(host_init), "mmc1")) {
448 host_arry[1] = host_init;
449 max_id = 2;
450 } else if (!strcmp(mmc_hostname(host_init), "mmc2")) {
451 host_arry[2] = host_init;
452 max_id = 3;
453 } else
454 return 0;
455
456 if (!flag)
457 prEntry = proc_create("sdio", 0660, NULL, &sdio_proc_fops);
458 else
459 return 0;
460
461 if (prEntry) {
462 flag = 1;
463 dev_info(mmc_dev(host_init), "/proc/sdio is created.\n");
464 } else
465 dev_info(mmc_dev(host_init), "create /proc/sdio failed.\n");
466
467 return 0;
468}