1 /* 2 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 */ 14 #include <linux/debugfs.h> 15 #include <linux/dma-mapping.h> 16 #include <linux/uaccess.h> 17 18 #include <soc/tegra/bpmp.h> 19 #include <soc/tegra/bpmp-abi.h> 20 21 struct seqbuf { 22 char *buf; 23 size_t pos; 24 size_t size; 25 }; 26 27 static void seqbuf_init(struct seqbuf *seqbuf, void *buf, size_t size) 28 { 29 seqbuf->buf = buf; 30 seqbuf->size = size; 31 seqbuf->pos = 0; 32 } 33 34 static size_t seqbuf_avail(struct seqbuf *seqbuf) 35 { 36 return seqbuf->pos < seqbuf->size ? seqbuf->size - seqbuf->pos : 0; 37 } 38 39 static size_t seqbuf_status(struct seqbuf *seqbuf) 40 { 41 return seqbuf->pos <= seqbuf->size ? 0 : -EOVERFLOW; 42 } 43 44 static int seqbuf_eof(struct seqbuf *seqbuf) 45 { 46 return seqbuf->pos >= seqbuf->size; 47 } 48 49 static int seqbuf_read(struct seqbuf *seqbuf, void *buf, size_t nbyte) 50 { 51 nbyte = min(nbyte, seqbuf_avail(seqbuf)); 52 memcpy(buf, seqbuf->buf + seqbuf->pos, nbyte); 53 seqbuf->pos += nbyte; 54 return seqbuf_status(seqbuf); 55 } 56 57 static int seqbuf_read_u32(struct seqbuf *seqbuf, uint32_t *v) 58 { 59 int err; 60 61 err = seqbuf_read(seqbuf, v, 4); 62 *v = le32_to_cpu(*v); 63 return err; 64 } 65 66 static int seqbuf_read_str(struct seqbuf *seqbuf, const char **str) 67 { 68 *str = seqbuf->buf + seqbuf->pos; 69 seqbuf->pos += strnlen(*str, seqbuf_avail(seqbuf)); 70 seqbuf->pos++; 71 return seqbuf_status(seqbuf); 72 } 73 74 static void seqbuf_seek(struct seqbuf *seqbuf, ssize_t offset) 75 { 76 seqbuf->pos += offset; 77 } 78 79 /* map filename in Linux debugfs to corresponding entry in BPMP */ 80 static const char *get_filename(struct tegra_bpmp *bpmp, 81 const struct file *file, char *buf, int size) 82 { 83 char root_path_buf[512]; 84 const char *root_path; 85 const char *filename; 86 size_t root_len; 87 88 root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf, 89 sizeof(root_path_buf)); 90 if (IS_ERR(root_path)) 91 return NULL; 92 93 root_len = strlen(root_path); 94 95 filename = dentry_path(file->f_path.dentry, buf, size); 96 if (IS_ERR(filename)) 97 return NULL; 98 99 if (strlen(filename) < root_len || 100 strncmp(filename, root_path, root_len)) 101 return NULL; 102 103 filename += root_len; 104 105 return filename; 106 } 107 108 static int mrq_debugfs_read(struct tegra_bpmp *bpmp, 109 dma_addr_t name, size_t sz_name, 110 dma_addr_t data, size_t sz_data, 111 size_t *nbytes) 112 { 113 struct mrq_debugfs_request req = { 114 .cmd = cpu_to_le32(CMD_DEBUGFS_READ), 115 .fop = { 116 .fnameaddr = cpu_to_le32((uint32_t)name), 117 .fnamelen = cpu_to_le32((uint32_t)sz_name), 118 .dataaddr = cpu_to_le32((uint32_t)data), 119 .datalen = cpu_to_le32((uint32_t)sz_data), 120 }, 121 }; 122 struct mrq_debugfs_response resp; 123 struct tegra_bpmp_message msg = { 124 .mrq = MRQ_DEBUGFS, 125 .tx = { 126 .data = &req, 127 .size = sizeof(req), 128 }, 129 .rx = { 130 .data = &resp, 131 .size = sizeof(resp), 132 }, 133 }; 134 int err; 135 136 err = tegra_bpmp_transfer(bpmp, &msg); 137 if (err < 0) 138 return err; 139 140 *nbytes = (size_t)resp.fop.nbytes; 141 142 return 0; 143 } 144 145 static int mrq_debugfs_write(struct tegra_bpmp *bpmp, 146 dma_addr_t name, size_t sz_name, 147 dma_addr_t data, size_t sz_data) 148 { 149 const struct mrq_debugfs_request req = { 150 .cmd = cpu_to_le32(CMD_DEBUGFS_WRITE), 151 .fop = { 152 .fnameaddr = cpu_to_le32((uint32_t)name), 153 .fnamelen = cpu_to_le32((uint32_t)sz_name), 154 .dataaddr = cpu_to_le32((uint32_t)data), 155 .datalen = cpu_to_le32((uint32_t)sz_data), 156 }, 157 }; 158 struct tegra_bpmp_message msg = { 159 .mrq = MRQ_DEBUGFS, 160 .tx = { 161 .data = &req, 162 .size = sizeof(req), 163 }, 164 }; 165 166 return tegra_bpmp_transfer(bpmp, &msg); 167 } 168 169 static int mrq_debugfs_dumpdir(struct tegra_bpmp *bpmp, dma_addr_t addr, 170 size_t size, size_t *nbytes) 171 { 172 const struct mrq_debugfs_request req = { 173 .cmd = cpu_to_le32(CMD_DEBUGFS_DUMPDIR), 174 .dumpdir = { 175 .dataaddr = cpu_to_le32((uint32_t)addr), 176 .datalen = cpu_to_le32((uint32_t)size), 177 }, 178 }; 179 struct mrq_debugfs_response resp; 180 struct tegra_bpmp_message msg = { 181 .mrq = MRQ_DEBUGFS, 182 .tx = { 183 .data = &req, 184 .size = sizeof(req), 185 }, 186 .rx = { 187 .data = &resp, 188 .size = sizeof(resp), 189 }, 190 }; 191 int err; 192 193 err = tegra_bpmp_transfer(bpmp, &msg); 194 if (err < 0) 195 return err; 196 197 *nbytes = (size_t)resp.dumpdir.nbytes; 198 199 return 0; 200 } 201 202 static int debugfs_show(struct seq_file *m, void *p) 203 { 204 struct file *file = m->private; 205 struct inode *inode = file_inode(file); 206 struct tegra_bpmp *bpmp = inode->i_private; 207 const size_t datasize = m->size; 208 const size_t namesize = SZ_256; 209 void *datavirt, *namevirt; 210 dma_addr_t dataphys, namephys; 211 char buf[256]; 212 const char *filename; 213 size_t len, nbytes; 214 int ret; 215 216 filename = get_filename(bpmp, file, buf, sizeof(buf)); 217 if (!filename) 218 return -ENOENT; 219 220 namevirt = dma_alloc_coherent(bpmp->dev, namesize, &namephys, 221 GFP_KERNEL | GFP_DMA32); 222 if (!namevirt) 223 return -ENOMEM; 224 225 datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys, 226 GFP_KERNEL | GFP_DMA32); 227 if (!datavirt) { 228 ret = -ENOMEM; 229 goto free_namebuf; 230 } 231 232 len = strlen(filename); 233 strncpy(namevirt, filename, namesize); 234 235 ret = mrq_debugfs_read(bpmp, namephys, len, dataphys, datasize, 236 &nbytes); 237 238 if (!ret) 239 seq_write(m, datavirt, nbytes); 240 241 dma_free_coherent(bpmp->dev, datasize, datavirt, dataphys); 242 free_namebuf: 243 dma_free_coherent(bpmp->dev, namesize, namevirt, namephys); 244 245 return ret; 246 } 247 248 static int debugfs_open(struct inode *inode, struct file *file) 249 { 250 return single_open_size(file, debugfs_show, file, SZ_128K); 251 } 252 253 static ssize_t debugfs_store(struct file *file, const char __user *buf, 254 size_t count, loff_t *f_pos) 255 { 256 struct inode *inode = file_inode(file); 257 struct tegra_bpmp *bpmp = inode->i_private; 258 const size_t datasize = count; 259 const size_t namesize = SZ_256; 260 void *datavirt, *namevirt; 261 dma_addr_t dataphys, namephys; 262 char fnamebuf[256]; 263 const char *filename; 264 size_t len; 265 int ret; 266 267 filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf)); 268 if (!filename) 269 return -ENOENT; 270 271 namevirt = dma_alloc_coherent(bpmp->dev, namesize, &namephys, 272 GFP_KERNEL | GFP_DMA32); 273 if (!namevirt) 274 return -ENOMEM; 275 276 datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys, 277 GFP_KERNEL | GFP_DMA32); 278 if (!datavirt) { 279 ret = -ENOMEM; 280 goto free_namebuf; 281 } 282 283 len = strlen(filename); 284 strncpy(namevirt, filename, namesize); 285 286 if (copy_from_user(datavirt, buf, count)) { 287 ret = -EFAULT; 288 goto free_databuf; 289 } 290 291 ret = mrq_debugfs_write(bpmp, namephys, len, dataphys, 292 count); 293 294 free_databuf: 295 dma_free_coherent(bpmp->dev, datasize, datavirt, dataphys); 296 free_namebuf: 297 dma_free_coherent(bpmp->dev, namesize, namevirt, namephys); 298 299 return ret ?: count; 300 } 301 302 static const struct file_operations debugfs_fops = { 303 .open = debugfs_open, 304 .read = seq_read, 305 .llseek = seq_lseek, 306 .write = debugfs_store, 307 .release = single_release, 308 }; 309 310 static int bpmp_populate_dir(struct tegra_bpmp *bpmp, struct seqbuf *seqbuf, 311 struct dentry *parent, uint32_t depth) 312 { 313 int err; 314 uint32_t d, t; 315 const char *name; 316 struct dentry *dentry; 317 318 while (!seqbuf_eof(seqbuf)) { 319 err = seqbuf_read_u32(seqbuf, &d); 320 if (err < 0) 321 return err; 322 323 if (d < depth) { 324 seqbuf_seek(seqbuf, -4); 325 /* go up a level */ 326 return 0; 327 } else if (d != depth) { 328 /* malformed data received from BPMP */ 329 return -EIO; 330 } 331 332 err = seqbuf_read_u32(seqbuf, &t); 333 if (err < 0) 334 return err; 335 err = seqbuf_read_str(seqbuf, &name); 336 if (err < 0) 337 return err; 338 339 if (t & DEBUGFS_S_ISDIR) { 340 dentry = debugfs_create_dir(name, parent); 341 if (!dentry) 342 return -ENOMEM; 343 err = bpmp_populate_dir(bpmp, seqbuf, dentry, depth+1); 344 if (err < 0) 345 return err; 346 } else { 347 umode_t mode; 348 349 mode = t & DEBUGFS_S_IRUSR ? S_IRUSR : 0; 350 mode |= t & DEBUGFS_S_IWUSR ? S_IWUSR : 0; 351 dentry = debugfs_create_file(name, mode, 352 parent, bpmp, 353 &debugfs_fops); 354 if (!dentry) 355 return -ENOMEM; 356 } 357 } 358 359 return 0; 360 } 361 362 static int create_debugfs_mirror(struct tegra_bpmp *bpmp, void *buf, 363 size_t bufsize, struct dentry *root) 364 { 365 struct seqbuf seqbuf; 366 int err; 367 368 bpmp->debugfs_mirror = debugfs_create_dir("debug", root); 369 if (!bpmp->debugfs_mirror) 370 return -ENOMEM; 371 372 seqbuf_init(&seqbuf, buf, bufsize); 373 err = bpmp_populate_dir(bpmp, &seqbuf, bpmp->debugfs_mirror, 0); 374 if (err < 0) { 375 debugfs_remove_recursive(bpmp->debugfs_mirror); 376 bpmp->debugfs_mirror = NULL; 377 } 378 379 return err; 380 } 381 382 int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp) 383 { 384 dma_addr_t phys; 385 void *virt; 386 const size_t sz = SZ_256K; 387 size_t nbytes; 388 int ret; 389 struct dentry *root; 390 391 if (!tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUGFS)) 392 return 0; 393 394 root = debugfs_create_dir("bpmp", NULL); 395 if (!root) 396 return -ENOMEM; 397 398 virt = dma_alloc_coherent(bpmp->dev, sz, &phys, 399 GFP_KERNEL | GFP_DMA32); 400 if (!virt) { 401 ret = -ENOMEM; 402 goto out; 403 } 404 405 ret = mrq_debugfs_dumpdir(bpmp, phys, sz, &nbytes); 406 if (ret < 0) 407 goto free; 408 409 ret = create_debugfs_mirror(bpmp, virt, nbytes, root); 410 free: 411 dma_free_coherent(bpmp->dev, sz, virt, phys); 412 out: 413 if (ret < 0) 414 debugfs_remove(root); 415 416 return ret; 417 } 418