brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · f10a4dc Raw
400 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Debugfs support for hosts and cards4 *5 * Copyright (C) 2008 Atmel Corporation6 */7#include <linux/moduleparam.h>8#include <linux/export.h>9#include <linux/debugfs.h>10#include <linux/fs.h>11#include <linux/seq_file.h>12#include <linux/slab.h>13#include <linux/stat.h>14#include <linux/fault-inject.h>15#include <linux/time.h>16 17#include <linux/mmc/card.h>18#include <linux/mmc/host.h>19#include <linux/mmc/mmc.h>20#include <linux/mmc/sd.h>21 22#include "core.h"23#include "card.h"24#include "host.h"25#include "mmc_ops.h"26 27#ifdef CONFIG_FAIL_MMC_REQUEST28 29static DECLARE_FAULT_ATTR(fail_default_attr);30static char *fail_request;31module_param(fail_request, charp, 0);32MODULE_PARM_DESC(fail_request, "default fault injection attributes");33 34#endif /* CONFIG_FAIL_MMC_REQUEST */35 36/* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */37static int mmc_ios_show(struct seq_file *s, void *data)38{39	static const char *vdd_str[] = {40		[8]	= "2.0",41		[9]	= "2.1",42		[10]	= "2.2",43		[11]	= "2.3",44		[12]	= "2.4",45		[13]	= "2.5",46		[14]	= "2.6",47		[15]	= "2.7",48		[16]	= "2.8",49		[17]	= "2.9",50		[18]	= "3.0",51		[19]	= "3.1",52		[20]	= "3.2",53		[21]	= "3.3",54		[22]	= "3.4",55		[23]	= "3.5",56		[24]	= "3.6",57	};58	struct mmc_host	*host = s->private;59	struct mmc_ios	*ios = &host->ios;60	const char *str;61 62	seq_printf(s, "clock:\t\t%u Hz\n", ios->clock);63	if (host->actual_clock)64		seq_printf(s, "actual clock:\t%u Hz\n", host->actual_clock);65	seq_printf(s, "vdd:\t\t%u ", ios->vdd);66	if ((1 << ios->vdd) & MMC_VDD_165_195)67		seq_printf(s, "(1.65 - 1.95 V)\n");68	else if (ios->vdd < (ARRAY_SIZE(vdd_str) - 1)69			&& vdd_str[ios->vdd] && vdd_str[ios->vdd + 1])70		seq_printf(s, "(%s ~ %s V)\n", vdd_str[ios->vdd],71				vdd_str[ios->vdd + 1]);72	else73		seq_printf(s, "(invalid)\n");74 75	switch (ios->bus_mode) {76	case MMC_BUSMODE_OPENDRAIN:77		str = "open drain";78		break;79	case MMC_BUSMODE_PUSHPULL:80		str = "push-pull";81		break;82	default:83		str = "invalid";84		break;85	}86	seq_printf(s, "bus mode:\t%u (%s)\n", ios->bus_mode, str);87 88	switch (ios->chip_select) {89	case MMC_CS_DONTCARE:90		str = "don't care";91		break;92	case MMC_CS_HIGH:93		str = "active high";94		break;95	case MMC_CS_LOW:96		str = "active low";97		break;98	default:99		str = "invalid";100		break;101	}102	seq_printf(s, "chip select:\t%u (%s)\n", ios->chip_select, str);103 104	switch (ios->power_mode) {105	case MMC_POWER_OFF:106		str = "off";107		break;108	case MMC_POWER_UP:109		str = "up";110		break;111	case MMC_POWER_ON:112		str = "on";113		break;114	default:115		str = "invalid";116		break;117	}118	seq_printf(s, "power mode:\t%u (%s)\n", ios->power_mode, str);119	seq_printf(s, "bus width:\t%u (%u bits)\n",120			ios->bus_width, 1 << ios->bus_width);121 122	switch (ios->timing) {123	case MMC_TIMING_LEGACY:124		str = "legacy";125		break;126	case MMC_TIMING_MMC_HS:127		str = "mmc high-speed";128		break;129	case MMC_TIMING_SD_HS:130		str = "sd high-speed";131		break;132	case MMC_TIMING_UHS_SDR12:133		str = "sd uhs SDR12";134		break;135	case MMC_TIMING_UHS_SDR25:136		str = "sd uhs SDR25";137		break;138	case MMC_TIMING_UHS_SDR50:139		str = "sd uhs SDR50";140		break;141	case MMC_TIMING_UHS_SDR104:142		str = "sd uhs SDR104";143		break;144	case MMC_TIMING_UHS_DDR50:145		str = "sd uhs DDR50";146		break;147	case MMC_TIMING_MMC_DDR52:148		str = "mmc DDR52";149		break;150	case MMC_TIMING_MMC_HS200:151		str = "mmc HS200";152		break;153	case MMC_TIMING_MMC_HS400:154		str = mmc_card_hs400es(host->card) ?155			"mmc HS400 enhanced strobe" : "mmc HS400";156		break;157	default:158		str = "invalid";159		break;160	}161	seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str);162 163	switch (ios->signal_voltage) {164	case MMC_SIGNAL_VOLTAGE_330:165		str = "3.30 V";166		break;167	case MMC_SIGNAL_VOLTAGE_180:168		str = "1.80 V";169		break;170	case MMC_SIGNAL_VOLTAGE_120:171		str = "1.20 V";172		break;173	default:174		str = "invalid";175		break;176	}177	seq_printf(s, "signal voltage:\t%u (%s)\n", ios->signal_voltage, str);178 179	switch (ios->drv_type) {180	case MMC_SET_DRIVER_TYPE_A:181		str = "driver type A";182		break;183	case MMC_SET_DRIVER_TYPE_B:184		str = "driver type B";185		break;186	case MMC_SET_DRIVER_TYPE_C:187		str = "driver type C";188		break;189	case MMC_SET_DRIVER_TYPE_D:190		str = "driver type D";191		break;192	default:193		str = "invalid";194		break;195	}196	seq_printf(s, "driver type:\t%u (%s)\n", ios->drv_type, str);197 198	return 0;199}200DEFINE_SHOW_ATTRIBUTE(mmc_ios);201 202static int mmc_clock_opt_get(void *data, u64 *val)203{204	struct mmc_host *host = data;205 206	*val = host->ios.clock;207 208	return 0;209}210 211static int mmc_clock_opt_set(void *data, u64 val)212{213	struct mmc_host *host = data;214 215	/* We need this check due to input value is u64 */216	if (val != 0 && (val > host->f_max || val < host->f_min))217		return -EINVAL;218 219	mmc_claim_host(host);220	mmc_set_clock(host, (unsigned int) val);221	mmc_release_host(host);222 223	return 0;224}225 226DEFINE_DEBUGFS_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,227	"%llu\n");228 229static int mmc_err_state_get(void *data, u64 *val)230{231	struct mmc_host *host = data;232	int i;233 234	if (!host)235		return -EINVAL;236 237	*val = 0;238	for (i = 0; i < MMC_ERR_MAX; i++) {239		if (host->err_stats[i]) {240			*val = 1;241			break;242		}243	}244 245	return 0;246}247 248DEFINE_DEBUGFS_ATTRIBUTE(mmc_err_state, mmc_err_state_get, NULL, "%llu\n");249 250static int mmc_err_stats_show(struct seq_file *file, void *data)251{252	struct mmc_host *host = file->private;253	const char *desc[MMC_ERR_MAX] = {254		[MMC_ERR_CMD_TIMEOUT] = "Command Timeout Occurred",255		[MMC_ERR_CMD_CRC] = "Command CRC Errors Occurred",256		[MMC_ERR_DAT_TIMEOUT] = "Data Timeout Occurred",257		[MMC_ERR_DAT_CRC] = "Data CRC Errors Occurred",258		[MMC_ERR_AUTO_CMD] = "Auto-Cmd Error Occurred",259		[MMC_ERR_ADMA] = "ADMA Error Occurred",260		[MMC_ERR_TUNING] = "Tuning Error Occurred",261		[MMC_ERR_CMDQ_RED] = "CMDQ RED Errors",262		[MMC_ERR_CMDQ_GCE] = "CMDQ GCE Errors",263		[MMC_ERR_CMDQ_ICCE] = "CMDQ ICCE Errors",264		[MMC_ERR_REQ_TIMEOUT] = "Request Timedout",265		[MMC_ERR_CMDQ_REQ_TIMEOUT] = "CMDQ Request Timedout",266		[MMC_ERR_ICE_CFG] = "ICE Config Errors",267		[MMC_ERR_CTRL_TIMEOUT] = "Controller Timedout errors",268		[MMC_ERR_UNEXPECTED_IRQ] = "Unexpected IRQ errors",269	};270	int i;271 272	for (i = 0; i < MMC_ERR_MAX; i++) {273		if (desc[i])274			seq_printf(file, "# %s:\t %d\n",275					desc[i], host->err_stats[i]);276	}277 278	return 0;279}280 281static int mmc_err_stats_open(struct inode *inode, struct file *file)282{283	return single_open(file, mmc_err_stats_show, inode->i_private);284}285 286static ssize_t mmc_err_stats_write(struct file *filp, const char __user *ubuf,287				   size_t cnt, loff_t *ppos)288{289	struct mmc_host *host = filp->f_mapping->host->i_private;290 291	pr_debug("%s: Resetting MMC error statistics\n", __func__);292	memset(host->err_stats, 0, sizeof(host->err_stats));293 294	return cnt;295}296 297static const struct file_operations mmc_err_stats_fops = {298	.open	= mmc_err_stats_open,299	.read	= seq_read,300	.write	= mmc_err_stats_write,301	.release = single_release,302};303 304static int mmc_caps_get(void *data, u64 *val)305{306	*val = *(u32 *)data;307	return 0;308}309 310static int mmc_caps_set(void *data, u64 val)311{312	u32 *caps = data;313	u32 diff = *caps ^ val;314	u32 allowed = MMC_CAP_AGGRESSIVE_PM |315		      MMC_CAP_SD_HIGHSPEED |316		      MMC_CAP_MMC_HIGHSPEED |317		      MMC_CAP_UHS |318		      MMC_CAP_DDR;319 320	if (diff & ~allowed)321		return -EINVAL;322 323	*caps = val;324 325	return 0;326}327 328static int mmc_caps2_set(void *data, u64 val)329{330	u32 allowed = MMC_CAP2_HSX00_1_8V | MMC_CAP2_HSX00_1_2V;331	u32 *caps = data;332	u32 diff = *caps ^ val;333 334	if (diff & ~allowed)335		return -EINVAL;336 337	*caps = val;338 339	return 0;340}341 342DEFINE_DEBUGFS_ATTRIBUTE(mmc_caps_fops, mmc_caps_get, mmc_caps_set,343			 "0x%08llx\n");344DEFINE_DEBUGFS_ATTRIBUTE(mmc_caps2_fops, mmc_caps_get, mmc_caps2_set,345			 "0x%08llx\n");346 347void mmc_add_host_debugfs(struct mmc_host *host)348{349	struct dentry *root;350 351	root = debugfs_create_dir(mmc_hostname(host), NULL);352	host->debugfs_root = root;353 354	debugfs_create_file("ios", 0400, root, host, &mmc_ios_fops);355	debugfs_create_file("caps", 0600, root, &host->caps, &mmc_caps_fops);356	debugfs_create_file("caps2", 0600, root, &host->caps2,357			    &mmc_caps2_fops);358	debugfs_create_file_unsafe("clock", 0600, root, host,359				   &mmc_clock_fops);360 361	debugfs_create_file_unsafe("err_state", 0600, root, host,362			    &mmc_err_state);363	debugfs_create_file("err_stats", 0600, root, host,364			    &mmc_err_stats_fops);365 366#ifdef CONFIG_FAIL_MMC_REQUEST367	if (fail_request)368		setup_fault_attr(&fail_default_attr, fail_request);369	host->fail_mmc_request = fail_default_attr;370	fault_create_debugfs_attr("fail_mmc_request", root,371				  &host->fail_mmc_request);372#endif373}374 375void mmc_remove_host_debugfs(struct mmc_host *host)376{377	debugfs_remove_recursive(host->debugfs_root);378}379 380void mmc_add_card_debugfs(struct mmc_card *card)381{382	struct mmc_host	*host = card->host;383	struct dentry	*root;384 385	if (!host->debugfs_root)386		return;387 388	root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);389	card->debugfs_root = root;390 391	debugfs_create_x32("state", 0400, root, &card->state);392	debugfs_create_x32("quirks", 0400, root, &card->quirks);393}394 395void mmc_remove_card_debugfs(struct mmc_card *card)396{397	debugfs_remove_recursive(card->debugfs_root);398	card->debugfs_root = NULL;399}400