msm_cvp_ioctl.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  4. */
  5. #include "cvp_private.h"
  6. #include "cvp_hfi_api.h"
  7. static int _get_pkt_hdr_from_user(struct cvp_kmd_arg __user *up,
  8. struct cvp_hal_session_cmd_pkt *pkt_hdr)
  9. {
  10. struct cvp_kmd_hfi_packet *u;
  11. u = &up->data.hfi_pkt;
  12. if (get_user(pkt_hdr->size, &u->pkt_data[0]))
  13. return -EFAULT;
  14. if (get_user(pkt_hdr->packet_type, &u->pkt_data[1]))
  15. return -EFAULT;
  16. if (get_pkt_index(pkt_hdr) < 0) {
  17. dprintk(CVP_ERR, "user mode provides incorrect hfi\n");
  18. goto set_default_pkt_hdr;
  19. }
  20. if (pkt_hdr->size > MAX_HFI_PKT_SIZE*sizeof(unsigned int)) {
  21. dprintk(CVP_ERR, "user HFI packet too large %x\n",
  22. pkt_hdr->size);
  23. return -EINVAL;
  24. }
  25. return 0;
  26. set_default_pkt_hdr:
  27. pkt_hdr->size = get_msg_size();
  28. return 0;
  29. }
  30. static int _get_fence_pkt_hdr_from_user(struct cvp_kmd_arg __user *up,
  31. struct cvp_hal_session_cmd_pkt *pkt_hdr)
  32. {
  33. struct cvp_kmd_hfi_synx_packet __user *u;
  34. u = &up->data.hfi_synx_pkt;
  35. if (get_user(pkt_hdr->size, &u->pkt_data[0]))
  36. return -EFAULT;
  37. if (get_user(pkt_hdr->packet_type, &u->pkt_data[1]))
  38. return -EFAULT;
  39. if (pkt_hdr->size > (MAX_HFI_PKT_SIZE*sizeof(unsigned int)))
  40. return -EINVAL;
  41. return 0;
  42. }
  43. /* Size is in unit of u32 */
  44. static int _copy_pkt_from_user(struct cvp_kmd_arg *kp,
  45. struct cvp_kmd_arg __user *up,
  46. unsigned int size)
  47. {
  48. struct cvp_kmd_hfi_packet *k, *u;
  49. int i;
  50. k = &kp->data.hfi_pkt;
  51. u = &up->data.hfi_pkt;
  52. for (i = 0; i < size; i++)
  53. if (get_user(k->pkt_data[i], &u->pkt_data[i]))
  54. return -EFAULT;
  55. return 0;
  56. }
  57. static int _copy_synx_data_from_user(
  58. struct cvp_kmd_hfi_synx_packet *k,
  59. struct cvp_kmd_hfi_synx_packet __user *u)
  60. {
  61. int i;
  62. for (i = 0; i < MAX_FENCE_DATA_SIZE; i++) {
  63. if (get_user(k->fence_data[i], &u->fence_data[i]))
  64. return -EFAULT;
  65. }
  66. return 0;
  67. }
  68. /* Size is in unit of u32 */
  69. static int _copy_fence_data_from_user_deprecate(
  70. struct cvp_kmd_hfi_fence_packet *k,
  71. struct cvp_kmd_hfi_fence_packet __user *u)
  72. {
  73. int i;
  74. for (i = 0; i < MAX_HFI_FENCE_SIZE; i++) {
  75. if (get_user(k->fence_data[i], &u->fence_data[i]))
  76. return -EFAULT;
  77. }
  78. if (get_user(k->frame_id, &u->frame_id)) {
  79. dprintk(CVP_ERR, "Failed to get frame id from fence pkt\n");
  80. return -EFAULT;
  81. }
  82. return 0;
  83. }
  84. static int _copy_fence_pkt_from_user(struct cvp_kmd_arg *kp,
  85. struct cvp_kmd_arg __user *up)
  86. { struct cvp_kmd_hfi_synx_packet *k;
  87. struct cvp_kmd_hfi_synx_packet __user *u;
  88. struct cvp_kmd_hfi_fence_packet __user *u1;
  89. int i;
  90. k = &kp->data.hfi_synx_pkt;
  91. u = &up->data.hfi_synx_pkt;
  92. u1 = &up->data.hfi_fence_pkt;
  93. for (i = 0; i < MAX_HFI_PKT_SIZE; i++)
  94. if (get_user(k->pkt_data[i], &u->pkt_data[i]))
  95. return -EFAULT;
  96. if (get_user(k->fence_data[0], &u->fence_data[0]))
  97. return -EFAULT;
  98. if (k->fence_data[0] == 0xFEEDFACE)
  99. return _copy_synx_data_from_user(k, u);
  100. else
  101. return _copy_fence_data_from_user_deprecate(
  102. (struct cvp_kmd_hfi_fence_packet *)k, u1);
  103. }
  104. static int _copy_frameid_from_user(struct cvp_kmd_arg *kp,
  105. struct cvp_kmd_arg __user *up)
  106. {
  107. if (get_user(kp->data.frame_id, &up->data.frame_id)) {
  108. dprintk(CVP_ERR, "Failed to get frame id from user\n");
  109. return -EFAULT;
  110. }
  111. return 0;
  112. }
  113. static int _copy_sysprop_from_user(struct cvp_kmd_arg *kp,
  114. struct cvp_kmd_arg __user *up)
  115. {
  116. struct cvp_kmd_sys_properties *k, *u;
  117. k = &kp->data.sys_properties;
  118. u = &up->data.sys_properties;
  119. if (get_user(k->prop_num, &u->prop_num))
  120. return -EFAULT;
  121. if (k->prop_num < 1 || k->prop_num > 32) {
  122. dprintk(CVP_ERR, "Num of prop out of range %d\n", k->prop_num);
  123. return -EFAULT;
  124. }
  125. return _copy_pkt_from_user(kp, up,
  126. (k->prop_num*((sizeof(struct cvp_kmd_sys_property)>>2)+1)));
  127. }
  128. static int _copy_pkt_to_user(struct cvp_kmd_arg *kp,
  129. struct cvp_kmd_arg __user *up,
  130. unsigned int size)
  131. {
  132. struct cvp_kmd_hfi_packet *k, *u;
  133. int i;
  134. k = &kp->data.hfi_pkt;
  135. u = &up->data.hfi_pkt;
  136. for (i = 0; i < size; i++)
  137. if (put_user(k->pkt_data[i], &u->pkt_data[i]))
  138. return -EFAULT;
  139. return 0;
  140. }
  141. static int _copy_fence_pkt_to_user(struct cvp_kmd_arg *kp,
  142. struct cvp_kmd_arg __user *up)
  143. {
  144. struct cvp_kmd_hfi_synx_packet *k;
  145. struct cvp_kmd_hfi_synx_packet __user *u;
  146. int i;
  147. k = &kp->data.hfi_synx_pkt;
  148. u = &up->data.hfi_synx_pkt;
  149. for (i = 0; i < MAX_HFI_PKT_SIZE; i++) {
  150. if (put_user(k->pkt_data[i], &u->pkt_data[i]))
  151. return -EFAULT;
  152. }
  153. return 0;
  154. }
  155. static int _copy_sysprop_to_user(struct cvp_kmd_arg *kp,
  156. struct cvp_kmd_arg __user *up)
  157. {
  158. struct cvp_kmd_sys_properties *k;
  159. struct cvp_kmd_sys_properties __user *u;
  160. int i;
  161. k = &kp->data.sys_properties;
  162. u = &up->data.sys_properties;
  163. for (i = 0; i < 8; i++)
  164. if (put_user(k->prop_data[i].data, &u->prop_data[i].data))
  165. return -EFAULT;
  166. return 0;
  167. }
  168. static void print_hfi_short(struct cvp_kmd_arg __user *up)
  169. {
  170. struct cvp_kmd_hfi_packet *pkt;
  171. unsigned int words[5];
  172. pkt = &up->data.hfi_pkt;
  173. if (get_user(words[0], &up->type) ||
  174. get_user(words[1], &up->buf_offset) ||
  175. get_user(words[2], &up->buf_num) ||
  176. get_user(words[3], &pkt->pkt_data[0]) ||
  177. get_user(words[4], &pkt->pkt_data[1]))
  178. dprintk(CVP_ERR, "Failed to print ioctl cmd\n");
  179. dprintk(CVP_HFI, "IOCTL cmd type %#x, offset %d, num %d, pkt %d %#x\n",
  180. words[0], words[1], words[2], words[3], words[4]);
  181. }
  182. static int _copy_session_ctrl_to_user(
  183. struct cvp_kmd_session_control *k,
  184. struct cvp_kmd_session_control *u)
  185. {
  186. int i;
  187. if (put_user(k->ctrl_type, &u->ctrl_type))
  188. return -EFAULT;
  189. for (i = 0; i < 8; i++)
  190. if (put_user(k->ctrl_data[i], &u->ctrl_data[i]))
  191. return -EFAULT;
  192. return 0;
  193. }
  194. static int _get_session_ctrl_from_user(
  195. struct cvp_kmd_session_control *k,
  196. struct cvp_kmd_session_control *u)
  197. {
  198. int i;
  199. if (get_user(k->ctrl_type, &u->ctrl_type))
  200. return -EFAULT;
  201. for (i = 0; i < 8; i++)
  202. if (get_user(k->ctrl_data[i], &u->ctrl_data[i]))
  203. return -EFAULT;
  204. return 0;
  205. }
  206. static int _get_session_info_from_user(
  207. struct cvp_kmd_session_info *k,
  208. struct cvp_kmd_session_info __user *u)
  209. {
  210. int i;
  211. if (get_user(k->session_id, &u->session_id))
  212. return -EFAULT;
  213. for (i = 0; i < 10; i++)
  214. if (get_user(k->reserved[i], &u->reserved[i]))
  215. return -EFAULT;
  216. return 0;
  217. }
  218. static int convert_from_user(struct cvp_kmd_arg *kp,
  219. unsigned long arg,
  220. struct msm_cvp_inst *inst)
  221. {
  222. int rc = 0;
  223. int i;
  224. struct cvp_kmd_arg __user *up = (struct cvp_kmd_arg *)arg;
  225. struct cvp_hal_session_cmd_pkt pkt_hdr;
  226. int pkt_idx;
  227. if (!kp || !up) {
  228. dprintk(CVP_ERR, "%s: invalid params\n", __func__);
  229. return -EINVAL;
  230. }
  231. print_hfi_short(up);
  232. if (get_user(kp->type, &up->type))
  233. return -EFAULT;
  234. if (get_user(kp->buf_offset, &up->buf_offset) ||
  235. get_user(kp->buf_num, &up->buf_num))
  236. return -EFAULT;
  237. switch (kp->type) {
  238. case CVP_KMD_GET_SESSION_INFO:
  239. {
  240. struct cvp_kmd_session_info *k;
  241. struct cvp_kmd_session_info __user *u;
  242. k = &kp->data.session;
  243. u = &up->data.session;
  244. if (_get_session_info_from_user(k, u)) {
  245. dprintk(CVP_ERR, "fail to get sess info\n");
  246. return -EFAULT;
  247. }
  248. break;
  249. }
  250. case CVP_KMD_REGISTER_BUFFER:
  251. {
  252. struct cvp_kmd_buffer *k, *u;
  253. k = &kp->data.regbuf;
  254. u = &up->data.regbuf;
  255. if (get_user(k->type, &u->type) ||
  256. get_user(k->index, &u->index) ||
  257. get_user(k->fd, &u->fd) ||
  258. get_user(k->size, &u->size) ||
  259. get_user(k->offset, &u->offset) ||
  260. get_user(k->pixelformat, &u->pixelformat) ||
  261. get_user(k->flags, &u->flags))
  262. return -EFAULT;
  263. for (i = 0; i < 5; i++)
  264. if (get_user(k->reserved[i], &u->reserved[i]))
  265. return -EFAULT;
  266. break;
  267. }
  268. case CVP_KMD_UNREGISTER_BUFFER:
  269. {
  270. struct cvp_kmd_buffer *k, *u;
  271. k = &kp->data.unregbuf;
  272. u = &up->data.unregbuf;
  273. if (get_user(k->type, &u->type) ||
  274. get_user(k->index, &u->index) ||
  275. get_user(k->fd, &u->fd) ||
  276. get_user(k->size, &u->size) ||
  277. get_user(k->offset, &u->offset) ||
  278. get_user(k->pixelformat, &u->pixelformat) ||
  279. get_user(k->flags, &u->flags))
  280. return -EFAULT;
  281. for (i = 0; i < 5; i++)
  282. if (get_user(k->reserved[i], &u->reserved[i]))
  283. return -EFAULT;
  284. break;
  285. }
  286. case CVP_KMD_SEND_CMD_PKT:
  287. {
  288. if (_get_pkt_hdr_from_user(up, &pkt_hdr)) {
  289. dprintk(CVP_ERR, "Invalid syscall: %x, %x, %x\n",
  290. kp->type, pkt_hdr.size, pkt_hdr.packet_type);
  291. return -EFAULT;
  292. }
  293. rc = _copy_pkt_from_user(kp, up, (pkt_hdr.size >> 2));
  294. break;
  295. }
  296. case CVP_KMD_SEND_FENCE_CMD_PKT:
  297. {
  298. if (_get_fence_pkt_hdr_from_user(up, &pkt_hdr)) {
  299. dprintk(CVP_ERR, "Invalid syscall: %x, %x, %x\n",
  300. kp->type, pkt_hdr.size, pkt_hdr.packet_type);
  301. return -EFAULT;
  302. }
  303. dprintk(CVP_HFI, "system call cmd pkt: %d 0x%x\n",
  304. pkt_hdr.size, pkt_hdr.packet_type);
  305. pkt_idx = get_pkt_index(&pkt_hdr);
  306. if (pkt_idx < 0) {
  307. dprintk(CVP_ERR, "%s incorrect packet %d, %x\n",
  308. __func__,
  309. pkt_hdr.size,
  310. pkt_hdr.packet_type);
  311. return -EFAULT;
  312. }
  313. rc = _copy_fence_pkt_from_user(kp, up);
  314. break;
  315. }
  316. case CVP_KMD_RECEIVE_MSG_PKT:
  317. break;
  318. case CVP_KMD_SESSION_CONTROL:
  319. {
  320. struct cvp_kmd_session_control *k, *u;
  321. k = &kp->data.session_ctrl;
  322. u = &up->data.session_ctrl;
  323. rc = _get_session_ctrl_from_user(k, u);
  324. break;
  325. }
  326. case CVP_KMD_GET_SYS_PROPERTY:
  327. {
  328. if (_copy_sysprop_from_user(kp, up)) {
  329. dprintk(CVP_ERR, "Failed to get sysprop from user\n");
  330. return -EFAULT;
  331. }
  332. break;
  333. }
  334. case CVP_KMD_SET_SYS_PROPERTY:
  335. {
  336. if (_copy_sysprop_from_user(kp, up)) {
  337. dprintk(CVP_ERR, "Failed to set sysprop from user\n");
  338. return -EFAULT;
  339. }
  340. break;
  341. }
  342. case CVP_KMD_FLUSH_ALL:
  343. case CVP_KMD_UPDATE_POWER:
  344. break;
  345. case CVP_KMD_FLUSH_FRAME:
  346. {
  347. if (_copy_frameid_from_user(kp, up))
  348. return -EFAULT;
  349. break;
  350. }
  351. default:
  352. dprintk(CVP_ERR, "%s: unknown cmd type 0x%x\n",
  353. __func__, kp->type);
  354. rc = -EINVAL;
  355. break;
  356. }
  357. return rc;
  358. }
  359. static int _put_user_session_info(
  360. struct cvp_kmd_session_info *k,
  361. struct cvp_kmd_session_info __user *u)
  362. {
  363. int i;
  364. if (put_user(k->session_id, &u->session_id))
  365. return -EFAULT;
  366. for (i = 0; i < 10; i++)
  367. if (put_user(k->reserved[i], &u->reserved[i]))
  368. return -EFAULT;
  369. return 0;
  370. }
  371. static int convert_to_user(struct cvp_kmd_arg *kp, unsigned long arg)
  372. {
  373. int rc = 0;
  374. int i, size = get_msg_size() >> 2;
  375. struct cvp_kmd_arg __user *up = (struct cvp_kmd_arg *)arg;
  376. struct cvp_hal_session_cmd_pkt pkt_hdr;
  377. if (!kp || !up) {
  378. dprintk(CVP_ERR, "%s: invalid params\n", __func__);
  379. return -EINVAL;
  380. }
  381. if (put_user(kp->type, &up->type))
  382. return -EFAULT;
  383. switch (kp->type) {
  384. case CVP_KMD_RECEIVE_MSG_PKT:
  385. {
  386. struct cvp_kmd_hfi_packet *k, *u;
  387. k = &kp->data.hfi_pkt;
  388. u = &up->data.hfi_pkt;
  389. for (i = 0; i < size; i++)
  390. if (put_user(k->pkt_data[i], &u->pkt_data[i]))
  391. return -EFAULT;
  392. break;
  393. }
  394. case CVP_KMD_GET_SESSION_INFO:
  395. {
  396. struct cvp_kmd_session_info *k;
  397. struct cvp_kmd_session_info __user *u;
  398. k = &kp->data.session;
  399. u = &up->data.session;
  400. if (_put_user_session_info(k, u)) {
  401. dprintk(CVP_ERR, "fail to copy sess info to user\n");
  402. return -EFAULT;
  403. }
  404. break;
  405. }
  406. case CVP_KMD_REGISTER_BUFFER:
  407. {
  408. struct cvp_kmd_buffer *k, *u;
  409. k = &kp->data.regbuf;
  410. u = &up->data.regbuf;
  411. if (put_user(k->type, &u->type) ||
  412. put_user(k->index, &u->index) ||
  413. put_user(k->fd, &u->fd) ||
  414. put_user(k->size, &u->size) ||
  415. put_user(k->offset, &u->offset) ||
  416. put_user(k->pixelformat, &u->pixelformat) ||
  417. put_user(k->flags, &u->flags))
  418. return -EFAULT;
  419. for (i = 0; i < 5; i++)
  420. if (put_user(k->reserved[i], &u->reserved[i]))
  421. return -EFAULT;
  422. break;
  423. }
  424. case CVP_KMD_UNREGISTER_BUFFER:
  425. {
  426. struct cvp_kmd_buffer *k, *u;
  427. k = &kp->data.unregbuf;
  428. u = &up->data.unregbuf;
  429. if (put_user(k->type, &u->type) ||
  430. put_user(k->index, &u->index) ||
  431. put_user(k->fd, &u->fd) ||
  432. put_user(k->size, &u->size) ||
  433. put_user(k->offset, &u->offset) ||
  434. put_user(k->pixelformat, &u->pixelformat) ||
  435. put_user(k->flags, &u->flags))
  436. return -EFAULT;
  437. for (i = 0; i < 5; i++)
  438. if (put_user(k->reserved[i], &u->reserved[i]))
  439. return -EFAULT;
  440. break;
  441. }
  442. case CVP_KMD_SEND_CMD_PKT:
  443. {
  444. if (_get_pkt_hdr_from_user(up, &pkt_hdr))
  445. return -EFAULT;
  446. dprintk(CVP_HFI, "Send user cmd pkt: %d %d\n",
  447. pkt_hdr.size, pkt_hdr.packet_type);
  448. rc = _copy_pkt_to_user(kp, up, (pkt_hdr.size >> 2));
  449. break;
  450. }
  451. case CVP_KMD_SEND_FENCE_CMD_PKT:
  452. {
  453. if (_get_fence_pkt_hdr_from_user(up, &pkt_hdr))
  454. return -EFAULT;
  455. dprintk(CVP_HFI, "Send user cmd pkt: %d %d\n",
  456. pkt_hdr.size, pkt_hdr.packet_type);
  457. rc = _copy_fence_pkt_to_user(kp, up);
  458. break;
  459. }
  460. case CVP_KMD_SESSION_CONTROL:
  461. {
  462. struct cvp_kmd_session_control *k, *u;
  463. k = &kp->data.session_ctrl;
  464. u = &up->data.session_ctrl;
  465. rc = _copy_session_ctrl_to_user(k, u);
  466. break;
  467. }
  468. case CVP_KMD_GET_SYS_PROPERTY:
  469. {
  470. if (_copy_sysprop_to_user(kp, up)) {
  471. dprintk(CVP_ERR, "Fail to copy sysprop to user\n");
  472. return -EFAULT;
  473. }
  474. break;
  475. }
  476. case CVP_KMD_FLUSH_ALL:
  477. case CVP_KMD_FLUSH_FRAME:
  478. case CVP_KMD_SET_SYS_PROPERTY:
  479. case CVP_KMD_UPDATE_POWER:
  480. break;
  481. default:
  482. dprintk(CVP_ERR, "%s: unknown cmd type 0x%x\n",
  483. __func__, kp->type);
  484. rc = -EINVAL;
  485. break;
  486. }
  487. return rc;
  488. }
  489. static long cvp_ioctl(struct msm_cvp_inst *inst,
  490. unsigned int cmd, unsigned long arg)
  491. {
  492. int rc;
  493. struct cvp_kmd_arg *karg;
  494. if (!inst) {
  495. dprintk(CVP_ERR, "%s: invalid params\n", __func__);
  496. return -EINVAL;
  497. }
  498. karg = kzalloc(sizeof(*karg), GFP_KERNEL);
  499. if (!karg)
  500. return -ENOMEM;
  501. if (convert_from_user(karg, arg, inst)) {
  502. dprintk(CVP_ERR, "%s: failed to get from user cmd %x\n",
  503. __func__, karg->type);
  504. kfree(karg);
  505. return -EFAULT;
  506. }
  507. rc = msm_cvp_private((void *)inst, cmd, karg);
  508. if (rc) {
  509. dprintk(CVP_ERR, "%s: failed cmd type %x %d\n",
  510. __func__, karg->type, rc);
  511. kfree(karg);
  512. return rc;
  513. }
  514. if (convert_to_user(karg, arg)) {
  515. dprintk(CVP_ERR, "%s: failed to copy to user cmd %x\n",
  516. __func__, karg->type);
  517. kfree(karg);
  518. return -EFAULT;
  519. }
  520. kfree(karg);
  521. return rc;
  522. }
  523. long cvp_unblocked_ioctl(struct file *filp,
  524. unsigned int cmd, unsigned long arg)
  525. {
  526. struct msm_cvp_inst *inst;
  527. if (!filp || !filp->private_data) {
  528. dprintk(CVP_ERR, "%s: invalid params\n", __func__);
  529. return -EINVAL;
  530. }
  531. inst = filp->private_data;
  532. return cvp_ioctl(inst, cmd, arg);
  533. }
  534. long cvp_compat_ioctl(struct file *filp,
  535. unsigned int cmd, unsigned long arg)
  536. {
  537. struct msm_cvp_inst *inst;
  538. if (!filp || !filp->private_data) {
  539. dprintk(CVP_ERR, "%s: invalid params\n", __func__);
  540. return -EINVAL;
  541. }
  542. inst = filp->private_data;
  543. return cvp_ioctl(inst, cmd, (unsigned long)compat_ptr(arg));
  544. }