| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * 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 | 4 | */ |
|---|
| 14 | 5 | #include <linux/debugfs.h> |
|---|
| 15 | 6 | #include <linux/dma-mapping.h> |
|---|
| 7 | +#include <linux/slab.h> |
|---|
| 16 | 8 | #include <linux/uaccess.h> |
|---|
| 17 | 9 | |
|---|
| 18 | 10 | #include <soc/tegra/bpmp.h> |
|---|
| 19 | 11 | #include <soc/tegra/bpmp-abi.h> |
|---|
| 12 | + |
|---|
| 13 | +static DEFINE_MUTEX(bpmp_debug_lock); |
|---|
| 20 | 14 | |
|---|
| 21 | 15 | struct seqbuf { |
|---|
| 22 | 16 | char *buf; |
|---|
| .. | .. |
|---|
| 80 | 74 | static const char *get_filename(struct tegra_bpmp *bpmp, |
|---|
| 81 | 75 | const struct file *file, char *buf, int size) |
|---|
| 82 | 76 | { |
|---|
| 83 | | - char root_path_buf[512]; |
|---|
| 84 | | - const char *root_path; |
|---|
| 85 | | - const char *filename; |
|---|
| 77 | + const char *root_path, *filename = NULL; |
|---|
| 78 | + char *root_path_buf; |
|---|
| 86 | 79 | size_t root_len; |
|---|
| 80 | + size_t root_path_buf_len = 512; |
|---|
| 81 | + |
|---|
| 82 | + root_path_buf = kzalloc(root_path_buf_len, GFP_KERNEL); |
|---|
| 83 | + if (!root_path_buf) |
|---|
| 84 | + goto out; |
|---|
| 87 | 85 | |
|---|
| 88 | 86 | root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf, |
|---|
| 89 | | - sizeof(root_path_buf)); |
|---|
| 87 | + root_path_buf_len); |
|---|
| 90 | 88 | if (IS_ERR(root_path)) |
|---|
| 91 | | - return NULL; |
|---|
| 89 | + goto out; |
|---|
| 92 | 90 | |
|---|
| 93 | 91 | root_len = strlen(root_path); |
|---|
| 94 | 92 | |
|---|
| 95 | 93 | filename = dentry_path(file->f_path.dentry, buf, size); |
|---|
| 96 | | - if (IS_ERR(filename)) |
|---|
| 97 | | - return NULL; |
|---|
| 94 | + if (IS_ERR(filename)) { |
|---|
| 95 | + filename = NULL; |
|---|
| 96 | + goto out; |
|---|
| 97 | + } |
|---|
| 98 | 98 | |
|---|
| 99 | | - if (strlen(filename) < root_len || |
|---|
| 100 | | - strncmp(filename, root_path, root_len)) |
|---|
| 101 | | - return NULL; |
|---|
| 99 | + if (strlen(filename) < root_len || strncmp(filename, root_path, root_len)) { |
|---|
| 100 | + filename = NULL; |
|---|
| 101 | + goto out; |
|---|
| 102 | + } |
|---|
| 102 | 103 | |
|---|
| 103 | 104 | filename += root_len; |
|---|
| 104 | 105 | |
|---|
| 106 | +out: |
|---|
| 107 | + kfree(root_path_buf); |
|---|
| 105 | 108 | return filename; |
|---|
| 109 | +} |
|---|
| 110 | + |
|---|
| 111 | +static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name, |
|---|
| 112 | + uint32_t *fd, uint32_t *len, bool write) |
|---|
| 113 | +{ |
|---|
| 114 | + struct mrq_debug_request req = { |
|---|
| 115 | + .cmd = cpu_to_le32(write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO), |
|---|
| 116 | + }; |
|---|
| 117 | + struct mrq_debug_response resp; |
|---|
| 118 | + struct tegra_bpmp_message msg = { |
|---|
| 119 | + .mrq = MRQ_DEBUG, |
|---|
| 120 | + .tx = { |
|---|
| 121 | + .data = &req, |
|---|
| 122 | + .size = sizeof(req), |
|---|
| 123 | + }, |
|---|
| 124 | + .rx = { |
|---|
| 125 | + .data = &resp, |
|---|
| 126 | + .size = sizeof(resp), |
|---|
| 127 | + }, |
|---|
| 128 | + }; |
|---|
| 129 | + ssize_t sz_name; |
|---|
| 130 | + int err = 0; |
|---|
| 131 | + |
|---|
| 132 | + sz_name = strscpy(req.fop.name, name, sizeof(req.fop.name)); |
|---|
| 133 | + if (sz_name < 0) { |
|---|
| 134 | + pr_err("File name too large: %s\n", name); |
|---|
| 135 | + return -EINVAL; |
|---|
| 136 | + } |
|---|
| 137 | + |
|---|
| 138 | + err = tegra_bpmp_transfer(bpmp, &msg); |
|---|
| 139 | + if (err < 0) |
|---|
| 140 | + return err; |
|---|
| 141 | + else if (msg.rx.ret < 0) |
|---|
| 142 | + return -EINVAL; |
|---|
| 143 | + |
|---|
| 144 | + *len = resp.fop.datalen; |
|---|
| 145 | + *fd = resp.fop.fd; |
|---|
| 146 | + |
|---|
| 147 | + return 0; |
|---|
| 148 | +} |
|---|
| 149 | + |
|---|
| 150 | +static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd) |
|---|
| 151 | +{ |
|---|
| 152 | + struct mrq_debug_request req = { |
|---|
| 153 | + .cmd = cpu_to_le32(CMD_DEBUG_CLOSE), |
|---|
| 154 | + .frd = { |
|---|
| 155 | + .fd = fd, |
|---|
| 156 | + }, |
|---|
| 157 | + }; |
|---|
| 158 | + struct mrq_debug_response resp; |
|---|
| 159 | + struct tegra_bpmp_message msg = { |
|---|
| 160 | + .mrq = MRQ_DEBUG, |
|---|
| 161 | + .tx = { |
|---|
| 162 | + .data = &req, |
|---|
| 163 | + .size = sizeof(req), |
|---|
| 164 | + }, |
|---|
| 165 | + .rx = { |
|---|
| 166 | + .data = &resp, |
|---|
| 167 | + .size = sizeof(resp), |
|---|
| 168 | + }, |
|---|
| 169 | + }; |
|---|
| 170 | + int err = 0; |
|---|
| 171 | + |
|---|
| 172 | + err = tegra_bpmp_transfer(bpmp, &msg); |
|---|
| 173 | + if (err < 0) |
|---|
| 174 | + return err; |
|---|
| 175 | + else if (msg.rx.ret < 0) |
|---|
| 176 | + return -EINVAL; |
|---|
| 177 | + |
|---|
| 178 | + return 0; |
|---|
| 179 | +} |
|---|
| 180 | + |
|---|
| 181 | +static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name, |
|---|
| 182 | + char *data, size_t sz_data, uint32_t *nbytes) |
|---|
| 183 | +{ |
|---|
| 184 | + struct mrq_debug_request req = { |
|---|
| 185 | + .cmd = cpu_to_le32(CMD_DEBUG_READ), |
|---|
| 186 | + }; |
|---|
| 187 | + struct mrq_debug_response resp; |
|---|
| 188 | + struct tegra_bpmp_message msg = { |
|---|
| 189 | + .mrq = MRQ_DEBUG, |
|---|
| 190 | + .tx = { |
|---|
| 191 | + .data = &req, |
|---|
| 192 | + .size = sizeof(req), |
|---|
| 193 | + }, |
|---|
| 194 | + .rx = { |
|---|
| 195 | + .data = &resp, |
|---|
| 196 | + .size = sizeof(resp), |
|---|
| 197 | + }, |
|---|
| 198 | + }; |
|---|
| 199 | + uint32_t fd = 0, len = 0; |
|---|
| 200 | + int remaining, err; |
|---|
| 201 | + |
|---|
| 202 | + mutex_lock(&bpmp_debug_lock); |
|---|
| 203 | + err = mrq_debug_open(bpmp, name, &fd, &len, 0); |
|---|
| 204 | + if (err) |
|---|
| 205 | + goto out; |
|---|
| 206 | + |
|---|
| 207 | + if (len > sz_data) { |
|---|
| 208 | + err = -EFBIG; |
|---|
| 209 | + goto close; |
|---|
| 210 | + } |
|---|
| 211 | + |
|---|
| 212 | + req.frd.fd = fd; |
|---|
| 213 | + remaining = len; |
|---|
| 214 | + |
|---|
| 215 | + while (remaining > 0) { |
|---|
| 216 | + err = tegra_bpmp_transfer(bpmp, &msg); |
|---|
| 217 | + if (err < 0) { |
|---|
| 218 | + goto close; |
|---|
| 219 | + } else if (msg.rx.ret < 0) { |
|---|
| 220 | + err = -EINVAL; |
|---|
| 221 | + goto close; |
|---|
| 222 | + } |
|---|
| 223 | + |
|---|
| 224 | + if (resp.frd.readlen > remaining) { |
|---|
| 225 | + pr_err("%s: read data length invalid\n", __func__); |
|---|
| 226 | + err = -EINVAL; |
|---|
| 227 | + goto close; |
|---|
| 228 | + } |
|---|
| 229 | + |
|---|
| 230 | + memcpy(data, resp.frd.data, resp.frd.readlen); |
|---|
| 231 | + data += resp.frd.readlen; |
|---|
| 232 | + remaining -= resp.frd.readlen; |
|---|
| 233 | + } |
|---|
| 234 | + |
|---|
| 235 | + *nbytes = len; |
|---|
| 236 | + |
|---|
| 237 | +close: |
|---|
| 238 | + err = mrq_debug_close(bpmp, fd); |
|---|
| 239 | +out: |
|---|
| 240 | + mutex_unlock(&bpmp_debug_lock); |
|---|
| 241 | + return err; |
|---|
| 242 | +} |
|---|
| 243 | + |
|---|
| 244 | +static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name, |
|---|
| 245 | + uint8_t *data, size_t sz_data) |
|---|
| 246 | +{ |
|---|
| 247 | + struct mrq_debug_request req = { |
|---|
| 248 | + .cmd = cpu_to_le32(CMD_DEBUG_WRITE) |
|---|
| 249 | + }; |
|---|
| 250 | + struct mrq_debug_response resp; |
|---|
| 251 | + struct tegra_bpmp_message msg = { |
|---|
| 252 | + .mrq = MRQ_DEBUG, |
|---|
| 253 | + .tx = { |
|---|
| 254 | + .data = &req, |
|---|
| 255 | + .size = sizeof(req), |
|---|
| 256 | + }, |
|---|
| 257 | + .rx = { |
|---|
| 258 | + .data = &resp, |
|---|
| 259 | + .size = sizeof(resp), |
|---|
| 260 | + }, |
|---|
| 261 | + }; |
|---|
| 262 | + uint32_t fd = 0, len = 0; |
|---|
| 263 | + size_t remaining; |
|---|
| 264 | + int err; |
|---|
| 265 | + |
|---|
| 266 | + mutex_lock(&bpmp_debug_lock); |
|---|
| 267 | + err = mrq_debug_open(bpmp, name, &fd, &len, 1); |
|---|
| 268 | + if (err) |
|---|
| 269 | + goto out; |
|---|
| 270 | + |
|---|
| 271 | + if (sz_data > len) { |
|---|
| 272 | + err = -EINVAL; |
|---|
| 273 | + goto close; |
|---|
| 274 | + } |
|---|
| 275 | + |
|---|
| 276 | + req.fwr.fd = fd; |
|---|
| 277 | + remaining = sz_data; |
|---|
| 278 | + |
|---|
| 279 | + while (remaining > 0) { |
|---|
| 280 | + len = min(remaining, sizeof(req.fwr.data)); |
|---|
| 281 | + memcpy(req.fwr.data, data, len); |
|---|
| 282 | + req.fwr.datalen = len; |
|---|
| 283 | + |
|---|
| 284 | + err = tegra_bpmp_transfer(bpmp, &msg); |
|---|
| 285 | + if (err < 0) { |
|---|
| 286 | + goto close; |
|---|
| 287 | + } else if (msg.rx.ret < 0) { |
|---|
| 288 | + err = -EINVAL; |
|---|
| 289 | + goto close; |
|---|
| 290 | + } |
|---|
| 291 | + |
|---|
| 292 | + data += req.fwr.datalen; |
|---|
| 293 | + remaining -= req.fwr.datalen; |
|---|
| 294 | + } |
|---|
| 295 | + |
|---|
| 296 | +close: |
|---|
| 297 | + err = mrq_debug_close(bpmp, fd); |
|---|
| 298 | +out: |
|---|
| 299 | + mutex_unlock(&bpmp_debug_lock); |
|---|
| 300 | + return err; |
|---|
| 301 | +} |
|---|
| 302 | + |
|---|
| 303 | +static int bpmp_debug_show(struct seq_file *m, void *p) |
|---|
| 304 | +{ |
|---|
| 305 | + struct file *file = m->private; |
|---|
| 306 | + struct inode *inode = file_inode(file); |
|---|
| 307 | + struct tegra_bpmp *bpmp = inode->i_private; |
|---|
| 308 | + char *databuf = NULL; |
|---|
| 309 | + char fnamebuf[256]; |
|---|
| 310 | + const char *filename; |
|---|
| 311 | + uint32_t nbytes = 0; |
|---|
| 312 | + size_t len; |
|---|
| 313 | + int err; |
|---|
| 314 | + |
|---|
| 315 | + len = seq_get_buf(m, &databuf); |
|---|
| 316 | + if (!databuf) |
|---|
| 317 | + return -ENOMEM; |
|---|
| 318 | + |
|---|
| 319 | + filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf)); |
|---|
| 320 | + if (!filename) |
|---|
| 321 | + return -ENOENT; |
|---|
| 322 | + |
|---|
| 323 | + err = mrq_debug_read(bpmp, filename, databuf, len, &nbytes); |
|---|
| 324 | + if (!err) |
|---|
| 325 | + seq_commit(m, nbytes); |
|---|
| 326 | + |
|---|
| 327 | + return err; |
|---|
| 328 | +} |
|---|
| 329 | + |
|---|
| 330 | +static ssize_t bpmp_debug_store(struct file *file, const char __user *buf, |
|---|
| 331 | + size_t count, loff_t *f_pos) |
|---|
| 332 | +{ |
|---|
| 333 | + struct inode *inode = file_inode(file); |
|---|
| 334 | + struct tegra_bpmp *bpmp = inode->i_private; |
|---|
| 335 | + char *databuf = NULL; |
|---|
| 336 | + char fnamebuf[256]; |
|---|
| 337 | + const char *filename; |
|---|
| 338 | + ssize_t err; |
|---|
| 339 | + |
|---|
| 340 | + filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf)); |
|---|
| 341 | + if (!filename) |
|---|
| 342 | + return -ENOENT; |
|---|
| 343 | + |
|---|
| 344 | + databuf = kmalloc(count, GFP_KERNEL); |
|---|
| 345 | + if (!databuf) |
|---|
| 346 | + return -ENOMEM; |
|---|
| 347 | + |
|---|
| 348 | + if (copy_from_user(databuf, buf, count)) { |
|---|
| 349 | + err = -EFAULT; |
|---|
| 350 | + goto free_ret; |
|---|
| 351 | + } |
|---|
| 352 | + |
|---|
| 353 | + err = mrq_debug_write(bpmp, filename, databuf, count); |
|---|
| 354 | + |
|---|
| 355 | +free_ret: |
|---|
| 356 | + kfree(databuf); |
|---|
| 357 | + |
|---|
| 358 | + return err ?: count; |
|---|
| 359 | +} |
|---|
| 360 | + |
|---|
| 361 | +static int bpmp_debug_open(struct inode *inode, struct file *file) |
|---|
| 362 | +{ |
|---|
| 363 | + return single_open_size(file, bpmp_debug_show, file, SZ_256K); |
|---|
| 364 | +} |
|---|
| 365 | + |
|---|
| 366 | +static const struct file_operations bpmp_debug_fops = { |
|---|
| 367 | + .open = bpmp_debug_open, |
|---|
| 368 | + .read = seq_read, |
|---|
| 369 | + .llseek = seq_lseek, |
|---|
| 370 | + .write = bpmp_debug_store, |
|---|
| 371 | + .release = single_release, |
|---|
| 372 | +}; |
|---|
| 373 | + |
|---|
| 374 | +static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp, |
|---|
| 375 | + struct dentry *parent, |
|---|
| 376 | + char *ppath) |
|---|
| 377 | +{ |
|---|
| 378 | + const size_t pathlen = SZ_256; |
|---|
| 379 | + const size_t bufsize = SZ_16K; |
|---|
| 380 | + uint32_t dsize, attrs = 0; |
|---|
| 381 | + struct dentry *dentry; |
|---|
| 382 | + struct seqbuf seqbuf; |
|---|
| 383 | + char *buf, *pathbuf; |
|---|
| 384 | + const char *name; |
|---|
| 385 | + int err = 0; |
|---|
| 386 | + |
|---|
| 387 | + if (!bpmp || !parent || !ppath) |
|---|
| 388 | + return -EINVAL; |
|---|
| 389 | + |
|---|
| 390 | + buf = kmalloc(bufsize, GFP_KERNEL); |
|---|
| 391 | + if (!buf) |
|---|
| 392 | + return -ENOMEM; |
|---|
| 393 | + |
|---|
| 394 | + pathbuf = kzalloc(pathlen, GFP_KERNEL); |
|---|
| 395 | + if (!pathbuf) { |
|---|
| 396 | + kfree(buf); |
|---|
| 397 | + return -ENOMEM; |
|---|
| 398 | + } |
|---|
| 399 | + |
|---|
| 400 | + err = mrq_debug_read(bpmp, ppath, buf, bufsize, &dsize); |
|---|
| 401 | + if (err) |
|---|
| 402 | + goto out; |
|---|
| 403 | + |
|---|
| 404 | + seqbuf_init(&seqbuf, buf, dsize); |
|---|
| 405 | + |
|---|
| 406 | + while (!seqbuf_eof(&seqbuf)) { |
|---|
| 407 | + err = seqbuf_read_u32(&seqbuf, &attrs); |
|---|
| 408 | + if (err) |
|---|
| 409 | + goto out; |
|---|
| 410 | + |
|---|
| 411 | + err = seqbuf_read_str(&seqbuf, &name); |
|---|
| 412 | + if (err < 0) |
|---|
| 413 | + goto out; |
|---|
| 414 | + |
|---|
| 415 | + if (attrs & DEBUGFS_S_ISDIR) { |
|---|
| 416 | + size_t len; |
|---|
| 417 | + |
|---|
| 418 | + dentry = debugfs_create_dir(name, parent); |
|---|
| 419 | + if (IS_ERR(dentry)) { |
|---|
| 420 | + err = PTR_ERR(dentry); |
|---|
| 421 | + goto out; |
|---|
| 422 | + } |
|---|
| 423 | + |
|---|
| 424 | + len = snprintf(pathbuf, pathlen, "%s%s/", ppath, name); |
|---|
| 425 | + if (len >= pathlen) { |
|---|
| 426 | + err = -EINVAL; |
|---|
| 427 | + goto out; |
|---|
| 428 | + } |
|---|
| 429 | + |
|---|
| 430 | + err = bpmp_populate_debugfs_inband(bpmp, dentry, |
|---|
| 431 | + pathbuf); |
|---|
| 432 | + if (err < 0) |
|---|
| 433 | + goto out; |
|---|
| 434 | + } else { |
|---|
| 435 | + umode_t mode; |
|---|
| 436 | + |
|---|
| 437 | + mode = attrs & DEBUGFS_S_IRUSR ? 0400 : 0; |
|---|
| 438 | + mode |= attrs & DEBUGFS_S_IWUSR ? 0200 : 0; |
|---|
| 439 | + dentry = debugfs_create_file(name, mode, parent, bpmp, |
|---|
| 440 | + &bpmp_debug_fops); |
|---|
| 441 | + if (IS_ERR(dentry)) { |
|---|
| 442 | + err = -ENOMEM; |
|---|
| 443 | + goto out; |
|---|
| 444 | + } |
|---|
| 445 | + } |
|---|
| 446 | + } |
|---|
| 447 | + |
|---|
| 448 | +out: |
|---|
| 449 | + kfree(pathbuf); |
|---|
| 450 | + kfree(buf); |
|---|
| 451 | + |
|---|
| 452 | + return err; |
|---|
| 106 | 453 | } |
|---|
| 107 | 454 | |
|---|
| 108 | 455 | static int mrq_debugfs_read(struct tegra_bpmp *bpmp, |
|---|
| .. | .. |
|---|
| 136 | 483 | err = tegra_bpmp_transfer(bpmp, &msg); |
|---|
| 137 | 484 | if (err < 0) |
|---|
| 138 | 485 | return err; |
|---|
| 486 | + else if (msg.rx.ret < 0) |
|---|
| 487 | + return -EINVAL; |
|---|
| 139 | 488 | |
|---|
| 140 | 489 | *nbytes = (size_t)resp.fop.nbytes; |
|---|
| 141 | 490 | |
|---|
| .. | .. |
|---|
| 193 | 542 | err = tegra_bpmp_transfer(bpmp, &msg); |
|---|
| 194 | 543 | if (err < 0) |
|---|
| 195 | 544 | return err; |
|---|
| 545 | + else if (msg.rx.ret < 0) |
|---|
| 546 | + return -EINVAL; |
|---|
| 196 | 547 | |
|---|
| 197 | 548 | *nbytes = (size_t)resp.dumpdir.nbytes; |
|---|
| 198 | 549 | |
|---|
| .. | .. |
|---|
| 211 | 562 | char buf[256]; |
|---|
| 212 | 563 | const char *filename; |
|---|
| 213 | 564 | size_t len, nbytes; |
|---|
| 214 | | - int ret; |
|---|
| 565 | + int err; |
|---|
| 215 | 566 | |
|---|
| 216 | 567 | filename = get_filename(bpmp, file, buf, sizeof(buf)); |
|---|
| 217 | 568 | if (!filename) |
|---|
| .. | .. |
|---|
| 225 | 576 | datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys, |
|---|
| 226 | 577 | GFP_KERNEL | GFP_DMA32); |
|---|
| 227 | 578 | if (!datavirt) { |
|---|
| 228 | | - ret = -ENOMEM; |
|---|
| 579 | + err = -ENOMEM; |
|---|
| 229 | 580 | goto free_namebuf; |
|---|
| 230 | 581 | } |
|---|
| 231 | 582 | |
|---|
| 232 | 583 | len = strlen(filename); |
|---|
| 233 | 584 | strncpy(namevirt, filename, namesize); |
|---|
| 234 | 585 | |
|---|
| 235 | | - ret = mrq_debugfs_read(bpmp, namephys, len, dataphys, datasize, |
|---|
| 586 | + err = mrq_debugfs_read(bpmp, namephys, len, dataphys, datasize, |
|---|
| 236 | 587 | &nbytes); |
|---|
| 237 | 588 | |
|---|
| 238 | | - if (!ret) |
|---|
| 589 | + if (!err) |
|---|
| 239 | 590 | seq_write(m, datavirt, nbytes); |
|---|
| 240 | 591 | |
|---|
| 241 | 592 | dma_free_coherent(bpmp->dev, datasize, datavirt, dataphys); |
|---|
| 242 | 593 | free_namebuf: |
|---|
| 243 | 594 | dma_free_coherent(bpmp->dev, namesize, namevirt, namephys); |
|---|
| 244 | 595 | |
|---|
| 245 | | - return ret; |
|---|
| 596 | + return err; |
|---|
| 246 | 597 | } |
|---|
| 247 | 598 | |
|---|
| 248 | 599 | static int debugfs_open(struct inode *inode, struct file *file) |
|---|
| .. | .. |
|---|
| 262 | 613 | char fnamebuf[256]; |
|---|
| 263 | 614 | const char *filename; |
|---|
| 264 | 615 | size_t len; |
|---|
| 265 | | - int ret; |
|---|
| 616 | + int err; |
|---|
| 266 | 617 | |
|---|
| 267 | 618 | filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf)); |
|---|
| 268 | 619 | if (!filename) |
|---|
| .. | .. |
|---|
| 276 | 627 | datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys, |
|---|
| 277 | 628 | GFP_KERNEL | GFP_DMA32); |
|---|
| 278 | 629 | if (!datavirt) { |
|---|
| 279 | | - ret = -ENOMEM; |
|---|
| 630 | + err = -ENOMEM; |
|---|
| 280 | 631 | goto free_namebuf; |
|---|
| 281 | 632 | } |
|---|
| 282 | 633 | |
|---|
| .. | .. |
|---|
| 284 | 635 | strncpy(namevirt, filename, namesize); |
|---|
| 285 | 636 | |
|---|
| 286 | 637 | if (copy_from_user(datavirt, buf, count)) { |
|---|
| 287 | | - ret = -EFAULT; |
|---|
| 638 | + err = -EFAULT; |
|---|
| 288 | 639 | goto free_databuf; |
|---|
| 289 | 640 | } |
|---|
| 290 | 641 | |
|---|
| 291 | | - ret = mrq_debugfs_write(bpmp, namephys, len, dataphys, |
|---|
| 642 | + err = mrq_debugfs_write(bpmp, namephys, len, dataphys, |
|---|
| 292 | 643 | count); |
|---|
| 293 | 644 | |
|---|
| 294 | 645 | free_databuf: |
|---|
| .. | .. |
|---|
| 296 | 647 | free_namebuf: |
|---|
| 297 | 648 | dma_free_coherent(bpmp->dev, namesize, namevirt, namephys); |
|---|
| 298 | 649 | |
|---|
| 299 | | - return ret ?: count; |
|---|
| 650 | + return err ?: count; |
|---|
| 300 | 651 | } |
|---|
| 301 | 652 | |
|---|
| 302 | 653 | static const struct file_operations debugfs_fops = { |
|---|
| .. | .. |
|---|
| 338 | 689 | |
|---|
| 339 | 690 | if (t & DEBUGFS_S_ISDIR) { |
|---|
| 340 | 691 | dentry = debugfs_create_dir(name, parent); |
|---|
| 341 | | - if (!dentry) |
|---|
| 692 | + if (IS_ERR(dentry)) |
|---|
| 342 | 693 | return -ENOMEM; |
|---|
| 343 | 694 | err = bpmp_populate_dir(bpmp, seqbuf, dentry, depth+1); |
|---|
| 344 | 695 | if (err < 0) |
|---|
| .. | .. |
|---|
| 351 | 702 | dentry = debugfs_create_file(name, mode, |
|---|
| 352 | 703 | parent, bpmp, |
|---|
| 353 | 704 | &debugfs_fops); |
|---|
| 354 | | - if (!dentry) |
|---|
| 705 | + if (IS_ERR(dentry)) |
|---|
| 355 | 706 | return -ENOMEM; |
|---|
| 356 | 707 | } |
|---|
| 357 | 708 | } |
|---|
| .. | .. |
|---|
| 359 | 710 | return 0; |
|---|
| 360 | 711 | } |
|---|
| 361 | 712 | |
|---|
| 362 | | -static int create_debugfs_mirror(struct tegra_bpmp *bpmp, void *buf, |
|---|
| 363 | | - size_t bufsize, struct dentry *root) |
|---|
| 713 | +static int bpmp_populate_debugfs_shmem(struct tegra_bpmp *bpmp) |
|---|
| 364 | 714 | { |
|---|
| 365 | 715 | struct seqbuf seqbuf; |
|---|
| 716 | + const size_t sz = SZ_512K; |
|---|
| 717 | + dma_addr_t phys; |
|---|
| 718 | + size_t nbytes; |
|---|
| 719 | + void *virt; |
|---|
| 366 | 720 | int err; |
|---|
| 367 | 721 | |
|---|
| 368 | | - bpmp->debugfs_mirror = debugfs_create_dir("debug", root); |
|---|
| 369 | | - if (!bpmp->debugfs_mirror) |
|---|
| 722 | + virt = dma_alloc_coherent(bpmp->dev, sz, &phys, |
|---|
| 723 | + GFP_KERNEL | GFP_DMA32); |
|---|
| 724 | + if (!virt) |
|---|
| 370 | 725 | return -ENOMEM; |
|---|
| 371 | 726 | |
|---|
| 372 | | - seqbuf_init(&seqbuf, buf, bufsize); |
|---|
| 373 | | - err = bpmp_populate_dir(bpmp, &seqbuf, bpmp->debugfs_mirror, 0); |
|---|
| 727 | + err = mrq_debugfs_dumpdir(bpmp, phys, sz, &nbytes); |
|---|
| 374 | 728 | if (err < 0) { |
|---|
| 375 | | - debugfs_remove_recursive(bpmp->debugfs_mirror); |
|---|
| 376 | | - bpmp->debugfs_mirror = NULL; |
|---|
| 729 | + goto free; |
|---|
| 730 | + } else if (nbytes > sz) { |
|---|
| 731 | + err = -EINVAL; |
|---|
| 732 | + goto free; |
|---|
| 377 | 733 | } |
|---|
| 734 | + |
|---|
| 735 | + seqbuf_init(&seqbuf, virt, nbytes); |
|---|
| 736 | + err = bpmp_populate_dir(bpmp, &seqbuf, bpmp->debugfs_mirror, 0); |
|---|
| 737 | +free: |
|---|
| 738 | + dma_free_coherent(bpmp->dev, sz, virt, phys); |
|---|
| 378 | 739 | |
|---|
| 379 | 740 | return err; |
|---|
| 380 | 741 | } |
|---|
| 381 | 742 | |
|---|
| 382 | | -static int mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq) |
|---|
| 383 | | -{ |
|---|
| 384 | | - struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) }; |
|---|
| 385 | | - struct mrq_query_abi_response resp; |
|---|
| 386 | | - struct tegra_bpmp_message msg = { |
|---|
| 387 | | - .mrq = MRQ_QUERY_ABI, |
|---|
| 388 | | - .tx = { |
|---|
| 389 | | - .data = &req, |
|---|
| 390 | | - .size = sizeof(req), |
|---|
| 391 | | - }, |
|---|
| 392 | | - .rx = { |
|---|
| 393 | | - .data = &resp, |
|---|
| 394 | | - .size = sizeof(resp), |
|---|
| 395 | | - }, |
|---|
| 396 | | - }; |
|---|
| 397 | | - int ret; |
|---|
| 398 | | - |
|---|
| 399 | | - ret = tegra_bpmp_transfer(bpmp, &msg); |
|---|
| 400 | | - if (ret < 0) { |
|---|
| 401 | | - /* something went wrong; assume not supported */ |
|---|
| 402 | | - dev_warn(bpmp->dev, "tegra_bpmp_transfer failed (%d)\n", ret); |
|---|
| 403 | | - return 0; |
|---|
| 404 | | - } |
|---|
| 405 | | - |
|---|
| 406 | | - return resp.status ? 0 : 1; |
|---|
| 407 | | -} |
|---|
| 408 | | - |
|---|
| 409 | 743 | int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp) |
|---|
| 410 | 744 | { |
|---|
| 411 | | - dma_addr_t phys; |
|---|
| 412 | | - void *virt; |
|---|
| 413 | | - const size_t sz = SZ_256K; |
|---|
| 414 | | - size_t nbytes; |
|---|
| 415 | | - int ret; |
|---|
| 416 | 745 | struct dentry *root; |
|---|
| 746 | + bool inband; |
|---|
| 747 | + int err; |
|---|
| 417 | 748 | |
|---|
| 418 | | - if (!mrq_is_supported(bpmp, MRQ_DEBUGFS)) |
|---|
| 749 | + inband = tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUG); |
|---|
| 750 | + |
|---|
| 751 | + if (!inband && !tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUGFS)) |
|---|
| 419 | 752 | return 0; |
|---|
| 420 | 753 | |
|---|
| 421 | 754 | root = debugfs_create_dir("bpmp", NULL); |
|---|
| 422 | | - if (!root) |
|---|
| 755 | + if (IS_ERR(root)) |
|---|
| 423 | 756 | return -ENOMEM; |
|---|
| 424 | 757 | |
|---|
| 425 | | - virt = dma_alloc_coherent(bpmp->dev, sz, &phys, |
|---|
| 426 | | - GFP_KERNEL | GFP_DMA32); |
|---|
| 427 | | - if (!virt) { |
|---|
| 428 | | - ret = -ENOMEM; |
|---|
| 758 | + bpmp->debugfs_mirror = debugfs_create_dir("debug", root); |
|---|
| 759 | + if (IS_ERR(bpmp->debugfs_mirror)) { |
|---|
| 760 | + err = -ENOMEM; |
|---|
| 429 | 761 | goto out; |
|---|
| 430 | 762 | } |
|---|
| 431 | 763 | |
|---|
| 432 | | - ret = mrq_debugfs_dumpdir(bpmp, phys, sz, &nbytes); |
|---|
| 433 | | - if (ret < 0) |
|---|
| 434 | | - goto free; |
|---|
| 764 | + if (inband) |
|---|
| 765 | + err = bpmp_populate_debugfs_inband(bpmp, bpmp->debugfs_mirror, |
|---|
| 766 | + "/"); |
|---|
| 767 | + else |
|---|
| 768 | + err = bpmp_populate_debugfs_shmem(bpmp); |
|---|
| 435 | 769 | |
|---|
| 436 | | - ret = create_debugfs_mirror(bpmp, virt, nbytes, root); |
|---|
| 437 | | -free: |
|---|
| 438 | | - dma_free_coherent(bpmp->dev, sz, virt, phys); |
|---|
| 439 | 770 | out: |
|---|
| 440 | | - if (ret < 0) |
|---|
| 441 | | - debugfs_remove(root); |
|---|
| 771 | + if (err < 0) |
|---|
| 772 | + debugfs_remove_recursive(root); |
|---|
| 442 | 773 | |
|---|
| 443 | | - return ret; |
|---|
| 774 | + return err; |
|---|
| 444 | 775 | } |
|---|