vha_pdump.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. *****************************************************************************
  3. * Copyright (c) Imagination Technologies Ltd.
  4. *
  5. * The contents of this file are subject to the MIT license as set out below.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. *
  25. * Alternatively, the contents of this file may be used under the terms of the
  26. * GNU General Public License Version 2 ("GPL")in which case the provisions of
  27. * GPL are applicable instead of those above.
  28. *
  29. * If you wish to allow use of your version of this file only under the terms
  30. * of GPL, and not to allow others to use your version of this file under the
  31. * terms of the MIT license, indicate your decision by deleting the provisions
  32. * above and replace them with the notice and other provisions required by GPL
  33. * as set out in the file called "GPLHEADER" included in this distribution. If
  34. * you do not delete the provisions above, a recipient may use your version of
  35. * this file under the terms of either the MIT license or GPL.
  36. *
  37. * This License is also included in this distribution in the file called
  38. * "MIT_COPYING".
  39. *
  40. *****************************************************************************/
  41. #include <linux/slab.h>
  42. #include <linux/device.h>
  43. #include <linux/gfp.h>
  44. #include <linux/sched.h>
  45. #include <linux/list.h>
  46. #include <linux/moduleparam.h>
  47. #include <linux/list.h>
  48. #include <linux/delay.h>
  49. #include <linux/fs.h>
  50. #include <linux/io.h>
  51. #include <linux/seq_file.h>
  52. #include <linux/debugfs.h>
  53. #include <uapi/vha.h>
  54. #include "vha_common.h"
  55. #ifdef CONFIG_DEBUG_FS
  56. static uint32_t pdump_sizes_kB[PDUMP_MAX];
  57. module_param_array(pdump_sizes_kB, int, NULL, 0444);
  58. MODULE_PARM_DESC(pdump_sizes_kB, "sizes of buffers reserved for pdump TXT,PRM,RES,DBG,CRC,CMB_CRC");
  59. static bool no_pdump_cache = true;
  60. module_param(no_pdump_cache, bool, 0444);
  61. MODULE_PARM_DESC(no_pdump_cache, "if Y, then pdump cache feature is disabled");
  62. static uint32_t pdump_chunk_size_kB = 1024;
  63. module_param(pdump_chunk_size_kB, uint, 0444);
  64. MODULE_PARM_DESC(pdump_chunk_size_kB, "maximum size of pdump chunk to be stored at once");
  65. static const char *pdump_filenames[PDUMP_MAX] = {
  66. "pdump.txt", "pdump.prm", "pdump.res", "pdump.dbg", "pdump.crc", "pdump.crc_cmb",
  67. };
  68. static bool pdump_file_enabled[PDUMP_MAX] = {
  69. true, true, true, true, true, true,
  70. };
  71. /* read one of the pdump buffers */
  72. static ssize_t pdump_read(struct file *file, char __user *user_buf,
  73. size_t count, loff_t *ppos)
  74. {
  75. struct pdump_buf *pbuf = file->private_data;
  76. if (pbuf->len == pbuf->size)
  77. memcpy(pbuf->ptr+pbuf->size-8, "\n<oflo!>", 8);
  78. return simple_read_from_buffer(user_buf, count, ppos,
  79. pbuf->ptr, pbuf->len);
  80. }
  81. /*
  82. * write anything to the "reset" file, and
  83. * it will clear out the contents of all the pdump buffers
  84. */
  85. static ssize_t reset_write(struct file *file, const char __user *buf,
  86. size_t count, loff_t *ppos)
  87. {
  88. int i;
  89. struct pdump_descr *pbuf = file->private_data;
  90. for (i = 0; i < PDUMP_MAX; i++) {
  91. if (pbuf->pbufs[i].ptr)
  92. pbuf->pbufs[i].len = 0;
  93. }
  94. return count;
  95. }
  96. static const struct file_operations pdump_fops = {
  97. .read = pdump_read,
  98. .open = simple_open,
  99. .llseek = default_llseek,
  100. };
  101. static const struct file_operations reset_fops = {
  102. .write = reset_write,
  103. .open = simple_open,
  104. };
  105. static void config_pdump_files(struct vha_dev *vha) {
  106. if (!vha->cnn_combined_crc_enable)
  107. pdump_file_enabled[PDUMP_CRC_CMB] = false;
  108. }
  109. int vha_pdump_init(struct vha_dev *vha, struct pdump_descr* pdump)
  110. {
  111. int i;
  112. /* no purpose to pdumping if no TXT */
  113. if (pdump_sizes_kB[PDUMP_TXT] == 0)
  114. return -EINVAL;
  115. if (!vha->hw_props.dummy_dev) {
  116. dev_err(vha->dev, "%s: PDUMPing not supported with real hardware!\n",
  117. __func__);
  118. return -EPERM;
  119. }
  120. config_pdump_files(vha);
  121. /* and map the buffers into debugfs */
  122. for (i = 0; i < PDUMP_MAX; i++) {
  123. struct pdump_buf *pbuf = NULL;
  124. if (!pdump_file_enabled[i])
  125. continue;
  126. if (pdump_sizes_kB[i]) {
  127. if (pdump_sizes_kB[i] == UINT_MAX) {
  128. pbuf = img_pdump_create(pdump, i, 0);
  129. if (pbuf)
  130. pbuf->drop_data = true;
  131. } else {
  132. pbuf = img_pdump_create(pdump, i, pdump_sizes_kB[i]*1024);
  133. if (pbuf)
  134. pbuf->drop_data = false;
  135. }
  136. }
  137. if (pdump->pbufs[PDUMP_TXT].ptr == NULL)
  138. return -ENOMEM;
  139. if (pbuf && pbuf->ptr) {
  140. if (!debugfs_create_file(pdump_filenames[i],
  141. 0444, vha_dbg_get_sysfs(vha),
  142. pbuf, &pdump_fops))
  143. dev_warn(vha->dev,
  144. "%s: failed to create sysfs entry for pdump buf!\n",
  145. __func__);
  146. else
  147. dev_info(vha->dev, "%s: sysfs file %s created, size:%ukB\n",
  148. __func__,
  149. pdump_filenames[i], pdump_sizes_kB[i]);
  150. }
  151. }
  152. /* create a write-only file, for resetting all the pdump buffers
  153. * note: world write permission: it is pretty safe, because these
  154. * are just debug files.
  155. */
  156. if (!debugfs_create_file("pdump_reset", 0222,
  157. vha_dbg_get_sysfs(vha), pdump, &reset_fops))
  158. dev_warn(vha->dev,
  159. "%s: failed to create sysfs entry for pdump reset!\n",
  160. __func__);
  161. return 0;
  162. }
  163. void vha_pdump_deinit(struct pdump_descr* pdump)
  164. {
  165. img_pdump_destroy(pdump);
  166. }
  167. static void *get_buf_kptr(struct vha_session *session,
  168. struct vha_buffer *buf)
  169. {
  170. int ret;
  171. if (buf->kptr == NULL) {
  172. ret = img_mem_map_km(session->mem_ctx, buf->id);
  173. if (ret) {
  174. dev_err(session->vha->dev,
  175. "%s: failed to map buff %x to km: %d\n",
  176. __func__, buf->id, ret);
  177. return NULL;
  178. }
  179. buf->kptr = img_mem_get_kptr(session->mem_ctx, buf->id);
  180. }
  181. return buf->kptr;
  182. }
  183. static void put_buf_kptr(struct vha_session *session,
  184. struct vha_buffer *buf)
  185. {
  186. int ret;
  187. WARN_ON(!buf->kptr);
  188. if (buf->kptr != NULL) {
  189. ret = img_mem_unmap_km(session->mem_ctx, buf->id);
  190. if (ret)
  191. dev_err(session->vha->dev,
  192. "%s: failed to unmap buff %x from km: %d\n",
  193. __func__, buf->id, ret);
  194. buf->kptr = NULL;
  195. }
  196. }
  197. /* create pdump commands for LOAD Buffer */
  198. void vha_pdump_ldb_buf(struct vha_session *session, uint32_t pdump_num,
  199. struct vha_buffer *buf, uint32_t offset, uint32_t size, bool cache)
  200. {
  201. struct pdump_descr* pdump = vha_pdump_dev_get_drvdata(session->vha->dev);
  202. struct vha_dev* vha = session->vha;
  203. if (pdump_num >= PDUMP_MAX ||
  204. pdump->pbufs[PDUMP_TXT].ptr == NULL)
  205. return;
  206. if (buf->attr & IMG_MEM_ATTR_NOMAP)
  207. return;
  208. /* map buffer into km, if necessary */
  209. if (get_buf_kptr(session, buf) == NULL)
  210. return;
  211. if (no_pdump_cache)
  212. cache = false;
  213. if (!buf->pcache.valid ||
  214. (buf->pcache.valid &&
  215. (buf->pcache.offset != offset ||
  216. buf->pcache.size != size))) {
  217. buf->pcache.valid = cache;
  218. buf->pcache.size = size;
  219. buf->pcache.offset = offset;
  220. img_pdump_printf("LDB "_PMEM_":BLOCK_%d:%#x %#x %#zx %s -- %s\n",
  221. buf->id, offset, size,
  222. pdump->pbufs[pdump_num].len,
  223. pdump_filenames[pdump_num],
  224. buf->name);
  225. {
  226. void *ptr = buf->kptr + offset;
  227. int max_chunk = pdump_chunk_size_kB * 1024;
  228. while (size) {
  229. int chunk_size = size > max_chunk ?
  230. max_chunk : size;
  231. pr_debug("vha_pdump_ldb_buf chunk %d!\n",
  232. chunk_size);
  233. if (img_pdump_write(pdump, pdump_num,
  234. ptr, chunk_size) < 0) {
  235. img_pdump_printf("COM \"ERROR:pdump oflo, writing %#xB from %s to %s!\"\n",
  236. size, buf->name,
  237. pdump_filenames[pdump_num]);
  238. break;
  239. }
  240. ptr += chunk_size;
  241. size -= chunk_size;
  242. schedule();
  243. }
  244. }
  245. } else {
  246. img_pdump_printf("-- LDB_CACHED %s\n", buf->name);
  247. }
  248. put_buf_kptr(session, buf);
  249. }
  250. /* create pdump commands for SAVE Buffer */
  251. void vha_pdump_sab_buf(struct vha_session *session, uint32_t pdump_num,
  252. struct vha_buffer *buf, uint32_t offset, uint32_t size)
  253. {
  254. struct pdump_descr* pdump = vha_pdump_dev_get_drvdata(session->vha->dev);
  255. struct vha_dev* vha = session->vha;
  256. struct pdump_buf* pbuf;
  257. if (pdump_num >= PDUMP_MAX ||
  258. pdump->pbufs[PDUMP_TXT].ptr == NULL)
  259. return;
  260. pbuf = &pdump->pbufs[pdump_num];
  261. if (buf->attr & IMG_MEM_ATTR_NOMAP)
  262. return;
  263. if (get_buf_kptr(session, buf) == NULL)
  264. return;
  265. img_pdump_printf("SAB "_PMEM_":BLOCK_%d:%#x %#x %#zx %s -- %s\n",
  266. buf->id, offset, size,
  267. pbuf->len, pdump_filenames[pdump_num],
  268. buf->name);
  269. if (pbuf->drop_data) {
  270. pbuf->len += size;
  271. } else {
  272. void *ptr = buf->kptr + offset;
  273. int max_chunk = pdump_chunk_size_kB * 1024;
  274. /* Invalidate buffer cache just for sanity */
  275. img_mem_sync_device_to_cpu(session->mem_ctx, buf->id);
  276. /* write the binary data to the pdump blob file */
  277. while (size) {
  278. int chunk_size = size > max_chunk ? max_chunk : size;
  279. pr_debug("vha_pdump_sab_buf chunk %d!\n", chunk_size);
  280. if (img_pdump_write(pdump, pdump_num, ptr, chunk_size) < 0) {
  281. img_pdump_printf("COM \"ERROR:pdump oflo, writing %#xB from %s to %s!\"\n",
  282. size, buf->name,
  283. pdump_filenames[pdump_num]);
  284. break;
  285. }
  286. ptr += chunk_size;
  287. size -= chunk_size;
  288. schedule();
  289. }
  290. }
  291. put_buf_kptr(session, buf);
  292. }
  293. #else // CONFIG_DEBUG_FS
  294. int vha_pdump_init(struct vha_dev *vha, struct pdump_descr* pdump) { return 0; }
  295. void vha_pdump_deinit(struct pdump_descr* pdump) {}
  296. void vha_pdump_ldb_buf(struct vha_session *session, uint32_t pdump_num,
  297. struct vha_buffer *buffer, uint32_t offset, uint32_t len, bool cache) {}
  298. void vha_pdump_sab_buf(struct vha_session *session, uint32_t pdump_num,
  299. struct vha_buffer *buffer, uint32_t offset, uint32_t len) {}
  300. #endif // CONFIG_DEBUG_FS