hw_fence_ioctl.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  4. */
  5. #include <linux/file.h>
  6. #include <linux/fs.h>
  7. #include <linux/ioctl.h>
  8. #include <linux/ktime.h>
  9. #include <linux/types.h>
  10. #include <linux/sync_file.h>
  11. #include "hw_fence_drv_priv.h"
  12. #include "hw_fence_drv_utils.h"
  13. #include "hw_fence_drv_ipc.h"
  14. #include "hw_fence_drv_debug.h"
  15. #define HW_SYNC_IOCTL_COUNT ARRAY_SIZE(hw_sync_debugfs_ioctls)
  16. #define HW_FENCE_ARRAY_SIZE 10
  17. #define HW_SYNC_IOC_MAGIC 'W'
  18. #define HW_SYNC_IOC_REG_CLIENT _IOWR(HW_SYNC_IOC_MAGIC, 10, unsigned long)
  19. #define HW_SYNC_IOC_UNREG_CLIENT _IOWR(HW_SYNC_IOC_MAGIC, 11, unsigned long)
  20. #define HW_SYNC_IOC_CREATE_FENCE _IOWR(HW_SYNC_IOC_MAGIC, 12,\
  21. struct hw_fence_sync_create_data)
  22. #define HW_SYNC_IOC_CREATE_FENCE_ARRAY _IOWR(HW_SYNC_IOC_MAGIC, 14,\
  23. struct hw_fence_array_sync_create_data)
  24. #define HW_SYNC_IOC_REG_FOR_WAIT _IOWR(HW_SYNC_IOC_MAGIC, 16, int)
  25. #define HW_SYNC_IOC_FENCE_SIGNAL _IOWR(HW_SYNC_IOC_MAGIC, 17, unsigned long)
  26. #define HW_SYNC_IOC_FENCE_WAIT _IOWR(HW_SYNC_IOC_MAGIC, 18, int)
  27. #define HW_SYNC_IOC_RESET_CLIENT _IOWR(HW_SYNC_IOC_MAGIC, 19, unsigned long)
  28. #define HW_FENCE_IOCTL_NR(n) (_IOC_NR(n) - 2)
  29. #define HW_IOCTL_DEF(ioctl, _func) \
  30. [HW_FENCE_IOCTL_NR(ioctl)] = { \
  31. .cmd = ioctl, \
  32. .func = _func, \
  33. .name = #ioctl \
  34. }
  35. #define ktime_compare_safe(A, B) ktime_compare(ktime_sub((A), (B)), ktime_set(0, 0))
  36. /**
  37. * struct hw_sync_obj - per client hw sync object.
  38. * @context: context id used to create fences.
  39. * @client_id: to uniquely represent client.
  40. * @client_handle: Pointer to the structure holding the resources
  41. * allocated to the client.
  42. * @mem_descriptor: Memory descriptor of the queue allocated by the
  43. * hardware fence driver for each client during register.
  44. */
  45. struct hw_sync_obj {
  46. u64 context;
  47. int client_id;
  48. void *client_handle;
  49. struct msm_hw_fence_mem_addr mem_descriptor;
  50. };
  51. /**
  52. * struct hw_fence_sync_create_data - data used in creating fences.
  53. * @seqno: sequence number.
  54. * @incr_context: if set, then the context would be incremented.
  55. * @fence: returns the fd of the new sync_file with the created fence.
  56. * @hash: fence hash
  57. */
  58. struct hw_fence_sync_create_data {
  59. u64 seqno;
  60. bool incr_context;
  61. __s32 fence;
  62. u64 hash;
  63. };
  64. /**
  65. * struct hw_fence_array_sync_create_data - data used in creating multiple fences.
  66. * @seqno: sequence number used to create fence array.
  67. * @num_fences: number of fence fds received.
  68. * @fences: array of fence fds.
  69. * @fence_array_fd: fd of fence array.
  70. */
  71. struct hw_fence_array_sync_create_data {
  72. u64 seqno;
  73. int num_fences;
  74. u64 fences[HW_FENCE_ARRAY_SIZE];
  75. __s32 fence_array_fd;
  76. };
  77. /**
  78. * struct hw_fence_sync_signal_data - data used to signal fences.
  79. * @hash: hash of the fence.
  80. * @error_flag: error flag
  81. */
  82. struct hw_fence_sync_signal_data {
  83. u64 hash;
  84. u32 error_flag;
  85. };
  86. /**
  87. * struct hw_fence_sync_wait_data - data used to wait on fences.
  88. * @fence: fence fd.
  89. * @timeout_ms: fence wait time out.
  90. */
  91. struct hw_fence_sync_wait_data {
  92. __s32 fence;
  93. u64 timeout_ms;
  94. };
  95. /**
  96. * struct hw_fence_sync_reset_data - data used to reset client.
  97. * @client_id: client id.
  98. * @reset_flag: reset flag
  99. */
  100. struct hw_fence_sync_reset_data {
  101. int client_id;
  102. u32 reset_flag;
  103. };
  104. typedef long hw_fence_ioctl_t(struct hw_sync_obj *obj, unsigned long arg);
  105. /**
  106. * struct hw_sync_ioctl_def - hw_sync driver ioctl entry
  107. * @cmd: ioctl command number, without flags
  108. * @func: handler for this ioctl
  109. * @name: user-readable name for debug output
  110. */
  111. struct hw_sync_ioctl_def {
  112. unsigned int cmd;
  113. hw_fence_ioctl_t *func;
  114. const char *name;
  115. };
  116. static bool _is_valid_client(struct hw_sync_obj *obj)
  117. {
  118. if (!obj)
  119. return false;
  120. if (obj->client_id < HW_FENCE_CLIENT_ID_VAL0 || obj->client_id > HW_FENCE_CLIENT_ID_VAL6) {
  121. HWFNC_ERR("invalid client_id:%d min:%d max:%d\n", obj->client_id,
  122. HW_FENCE_CLIENT_ID_VAL0, HW_FENCE_CLIENT_ID_VAL6);
  123. return false;
  124. }
  125. return true;
  126. }
  127. static int _get_client_id(struct hw_sync_obj *obj, unsigned long arg)
  128. {
  129. int client_id;
  130. if (copy_from_user(&client_id, (void __user *)arg, sizeof(client_id)))
  131. return -EFAULT;
  132. if (!obj)
  133. return -EINVAL;
  134. if (client_id < HW_FENCE_CLIENT_ID_VAL0 || client_id > HW_FENCE_CLIENT_ID_VAL6) {
  135. HWFNC_ERR("invalid client_id:%d min:%d max:%d\n", client_id,
  136. HW_FENCE_CLIENT_ID_VAL0, HW_FENCE_CLIENT_ID_VAL6);
  137. return -EINVAL;
  138. }
  139. return client_id;
  140. }
  141. static void *_hw_sync_get_fence(int fd)
  142. {
  143. return fd >= 0 ? sync_file_get_fence(fd) : NULL;
  144. }
  145. static int hw_sync_debugfs_open(struct inode *inode, struct file *file)
  146. {
  147. struct hw_sync_obj *obj;
  148. obj = kzalloc(sizeof(*obj), GFP_KERNEL);
  149. if (!obj)
  150. return -ENOMEM;
  151. obj->context = dma_fence_context_alloc(1);
  152. file->private_data = obj;
  153. return 0;
  154. }
  155. static int hw_sync_debugfs_release(struct inode *inode, struct file *file)
  156. {
  157. struct hw_sync_obj *obj = file->private_data;
  158. if (!obj)
  159. return -EINVAL;
  160. kfree(obj);
  161. return 0;
  162. }
  163. static long hw_sync_ioctl_reg_client(struct hw_sync_obj *obj, unsigned long arg)
  164. {
  165. int client_id = _get_client_id(obj, arg);
  166. if (IS_ERR(&client_id)) {
  167. return client_id;
  168. } else if (obj->client_handle) {
  169. HWFNC_ERR("client:%d already registered as validation client\n", client_id);
  170. return -EINVAL;
  171. }
  172. obj->client_id = client_id;
  173. obj->client_handle = msm_hw_fence_register(obj->client_id, &obj->mem_descriptor);
  174. if (IS_ERR_OR_NULL(obj->client_handle))
  175. return -EINVAL;
  176. return 0;
  177. }
  178. static long hw_sync_ioctl_unreg_client(struct hw_sync_obj *obj, unsigned long arg)
  179. {
  180. int client_id = _get_client_id(obj, arg);
  181. if (IS_ERR(&client_id)) {
  182. return client_id;
  183. } else if (client_id != obj->client_id) {
  184. HWFNC_ERR("deregistering hw-fence client %d with invalid client_id arg:%d\n",
  185. obj->client_id, client_id);
  186. return -EINVAL;
  187. }
  188. return msm_hw_fence_deregister(obj->client_handle);
  189. }
  190. static long hw_sync_ioctl_create_fence(struct hw_sync_obj *obj, unsigned long arg)
  191. {
  192. struct msm_hw_fence_create_params params;
  193. struct hw_fence_sync_create_data data;
  194. struct hw_dma_fence *fence;
  195. spinlock_t *fence_lock;
  196. u64 hash;
  197. struct sync_file *sync_file;
  198. int fd, ret;
  199. if (!_is_valid_client(obj)) {
  200. return -EINVAL;
  201. } else if (IS_ERR_OR_NULL(obj->client_handle)) {
  202. HWFNC_ERR("client:%d is not register as validation client\n", obj->client_id);
  203. return -EINVAL;
  204. }
  205. if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
  206. return -EFAULT;
  207. /* create dma fence */
  208. fence_lock = kzalloc(sizeof(*fence_lock), GFP_KERNEL);
  209. if (!fence_lock)
  210. return -ENOMEM;
  211. fence = kzalloc(sizeof(*fence), GFP_KERNEL);
  212. if (!fence) {
  213. kfree(fence_lock);
  214. return -ENOMEM;
  215. }
  216. snprintf(fence->name, HW_FENCE_NAME_SIZE, "hwfence:id:%d:ctx=%lu:seqno:%lu",
  217. obj->client_id, obj->context, data.seqno);
  218. spin_lock_init(fence_lock);
  219. dma_fence_init(&fence->base, &hw_fence_dbg_ops, fence_lock, obj->context, data.seqno);
  220. HWFNC_DBG_H("creating hw_fence for client:%d ctx:%llu seqno:%llu\n", obj->client_id,
  221. obj->context, data.seqno);
  222. params.fence = &fence->base;
  223. params.handle = &hash;
  224. /* create hw fence */
  225. ret = msm_hw_fence_create(obj->client_handle, &params);
  226. if (ret) {
  227. HWFNC_ERR("failed to create hw_fence for client:%d ctx:%llu seqno:%llu\n",
  228. obj->client_id, obj->context, data.seqno);
  229. dma_fence_put(&fence->base);
  230. return -EINVAL;
  231. }
  232. /* keep handle in dma_fence, to destroy hw-fence during release */
  233. fence->client_handle = obj->client_handle;
  234. if (data.incr_context)
  235. obj->context = dma_fence_context_alloc(1);
  236. /* create fd */
  237. fd = get_unused_fd_flags(0);
  238. if (fd < 0) {
  239. HWFNC_ERR("failed to get fd for client:%d\n", obj->client_id);
  240. dma_fence_put(&fence->base);
  241. return fd;
  242. }
  243. sync_file = sync_file_create(&fence->base);
  244. if (sync_file == NULL) {
  245. HWFNC_ERR("couldn't create fence fd, %d\n", fd);
  246. dma_fence_put(&fence->base);
  247. ret = -EINVAL;
  248. goto exit;
  249. }
  250. /* Decrement the refcount that sync_file_create increments */
  251. dma_fence_put(&fence->base);
  252. data.fence = fd;
  253. data.hash = hash;
  254. if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
  255. dma_fence_put(&fence->base);
  256. fput(sync_file->file);
  257. ret = -EFAULT;
  258. goto exit;
  259. }
  260. fd_install(fd, sync_file->file);
  261. return 0;
  262. exit:
  263. put_unused_fd(fd);
  264. return ret;
  265. }
  266. static void _put_child_fences(int i, struct dma_fence **fences)
  267. {
  268. int fence_idx;
  269. for (fence_idx = i; fence_idx >= 0 ; fence_idx--)
  270. dma_fence_put(fences[i]);
  271. }
  272. static long hw_sync_ioctl_create_fence_array(struct hw_sync_obj *obj, unsigned long arg)
  273. {
  274. struct dma_fence_array *fence_array;
  275. struct hw_fence_array_sync_create_data data;
  276. struct dma_fence **fences = NULL;
  277. struct sync_file *sync_file;
  278. int num_fences, i, fd, ret;
  279. struct hw_dma_fence *fence;
  280. if (!_is_valid_client(obj)) {
  281. return -EINVAL;
  282. } else if (IS_ERR_OR_NULL(obj->client_handle)) {
  283. HWFNC_ERR("client:%d is not register as validation client\n", obj->client_id);
  284. return -EINVAL;
  285. }
  286. if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
  287. return -EFAULT;
  288. num_fences = data.num_fences;
  289. if (num_fences > HW_FENCE_ARRAY_SIZE) {
  290. HWFNC_ERR("Number of fences: %d is greater than allowed size: %d\n",
  291. num_fences, HW_FENCE_ARRAY_SIZE);
  292. return -EINVAL;
  293. }
  294. fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
  295. if (!fences) {
  296. return -ENOMEM;
  297. }
  298. for (i = 0; i < num_fences; i++) {
  299. fd = data.fences[i];
  300. if (fd <= 0) {
  301. kfree(fences);
  302. return -EINVAL;
  303. }
  304. fence = (struct hw_dma_fence *)_hw_sync_get_fence(fd);
  305. if (!fence) {
  306. _put_child_fences(i-1, fences);
  307. kfree(fences);
  308. return -EINVAL;
  309. }
  310. fences[i] = &fence->base;
  311. }
  312. /* create the fence array from array of dma fences */
  313. fence_array = dma_fence_array_create(num_fences, fences, obj->context, data.seqno, 0);
  314. if (!fence_array) {
  315. HWFNC_ERR("Error creating fence_array\n");
  316. /* decrease the refcount incremented for each child fences */
  317. for (i = 0; i < num_fences; i++)
  318. dma_fence_put(fences[i]);
  319. kfree(fences);
  320. return -EINVAL;
  321. }
  322. /* create fd */
  323. fd = get_unused_fd_flags(0);
  324. if (fd <= 0) {
  325. HWFNC_ERR("failed to get fd for client:%d\n", obj->client_id);
  326. dma_fence_put(&fence_array->base);
  327. return fd;
  328. }
  329. sync_file = sync_file_create(&fence_array->base);
  330. if (sync_file == NULL) {
  331. HWFNC_ERR("couldn't create fence fd, %d\n", fd);
  332. dma_fence_put(&fence_array->base);
  333. kfree(fence_array);
  334. ret = -EINVAL;
  335. goto exit;
  336. }
  337. /* Decrement the refcount that sync_file_create increments */
  338. dma_fence_put(&fence_array->base);
  339. data.fence_array_fd = fd;
  340. if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
  341. fput(sync_file->file);
  342. dma_fence_put(&fence_array->base);
  343. ret = -EFAULT;
  344. goto exit;
  345. }
  346. fd_install(fd, sync_file->file);
  347. return 0;
  348. exit:
  349. put_unused_fd(fd);
  350. return ret;
  351. }
  352. /*
  353. * this IOCTL only supports receiving one fence as input-parameter, which can be
  354. * either a "dma_fence" or a "dma_fence_array", but eventually we would expand
  355. * this API to receive more fences
  356. */
  357. static long hw_sync_ioctl_reg_for_wait(struct hw_sync_obj *obj, unsigned long arg)
  358. {
  359. struct dma_fence *fence;
  360. int ret, fd, num_fences = 1;
  361. if (!_is_valid_client(obj))
  362. return -EINVAL;
  363. if (copy_from_user(&fd, (void __user *)arg, sizeof(fd)))
  364. return -EFAULT;
  365. fence = (struct dma_fence *)_hw_sync_get_fence(fd);
  366. if (!fence) {
  367. HWFNC_ERR("Invalid fence fd: %d\n", fd);
  368. return -EINVAL;
  369. }
  370. ret = msm_hw_fence_wait_update_v2(obj->client_handle, &fence, NULL, NULL, num_fences, 1);
  371. /* Decrement the refcount that hw_sync_get_fence increments */
  372. dma_fence_put(fence);
  373. return ret;
  374. }
  375. static long hw_sync_ioctl_fence_signal(struct hw_sync_obj *obj, unsigned long arg)
  376. {
  377. struct msm_hw_fence_client *hw_fence_client;
  378. struct hw_fence_sync_signal_data data;
  379. int ret, tx_client, rx_client, signal_id;
  380. if (!_is_valid_client(obj)) {
  381. return -EINVAL;
  382. } else if (IS_ERR_OR_NULL(obj->client_handle)) {
  383. HWFNC_ERR("invalid client handle for the client_id: %d\n", obj->client_id);
  384. return -EINVAL;
  385. }
  386. hw_fence_client = (struct msm_hw_fence_client *)obj->client_handle;
  387. if (!hw_fence_client) {
  388. HWFNC_ERR("invalid client handle\n");
  389. return -EINVAL;
  390. }
  391. if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
  392. return -EFAULT;
  393. ret = msm_hw_fence_update_txq(obj->client_handle, data.hash, 0, data.error_flag);
  394. if (ret) {
  395. HWFNC_ERR("hw fence update txq has failed client_id: %d\n", obj->client_id);
  396. return ret;
  397. }
  398. signal_id = dbg_out_clients_signal_map_no_dpu[obj->client_id].ipc_signal_id;
  399. if (signal_id < 0)
  400. return -EINVAL;
  401. tx_client = hw_fence_client->ipc_client_pid;
  402. rx_client = hw_fence_client->ipc_client_vid;
  403. ret = msm_hw_fence_trigger_signal(obj->client_handle, tx_client, rx_client, signal_id);
  404. if (ret) {
  405. HWFNC_ERR("hw fence trigger signal has failed\n");
  406. return ret;
  407. }
  408. return 0;
  409. }
  410. static long hw_sync_ioctl_fence_wait(struct hw_sync_obj *obj, unsigned long arg)
  411. {
  412. struct msm_hw_fence_client *hw_fence_client;
  413. struct msm_hw_fence_queue_payload payload;
  414. struct hw_fence_sync_wait_data data;
  415. struct dma_fence *fence;
  416. ktime_t cur_ktime, exp_ktime;
  417. int fd, ret, read = 1, queue_type = HW_FENCE_RX_QUEUE - 1; /* rx queue index */
  418. if (!_is_valid_client(obj))
  419. return -EINVAL;
  420. if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
  421. return -EFAULT;
  422. fd = data.fence;
  423. fence = (struct dma_fence *)_hw_sync_get_fence(fd);
  424. if (!fence) {
  425. HWFNC_ERR("Invalid fence fd: %d\n", fd);
  426. return -EINVAL;
  427. }
  428. hw_fence_client = (struct msm_hw_fence_client *)obj->client_handle;
  429. if (!hw_fence_client) {
  430. HWFNC_ERR("invalid client handle for fd:%d\n", fd);
  431. /* Decrement the refcount that hw_sync_get_fence increments */
  432. dma_fence_put(fence);
  433. return -EINVAL;
  434. }
  435. exp_ktime = ktime_add_ms(ktime_get(), data.timeout_ms);
  436. do {
  437. ret = wait_event_timeout(hw_fence_client->wait_queue,
  438. atomic_read(&hw_fence_client->val_signal) > 0,
  439. msecs_to_jiffies(data.timeout_ms));
  440. cur_ktime = ktime_get();
  441. } while ((atomic_read(&hw_fence_client->val_signal) <= 0) && (ret == 0) &&
  442. ktime_compare_safe(exp_ktime, cur_ktime) > 0);
  443. if (!ret) {
  444. HWFNC_ERR("timed out waiting for the client signal %d\n", data.timeout_ms);
  445. /* Decrement the refcount that hw_sync_get_fence increments */
  446. dma_fence_put(fence);
  447. return -ETIMEDOUT;
  448. }
  449. /* clear doorbell signal flag */
  450. atomic_set(&hw_fence_client->val_signal, 0);
  451. while (read) {
  452. read = hw_fence_read_queue(obj->client_handle, &payload, queue_type);
  453. if (read < 0) {
  454. HWFNC_ERR("unable to read client rxq client_id:%d\n", obj->client_id);
  455. break;
  456. }
  457. HWFNC_DBG_L("rxq read: hash:%llu, flags:%llu, error:%lu\n",
  458. payload.hash, payload.flags, payload.error);
  459. if (payload.ctxt_id == fence->context && payload.seqno == fence->seqno) {
  460. /* Decrement the refcount that hw_sync_get_fence increments */
  461. dma_fence_put(fence);
  462. return 0;
  463. }
  464. }
  465. /* Decrement the refcount that hw_sync_get_fence increments */
  466. dma_fence_put(fence);
  467. HWFNC_ERR("fence received did not match the fence expected\n");
  468. HWFNC_ERR("fence received: context:%d seqno:%d fence expected: context:%d seqno:%d\n",
  469. payload.ctxt_id, payload.seqno, fence->context, fence->seqno);
  470. return read;
  471. }
  472. static long hw_sync_ioctl_reset_client(struct hw_sync_obj *obj, unsigned long arg)
  473. {
  474. int ret;
  475. struct hw_fence_sync_reset_data data;
  476. if (!_is_valid_client(obj)) {
  477. return -EINVAL;
  478. } else if (IS_ERR_OR_NULL(obj->client_handle)) {
  479. HWFNC_ERR("client:%d handle doesn't exists\n", obj->client_id);
  480. return -EINVAL;
  481. }
  482. if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
  483. return -EFAULT;
  484. ret = msm_hw_fence_reset_client(obj->client_handle, data.reset_flag);
  485. if (ret) {
  486. HWFNC_ERR("hw fence reset client has failed\n");
  487. return ret;
  488. }
  489. return 0;
  490. }
  491. static const struct hw_sync_ioctl_def hw_sync_debugfs_ioctls[] = {
  492. HW_IOCTL_DEF(HW_SYNC_IOC_REG_CLIENT, hw_sync_ioctl_reg_client),
  493. HW_IOCTL_DEF(HW_SYNC_IOC_UNREG_CLIENT, hw_sync_ioctl_unreg_client),
  494. HW_IOCTL_DEF(HW_SYNC_IOC_CREATE_FENCE, hw_sync_ioctl_create_fence),
  495. HW_IOCTL_DEF(HW_SYNC_IOC_CREATE_FENCE_ARRAY, hw_sync_ioctl_create_fence_array),
  496. HW_IOCTL_DEF(HW_SYNC_IOC_REG_FOR_WAIT, hw_sync_ioctl_reg_for_wait),
  497. HW_IOCTL_DEF(HW_SYNC_IOC_FENCE_SIGNAL, hw_sync_ioctl_fence_signal),
  498. HW_IOCTL_DEF(HW_SYNC_IOC_FENCE_WAIT, hw_sync_ioctl_fence_wait),
  499. HW_IOCTL_DEF(HW_SYNC_IOC_RESET_CLIENT, hw_sync_ioctl_reset_client)
  500. };
  501. static long hw_sync_debugfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  502. {
  503. struct hw_sync_obj *obj = file->private_data;
  504. int num = HW_FENCE_IOCTL_NR(cmd);
  505. hw_fence_ioctl_t *func;
  506. if (num >= HW_SYNC_IOCTL_COUNT) {
  507. HWFNC_ERR("invalid ioctl num = %d\n", num);
  508. return -EINVAL;
  509. }
  510. func = (&hw_sync_debugfs_ioctls[num])->func;
  511. if (unlikely(!func)) {
  512. HWFNC_ERR("no function num = %d\n", num);
  513. return -ENOTTY;
  514. }
  515. return func(obj, arg);
  516. }
  517. const struct file_operations hw_sync_debugfs_fops = {
  518. .open = hw_sync_debugfs_open,
  519. .release = hw_sync_debugfs_release,
  520. .unlocked_ioctl = hw_sync_debugfs_ioctl,
  521. };