diff options
author | Arnd Bergmann <arnd@arndb.de> | 2017-11-02 11:14:18 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2017-11-02 11:14:18 -0400 |
commit | 097924c67798164dbbb2b856b171b5257343ac4b (patch) | |
tree | 1373176989760ec441940b83ee8d1c6e13293adb /drivers/firmware | |
parent | 1c6788e8746d5250ad9bd16e1e48140a396f4733 (diff) | |
parent | f2381f652266fabfb7a8f5c4b2a05de36cad3a73 (diff) |
Merge tag 'tegra-for-4.15-firmware' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/drivers
Pull "firmware: tegra: Changes for v4.15-rc1" from Thierry Reding:
This contains a couple of (non-critical) fixes and improvements for the
BPMP driver as well as support for debugfs.
* tag 'tegra-for-4.15-firmware' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
firmware: tegra: Add BPMP debugfs support
firmware: tegra: Add stubs when BPMP not enabled
firmware: tegra: Expose tegra_bpmp_mrq_return()
firmware: tegra: Propagate error code to caller
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/tegra/Makefile | 4 | ||||
-rw-r--r-- | drivers/firmware/tegra/bpmp-debugfs.c | 444 | ||||
-rw-r--r-- | drivers/firmware/tegra/bpmp.c | 31 |
3 files changed, 470 insertions, 9 deletions
diff --git a/drivers/firmware/tegra/Makefile b/drivers/firmware/tegra/Makefile index e34a2f79e1ad..1b826dcca719 100644 --- a/drivers/firmware/tegra/Makefile +++ b/drivers/firmware/tegra/Makefile | |||
@@ -1,2 +1,4 @@ | |||
1 | obj-$(CONFIG_TEGRA_BPMP) += bpmp.o | 1 | tegra-bpmp-y = bpmp.o |
2 | tegra-bpmp-$(CONFIG_DEBUG_FS) += bpmp-debugfs.o | ||
3 | obj-$(CONFIG_TEGRA_BPMP) += tegra-bpmp.o | ||
2 | obj-$(CONFIG_TEGRA_IVC) += ivc.o | 4 | obj-$(CONFIG_TEGRA_IVC) += ivc.o |
diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c new file mode 100644 index 000000000000..f7f6a0a5cb07 --- /dev/null +++ b/drivers/firmware/tegra/bpmp-debugfs.c | |||
@@ -0,0 +1,444 @@ | |||
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 | 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 | int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp) | ||
410 | { | ||
411 | dma_addr_t phys; | ||
412 | void *virt; | ||
413 | const size_t sz = SZ_256K; | ||
414 | size_t nbytes; | ||
415 | int ret; | ||
416 | struct dentry *root; | ||
417 | |||
418 | if (!mrq_is_supported(bpmp, MRQ_DEBUGFS)) | ||
419 | return 0; | ||
420 | |||
421 | root = debugfs_create_dir("bpmp", NULL); | ||
422 | if (!root) | ||
423 | return -ENOMEM; | ||
424 | |||
425 | virt = dma_alloc_coherent(bpmp->dev, sz, &phys, | ||
426 | GFP_KERNEL | GFP_DMA32); | ||
427 | if (!virt) { | ||
428 | ret = -ENOMEM; | ||
429 | goto out; | ||
430 | } | ||
431 | |||
432 | ret = mrq_debugfs_dumpdir(bpmp, phys, sz, &nbytes); | ||
433 | if (ret < 0) | ||
434 | goto free; | ||
435 | |||
436 | ret = create_debugfs_mirror(bpmp, virt, nbytes, root); | ||
437 | free: | ||
438 | dma_free_coherent(bpmp->dev, sz, virt, phys); | ||
439 | out: | ||
440 | if (ret < 0) | ||
441 | debugfs_remove(root); | ||
442 | |||
443 | return ret; | ||
444 | } | ||
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 73ca55b7b7ec..a7f461f2e650 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c | |||
@@ -194,16 +194,24 @@ static int tegra_bpmp_wait_master_free(struct tegra_bpmp_channel *channel) | |||
194 | } | 194 | } |
195 | 195 | ||
196 | static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel, | 196 | static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel, |
197 | void *data, size_t size) | 197 | void *data, size_t size, int *ret) |
198 | { | 198 | { |
199 | int err; | ||
200 | |||
199 | if (data && size > 0) | 201 | if (data && size > 0) |
200 | memcpy(data, channel->ib->data, size); | 202 | memcpy(data, channel->ib->data, size); |
201 | 203 | ||
202 | return tegra_ivc_read_advance(channel->ivc); | 204 | err = tegra_ivc_read_advance(channel->ivc); |
205 | if (err < 0) | ||
206 | return err; | ||
207 | |||
208 | *ret = channel->ib->code; | ||
209 | |||
210 | return 0; | ||
203 | } | 211 | } |
204 | 212 | ||
205 | static ssize_t tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel, | 213 | static ssize_t tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel, |
206 | void *data, size_t size) | 214 | void *data, size_t size, int *ret) |
207 | { | 215 | { |
208 | struct tegra_bpmp *bpmp = channel->bpmp; | 216 | struct tegra_bpmp *bpmp = channel->bpmp; |
209 | unsigned long flags; | 217 | unsigned long flags; |
@@ -217,7 +225,7 @@ static ssize_t tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel, | |||
217 | } | 225 | } |
218 | 226 | ||
219 | spin_lock_irqsave(&bpmp->lock, flags); | 227 | spin_lock_irqsave(&bpmp->lock, flags); |
220 | err = __tegra_bpmp_channel_read(channel, data, size); | 228 | err = __tegra_bpmp_channel_read(channel, data, size, ret); |
221 | clear_bit(index, bpmp->threaded.allocated); | 229 | clear_bit(index, bpmp->threaded.allocated); |
222 | spin_unlock_irqrestore(&bpmp->lock, flags); | 230 | spin_unlock_irqrestore(&bpmp->lock, flags); |
223 | 231 | ||
@@ -337,7 +345,8 @@ int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, | |||
337 | if (err < 0) | 345 | if (err < 0) |
338 | return err; | 346 | return err; |
339 | 347 | ||
340 | return __tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size); | 348 | return __tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size, |
349 | &msg->rx.ret); | ||
341 | } | 350 | } |
342 | EXPORT_SYMBOL_GPL(tegra_bpmp_transfer_atomic); | 351 | EXPORT_SYMBOL_GPL(tegra_bpmp_transfer_atomic); |
343 | 352 | ||
@@ -371,7 +380,8 @@ int tegra_bpmp_transfer(struct tegra_bpmp *bpmp, | |||
371 | if (err == 0) | 380 | if (err == 0) |
372 | return -ETIMEDOUT; | 381 | return -ETIMEDOUT; |
373 | 382 | ||
374 | return tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size); | 383 | return tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size, |
384 | &msg->rx.ret); | ||
375 | } | 385 | } |
376 | EXPORT_SYMBOL_GPL(tegra_bpmp_transfer); | 386 | EXPORT_SYMBOL_GPL(tegra_bpmp_transfer); |
377 | 387 | ||
@@ -387,8 +397,8 @@ static struct tegra_bpmp_mrq *tegra_bpmp_find_mrq(struct tegra_bpmp *bpmp, | |||
387 | return NULL; | 397 | return NULL; |
388 | } | 398 | } |
389 | 399 | ||
390 | static void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, | 400 | void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code, |
391 | int code, const void *data, size_t size) | 401 | const void *data, size_t size) |
392 | { | 402 | { |
393 | unsigned long flags = channel->ib->flags; | 403 | unsigned long flags = channel->ib->flags; |
394 | struct tegra_bpmp *bpmp = channel->bpmp; | 404 | struct tegra_bpmp *bpmp = channel->bpmp; |
@@ -426,6 +436,7 @@ static void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, | |||
426 | mbox_client_txdone(bpmp->mbox.channel, 0); | 436 | mbox_client_txdone(bpmp->mbox.channel, 0); |
427 | } | 437 | } |
428 | } | 438 | } |
439 | EXPORT_SYMBOL_GPL(tegra_bpmp_mrq_return); | ||
429 | 440 | ||
430 | static void tegra_bpmp_handle_mrq(struct tegra_bpmp *bpmp, | 441 | static void tegra_bpmp_handle_mrq(struct tegra_bpmp *bpmp, |
431 | unsigned int mrq, | 442 | unsigned int mrq, |
@@ -824,6 +835,10 @@ static int tegra_bpmp_probe(struct platform_device *pdev) | |||
824 | if (err < 0) | 835 | if (err < 0) |
825 | goto free_mrq; | 836 | goto free_mrq; |
826 | 837 | ||
838 | err = tegra_bpmp_init_debugfs(bpmp); | ||
839 | if (err < 0) | ||
840 | dev_err(&pdev->dev, "debugfs initialization failed: %d\n", err); | ||
841 | |||
827 | return 0; | 842 | return 0; |
828 | 843 | ||
829 | free_mrq: | 844 | free_mrq: |