atmel-mci: debugfs support

Create additional files under the host's debugfs directory containing
additional host-specific debug information.

Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

authored by

Haavard Skinnemoen and committed by
Pierre Ossman
deec9ae3 f4b7f927

+191
+2
drivers/mmc/host/atmel-mci-regs.h
··· 82 82 # define MCI_OVRE ( 1 << 30) /* RX Overrun Error */ 83 83 # define MCI_UNRE ( 1 << 31) /* TX Underrun Error */ 84 84 85 + #define MCI_REGS_SIZE 0x100 86 + 85 87 /* Register access macros */ 86 88 #define mci_readl(port,reg) \ 87 89 __raw_readl((port)->regs + MCI_##reg)
+189
drivers/mmc/host/atmel-mci.c
··· 9 9 */ 10 10 #include <linux/blkdev.h> 11 11 #include <linux/clk.h> 12 + #include <linux/debugfs.h> 12 13 #include <linux/device.h> 13 14 #include <linux/init.h> 14 15 #include <linux/interrupt.h> ··· 17 16 #include <linux/module.h> 18 17 #include <linux/platform_device.h> 19 18 #include <linux/scatterlist.h> 19 + #include <linux/seq_file.h> 20 + #include <linux/stat.h> 20 21 21 22 #include <linux/mmc/host.h> 22 23 ··· 91 88 #define atmci_clear_pending(host, event) \ 92 89 clear_bit(event, &host->pending_events) 93 90 91 + /* 92 + * The debugfs stuff below is mostly optimized away when 93 + * CONFIG_DEBUG_FS is not set. 94 + */ 95 + static int atmci_req_show(struct seq_file *s, void *v) 96 + { 97 + struct atmel_mci *host = s->private; 98 + struct mmc_request *mrq = host->mrq; 99 + struct mmc_command *cmd; 100 + struct mmc_command *stop; 101 + struct mmc_data *data; 102 + 103 + /* Make sure we get a consistent snapshot */ 104 + spin_lock_irq(&host->mmc->lock); 105 + 106 + if (mrq) { 107 + cmd = mrq->cmd; 108 + data = mrq->data; 109 + stop = mrq->stop; 110 + 111 + if (cmd) 112 + seq_printf(s, 113 + "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 114 + cmd->opcode, cmd->arg, cmd->flags, 115 + cmd->resp[0], cmd->resp[1], cmd->resp[2], 116 + cmd->resp[2], cmd->error); 117 + if (data) 118 + seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", 119 + data->bytes_xfered, data->blocks, 120 + data->blksz, data->flags, data->error); 121 + if (stop) 122 + seq_printf(s, 123 + "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 124 + stop->opcode, stop->arg, stop->flags, 125 + stop->resp[0], stop->resp[1], stop->resp[2], 126 + stop->resp[2], stop->error); 127 + } 128 + 129 + spin_unlock_irq(&host->mmc->lock); 130 + 131 + return 0; 132 + } 133 + 134 + static int atmci_req_open(struct inode *inode, struct file *file) 135 + { 136 + return single_open(file, atmci_req_show, inode->i_private); 137 + } 138 + 139 + static const struct file_operations atmci_req_fops = { 140 + .owner = THIS_MODULE, 141 + .open = atmci_req_open, 142 + .read = seq_read, 143 + .llseek = seq_lseek, 144 + .release = single_release, 145 + }; 146 + 147 + static void atmci_show_status_reg(struct seq_file *s, 148 + const char *regname, u32 value) 149 + { 150 + static const char *sr_bit[] = { 151 + [0] = "CMDRDY", 152 + [1] = "RXRDY", 153 + [2] = "TXRDY", 154 + [3] = "BLKE", 155 + [4] = "DTIP", 156 + [5] = "NOTBUSY", 157 + [8] = "SDIOIRQA", 158 + [9] = "SDIOIRQB", 159 + [16] = "RINDE", 160 + [17] = "RDIRE", 161 + [18] = "RCRCE", 162 + [19] = "RENDE", 163 + [20] = "RTOE", 164 + [21] = "DCRCE", 165 + [22] = "DTOE", 166 + [30] = "OVRE", 167 + [31] = "UNRE", 168 + }; 169 + unsigned int i; 170 + 171 + seq_printf(s, "%s:\t0x%08x", regname, value); 172 + for (i = 0; i < ARRAY_SIZE(sr_bit); i++) { 173 + if (value & (1 << i)) { 174 + if (sr_bit[i]) 175 + seq_printf(s, " %s", sr_bit[i]); 176 + else 177 + seq_puts(s, " UNKNOWN"); 178 + } 179 + } 180 + seq_putc(s, '\n'); 181 + } 182 + 183 + static int atmci_regs_show(struct seq_file *s, void *v) 184 + { 185 + struct atmel_mci *host = s->private; 186 + u32 *buf; 187 + 188 + buf = kmalloc(MCI_REGS_SIZE, GFP_KERNEL); 189 + if (!buf) 190 + return -ENOMEM; 191 + 192 + /* Grab a more or less consistent snapshot */ 193 + spin_lock_irq(&host->mmc->lock); 194 + memcpy_fromio(buf, host->regs, MCI_REGS_SIZE); 195 + spin_unlock_irq(&host->mmc->lock); 196 + 197 + seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n", 198 + buf[MCI_MR / 4], 199 + buf[MCI_MR / 4] & MCI_MR_RDPROOF ? " RDPROOF" : "", 200 + buf[MCI_MR / 4] & MCI_MR_WRPROOF ? " WRPROOF" : "", 201 + buf[MCI_MR / 4] & 0xff); 202 + seq_printf(s, "DTOR:\t0x%08x\n", buf[MCI_DTOR / 4]); 203 + seq_printf(s, "SDCR:\t0x%08x\n", buf[MCI_SDCR / 4]); 204 + seq_printf(s, "ARGR:\t0x%08x\n", buf[MCI_ARGR / 4]); 205 + seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n", 206 + buf[MCI_BLKR / 4], 207 + buf[MCI_BLKR / 4] & 0xffff, 208 + (buf[MCI_BLKR / 4] >> 16) & 0xffff); 209 + 210 + /* Don't read RSPR and RDR; it will consume the data there */ 211 + 212 + atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]); 213 + atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]); 214 + 215 + return 0; 216 + } 217 + 218 + static int atmci_regs_open(struct inode *inode, struct file *file) 219 + { 220 + return single_open(file, atmci_regs_show, inode->i_private); 221 + } 222 + 223 + static const struct file_operations atmci_regs_fops = { 224 + .owner = THIS_MODULE, 225 + .open = atmci_regs_open, 226 + .read = seq_read, 227 + .llseek = seq_lseek, 228 + .release = single_release, 229 + }; 230 + 231 + static void atmci_init_debugfs(struct atmel_mci *host) 232 + { 233 + struct mmc_host *mmc; 234 + struct dentry *root; 235 + struct dentry *node; 236 + struct resource *res; 237 + 238 + mmc = host->mmc; 239 + root = mmc->debugfs_root; 240 + if (!root) 241 + return; 242 + 243 + node = debugfs_create_file("regs", S_IRUSR, root, host, 244 + &atmci_regs_fops); 245 + if (IS_ERR(node)) 246 + return; 247 + if (!node) 248 + goto err; 249 + 250 + res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); 251 + node->d_inode->i_size = res->end - res->start + 1; 252 + 253 + node = debugfs_create_file("req", S_IRUSR, root, host, &atmci_req_fops); 254 + if (!node) 255 + goto err; 256 + 257 + node = debugfs_create_x32("pending_events", S_IRUSR, root, 258 + (u32 *)&host->pending_events); 259 + if (!node) 260 + goto err; 261 + 262 + node = debugfs_create_x32("completed_events", S_IRUSR, root, 263 + (u32 *)&host->completed_events); 264 + if (!node) 265 + goto err; 266 + 267 + return; 268 + 269 + err: 270 + dev_err(&host->pdev->dev, 271 + "failed to initialize debugfs for controller\n"); 272 + } 94 273 95 274 static void atmci_enable(struct atmel_mci *host) 96 275 { ··· 1090 905 "Atmel MCI controller at 0x%08lx irq %d\n", 1091 906 host->mapbase, irq); 1092 907 908 + atmci_init_debugfs(host); 909 + 1093 910 return 0; 1094 911 1095 912 err_request_irq: ··· 1110 923 platform_set_drvdata(pdev, NULL); 1111 924 1112 925 if (host) { 926 + /* Debugfs stuff is cleaned up by mmc core */ 927 + 1113 928 if (host->detect_pin >= 0) { 1114 929 int pin = host->detect_pin; 1115 930