1 /* 2 * Debugfs support for hosts and cards 3 * 4 * Copyright (C) 2008 Atmel Corporation 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 #include <linux/moduleparam.h> 11 #include <linux/debugfs.h> 12 #include <linux/fs.h> 13 #include <linux/seq_file.h> 14 #include <linux/slab.h> 15 #include <linux/stat.h> 16 #include <linux/fault-inject.h> 17 18 #include <linux/mmc/card.h> 19 #include <linux/mmc/host.h> 20 21 #include "core.h" 22 #include "mmc_ops.h" 23 24 #ifdef CONFIG_FAIL_MMC_REQUEST 25 26 static DECLARE_FAULT_ATTR(fail_default_attr); 27 static char *fail_request; 28 module_param(fail_request, charp, 0); 29 30 #endif /* CONFIG_FAIL_MMC_REQUEST */ 31 32 /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */ 33 static int mmc_ios_show(struct seq_file *s, void *data) 34 { 35 static const char *vdd_str[] = { 36 [8] = "2.0", 37 [9] = "2.1", 38 [10] = "2.2", 39 [11] = "2.3", 40 [12] = "2.4", 41 [13] = "2.5", 42 [14] = "2.6", 43 [15] = "2.7", 44 [16] = "2.8", 45 [17] = "2.9", 46 [18] = "3.0", 47 [19] = "3.1", 48 [20] = "3.2", 49 [21] = "3.3", 50 [22] = "3.4", 51 [23] = "3.5", 52 [24] = "3.6", 53 }; 54 struct mmc_host *host = s->private; 55 struct mmc_ios *ios = &host->ios; 56 const char *str; 57 58 seq_printf(s, "clock:\t\t%u Hz\n", ios->clock); 59 seq_printf(s, "vdd:\t\t%u ", ios->vdd); 60 if ((1 << ios->vdd) & MMC_VDD_165_195) 61 seq_printf(s, "(1.65 - 1.95 V)\n"); 62 else if (ios->vdd < (ARRAY_SIZE(vdd_str) - 1) 63 && vdd_str[ios->vdd] && vdd_str[ios->vdd + 1]) 64 seq_printf(s, "(%s ~ %s V)\n", vdd_str[ios->vdd], 65 vdd_str[ios->vdd + 1]); 66 else 67 seq_printf(s, "(invalid)\n"); 68 69 switch (ios->bus_mode) { 70 case MMC_BUSMODE_OPENDRAIN: 71 str = "open drain"; 72 break; 73 case MMC_BUSMODE_PUSHPULL: 74 str = "push-pull"; 75 break; 76 default: 77 str = "invalid"; 78 break; 79 } 80 seq_printf(s, "bus mode:\t%u (%s)\n", ios->bus_mode, str); 81 82 switch (ios->chip_select) { 83 case MMC_CS_DONTCARE: 84 str = "don't care"; 85 break; 86 case MMC_CS_HIGH: 87 str = "active high"; 88 break; 89 case MMC_CS_LOW: 90 str = "active low"; 91 break; 92 default: 93 str = "invalid"; 94 break; 95 } 96 seq_printf(s, "chip select:\t%u (%s)\n", ios->chip_select, str); 97 98 switch (ios->power_mode) { 99 case MMC_POWER_OFF: 100 str = "off"; 101 break; 102 case MMC_POWER_UP: 103 str = "up"; 104 break; 105 case MMC_POWER_ON: 106 str = "on"; 107 break; 108 default: 109 str = "invalid"; 110 break; 111 } 112 seq_printf(s, "power mode:\t%u (%s)\n", ios->power_mode, str); 113 seq_printf(s, "bus width:\t%u (%u bits)\n", 114 ios->bus_width, 1 << ios->bus_width); 115 116 switch (ios->timing) { 117 case MMC_TIMING_LEGACY: 118 str = "legacy"; 119 break; 120 case MMC_TIMING_MMC_HS: 121 str = "mmc high-speed"; 122 break; 123 case MMC_TIMING_SD_HS: 124 str = "sd high-speed"; 125 break; 126 case MMC_TIMING_UHS_SDR50: 127 str = "sd uhs SDR50"; 128 break; 129 case MMC_TIMING_UHS_SDR104: 130 str = "sd uhs SDR104"; 131 break; 132 case MMC_TIMING_UHS_DDR50: 133 str = "sd uhs DDR50"; 134 break; 135 default: 136 str = "invalid"; 137 break; 138 } 139 seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str); 140 141 return 0; 142 } 143 144 static int mmc_ios_open(struct inode *inode, struct file *file) 145 { 146 return single_open(file, mmc_ios_show, inode->i_private); 147 } 148 149 static const struct file_operations mmc_ios_fops = { 150 .open = mmc_ios_open, 151 .read = seq_read, 152 .llseek = seq_lseek, 153 .release = single_release, 154 }; 155 156 static int mmc_clock_opt_get(void *data, u64 *val) 157 { 158 struct mmc_host *host = data; 159 160 *val = host->ios.clock; 161 162 return 0; 163 } 164 165 static int mmc_clock_opt_set(void *data, u64 val) 166 { 167 struct mmc_host *host = data; 168 169 /* We need this check due to input value is u64 */ 170 if (val > host->f_max) 171 return -EINVAL; 172 173 mmc_claim_host(host); 174 mmc_set_clock(host, (unsigned int) val); 175 mmc_release_host(host); 176 177 return 0; 178 } 179 180 DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set, 181 "%llu\n"); 182 183 void mmc_add_host_debugfs(struct mmc_host *host) 184 { 185 struct dentry *root; 186 187 root = debugfs_create_dir(mmc_hostname(host), NULL); 188 if (IS_ERR(root)) 189 /* Don't complain -- debugfs just isn't enabled */ 190 return; 191 if (!root) 192 /* Complain -- debugfs is enabled, but it failed to 193 * create the directory. */ 194 goto err_root; 195 196 host->debugfs_root = root; 197 198 if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops)) 199 goto err_node; 200 201 if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host, 202 &mmc_clock_fops)) 203 goto err_node; 204 205 #ifdef CONFIG_MMC_CLKGATE 206 if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR), 207 root, &host->clk_delay)) 208 goto err_node; 209 #endif 210 #ifdef CONFIG_FAIL_MMC_REQUEST 211 if (fail_request) 212 setup_fault_attr(&fail_default_attr, fail_request); 213 host->fail_mmc_request = fail_default_attr; 214 if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request", 215 root, 216 &host->fail_mmc_request))) 217 goto err_node; 218 #endif 219 return; 220 221 err_node: 222 debugfs_remove_recursive(root); 223 host->debugfs_root = NULL; 224 err_root: 225 dev_err(&host->class_dev, "failed to initialize debugfs\n"); 226 } 227 228 void mmc_remove_host_debugfs(struct mmc_host *host) 229 { 230 debugfs_remove_recursive(host->debugfs_root); 231 } 232 233 static int mmc_dbg_card_status_get(void *data, u64 *val) 234 { 235 struct mmc_card *card = data; 236 u32 status; 237 int ret; 238 239 mmc_claim_host(card->host); 240 241 ret = mmc_send_status(data, &status); 242 if (!ret) 243 *val = status; 244 245 mmc_release_host(card->host); 246 247 return ret; 248 } 249 DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get, 250 NULL, "%08llx\n"); 251 252 #define EXT_CSD_STR_LEN 1025 253 254 static int mmc_ext_csd_open(struct inode *inode, struct file *filp) 255 { 256 struct mmc_card *card = inode->i_private; 257 char *buf; 258 ssize_t n = 0; 259 u8 *ext_csd; 260 int err, i; 261 262 buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL); 263 if (!buf) 264 return -ENOMEM; 265 266 ext_csd = kmalloc(512, GFP_KERNEL); 267 if (!ext_csd) { 268 err = -ENOMEM; 269 goto out_free; 270 } 271 272 mmc_claim_host(card->host); 273 err = mmc_send_ext_csd(card, ext_csd); 274 mmc_release_host(card->host); 275 if (err) 276 goto out_free; 277 278 for (i = 511; i >= 0; i--) 279 n += sprintf(buf + n, "%02x", ext_csd[i]); 280 n += sprintf(buf + n, "\n"); 281 BUG_ON(n != EXT_CSD_STR_LEN); 282 283 filp->private_data = buf; 284 kfree(ext_csd); 285 return 0; 286 287 out_free: 288 kfree(buf); 289 kfree(ext_csd); 290 return err; 291 } 292 293 static ssize_t mmc_ext_csd_read(struct file *filp, char __user *ubuf, 294 size_t cnt, loff_t *ppos) 295 { 296 char *buf = filp->private_data; 297 298 return simple_read_from_buffer(ubuf, cnt, ppos, 299 buf, EXT_CSD_STR_LEN); 300 } 301 302 static int mmc_ext_csd_release(struct inode *inode, struct file *file) 303 { 304 kfree(file->private_data); 305 return 0; 306 } 307 308 static const struct file_operations mmc_dbg_ext_csd_fops = { 309 .open = mmc_ext_csd_open, 310 .read = mmc_ext_csd_read, 311 .release = mmc_ext_csd_release, 312 .llseek = default_llseek, 313 }; 314 315 void mmc_add_card_debugfs(struct mmc_card *card) 316 { 317 struct mmc_host *host = card->host; 318 struct dentry *root; 319 320 if (!host->debugfs_root) 321 return; 322 323 root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root); 324 if (IS_ERR(root)) 325 /* Don't complain -- debugfs just isn't enabled */ 326 return; 327 if (!root) 328 /* Complain -- debugfs is enabled, but it failed to 329 * create the directory. */ 330 goto err; 331 332 card->debugfs_root = root; 333 334 if (!debugfs_create_x32("state", S_IRUSR, root, &card->state)) 335 goto err; 336 337 if (mmc_card_mmc(card) || mmc_card_sd(card)) 338 if (!debugfs_create_file("status", S_IRUSR, root, card, 339 &mmc_dbg_card_status_fops)) 340 goto err; 341 342 if (mmc_card_mmc(card)) 343 if (!debugfs_create_file("ext_csd", S_IRUSR, root, card, 344 &mmc_dbg_ext_csd_fops)) 345 goto err; 346 347 return; 348 349 err: 350 debugfs_remove_recursive(root); 351 card->debugfs_root = NULL; 352 dev_err(&card->dev, "failed to initialize debugfs\n"); 353 } 354 355 void mmc_remove_card_debugfs(struct mmc_card *card) 356 { 357 debugfs_remove_recursive(card->debugfs_root); 358 } 359