--- linux-4.9.37/drivers/mmc/host/sdhci-proc.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-4.9.y/drivers/mmc/host/sdhci-proc.c 2021-06-07 13:01:33.000000000 +0300 @@ -0,0 +1,272 @@ +/* + * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "sdhci.h" +#include "sdhci-proc.h" + +#define MCI_PARENT "mci" +#define MCI_STATS_PROC "mci_info" +#define MAX_CLOCK_SCALE 4 + +unsigned int slot_index; +struct mmc_host *mci_host[MCI_SLOT_NUM] = {NULL}; +static struct proc_dir_entry *proc_mci_dir; + +static char *card_type[MAX_CARD_TYPE + 1] = { + "MMC card", + "SD card", + "SDIO card", + "SD combo (IO+mem) card", + "unknown" +}; +static char *clock_unit[MAX_CLOCK_SCALE] = { + "Hz", + "KHz", + "MHz", + "GHz" +}; + +static char *mci_get_card_type(unsigned int sd_type) +{ + if (sd_type >= MAX_CARD_TYPE) + return card_type[MAX_CARD_TYPE]; + else + return card_type[sd_type]; +} + +static unsigned int analyze_clock_scale(unsigned int clock, unsigned int *clock_val) +{ + unsigned int scale = 0; + unsigned int tmp = clock; + + while (1) { + tmp = tmp / 1000; /* 1000 for clk calculate */ + if (tmp > 0) { + *clock_val = tmp; + scale++; + } else { + break; + } + } + return scale; +} + +static inline int is_card_uhs(unsigned char timing) +{ + return timing >= MMC_TIMING_UHS_SDR12 && + timing <= MMC_TIMING_UHS_DDR50; +}; + +static inline int is_card_hs(unsigned char timing) +{ + return timing == MMC_TIMING_SD_HS || timing == MMC_TIMING_MMC_HS; +}; + +static void mci_stats_seq_printout(struct seq_file *s) +{ + unsigned int index_mci; + unsigned int clock; + unsigned int clock_scale; + unsigned int clock_value = 0; + const char *type = NULL; + static struct mmc_host *mmc = NULL; + const char *uhs_bus_speed_mode = ""; + static const char *uhs_speeds[] = { + [UHS_SDR12_BUS_SPEED] = "SDR12 ", + [UHS_SDR25_BUS_SPEED] = "SDR25 ", + [UHS_SDR50_BUS_SPEED] = "SDR50 ", + [UHS_SDR104_BUS_SPEED] = "SDR104 ", + [UHS_DDR50_BUS_SPEED] = "DDR50 ", + }; + unsigned int speed_class, grade_speed_uhs; + struct card_info *info = NULL; + unsigned int present; + struct sdhci_host *host = NULL; + + for (index_mci = 0; index_mci < MCI_SLOT_NUM; index_mci++) { + mmc = mci_host[index_mci]; + if (mmc == NULL) { + seq_printf(s, "MCI%d: invalid\n", index_mci); + continue; + } else { + seq_printf(s, "MCI%d", index_mci); + } + host = mmc_priv(mmc); + info = &host->c_info; + + present = host->mmc->ops->get_cd(host->mmc); + if (present) + seq_puts(s, ": pluged"); + else + seq_puts(s, ": unplugged"); + + if (info->card_connect != CARD_CONNECT) { + if (mmc->card_status == MMC_CARD_INIT_FAIL) + seq_puts(s, "_init_failed\n"); + else + seq_puts(s, "_disconnected\n"); + } else { + seq_puts(s, "_connected\n"); + + seq_printf(s, "\tType: %s", + mci_get_card_type(info->card_type)); + + if (info->card_state & MMC_STATE_BLOCKADDR) { + if (info->card_state & MMC_CARD_SDXC) + type = "SDXC"; + else + type = "SDHC"; + seq_printf(s, "(%s)\n", type); + } + + if (is_card_uhs(info->timing) && + info->sd_bus_speed < ARRAY_SIZE(uhs_speeds)) + uhs_bus_speed_mode = + uhs_speeds[info->sd_bus_speed]; + + seq_printf(s, "\tMode: %s%s%s%s\n", + is_card_uhs(info->timing) ? "UHS " : + (is_card_hs(info->timing) ? "HS " : ""), + info->timing == MMC_TIMING_MMC_HS400 ? "HS400 " : + (info->timing == MMC_TIMING_MMC_HS200 ? "HS200 " : ""), + info->timing == MMC_TIMING_MMC_DDR52 ? "DDR " : "", + uhs_bus_speed_mode); + + speed_class = UNSTUFF_BITS(info->ssr, 56, 8); /* 56 equal 440 -384 */ + grade_speed_uhs = UNSTUFF_BITS(info->ssr, 12, 4); /* 12 equal 396 - 384 */ + seq_printf(s, "\tSpeed Class: Class %s\n", + (speed_class == 0x00) ? "0" : + (speed_class == 0x01) ? "2" : + (speed_class == 0x02) ? "4" : + (speed_class == 0x03) ? "6" : + (speed_class == 0x04) ? "10" : + "Reserved"); + seq_printf(s, "\tUhs Speed Grade: %s\n", + (grade_speed_uhs == 0x00) ? + "Less than 10MB/sec(0h)" : + (grade_speed_uhs == 0x01) ? + "10MB/sec and above(1h)" : + "Reserved"); + + clock = info->card_support_clock; + clock_scale = analyze_clock_scale(clock, &clock_value); + seq_printf(s, "\tHost work clock: %d%s\n", + clock_value, clock_unit[clock_scale]); + + clock = info->card_support_clock; + clock_scale = analyze_clock_scale(clock, &clock_value); + seq_printf(s, "\tCard support clock: %d%s\n", + clock_value, clock_unit[clock_scale]); + + clock = mmc->actual_clock; + clock_scale = analyze_clock_scale(clock, &clock_value); + seq_printf(s, "\tCard work clock: %d%s\n", + clock_value, clock_unit[clock_scale]); + + /* add card read/write error count */ + seq_printf(s, "\tCard error count: %d\n", + host->error_count); + } + } +} + +/* proc interface setup */ +static void *mci_seq_start(struct seq_file *s, loff_t *pos) +{ + /* counter is used to tracking multi proc interfaces + * We have only one interface so return zero + * pointer to start the sequence. + */ + static unsigned long counter; + + if (*pos == 0) + return &counter; + + *pos = 0; + return NULL; +} + +/* proc interface next */ +static void *mci_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + (*pos)++; + if (*pos >= MCI_SLOT_NUM) + return NULL; + + return NULL; +} + +/* define parameters where showed in proc file */ +static int mci_stats_seq_show(struct seq_file *s, void *v) +{ + mci_stats_seq_printout(s); + return 0; +} + +/* proc interface stop */ +static void mci_seq_stop(struct seq_file *s, void *v) +{ +} + +/* proc interface operation */ +static const struct seq_operations mci_stats_seq_ops = { + .start = mci_seq_start, + .next = mci_seq_next, + .stop = mci_seq_stop, + .show = mci_stats_seq_show +}; + +/* proc file open */ +static int mci_stats_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &mci_stats_seq_ops); +}; + +/* proc file operation */ +static const struct file_operations mci_stats_proc_ops = { + .owner = THIS_MODULE, + .open = mci_stats_proc_open, + .read = seq_read, + .release = seq_release +}; + +int mci_proc_init(void) +{ + struct proc_dir_entry *proc_stats_entry = NULL; + + proc_mci_dir = proc_mkdir(MCI_PARENT, NULL); + if (!proc_mci_dir) { + pr_err("%s: failed to create proc file %s\n", + __func__, MCI_PARENT); + return 1; + } + + proc_stats_entry = proc_create(MCI_STATS_PROC, + 0, proc_mci_dir, &mci_stats_proc_ops); + if (!proc_stats_entry) { + pr_err("%s: failed to create proc file %s\n", + __func__, MCI_STATS_PROC); + return 1; + } + + return 0; +} + +int mci_proc_shutdown(void) +{ + if (proc_mci_dir) { + remove_proc_entry(MCI_STATS_PROC, proc_mci_dir); + remove_proc_entry(MCI_PARENT, NULL); + proc_mci_dir = NULL; + } + + return 0; +}