kfd_process_queue_manager.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /*
  2. * Copyright 2014 Advanced Micro Devices, Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. */
  23. #include <linux/slab.h>
  24. #include <linux/list.h>
  25. #include "kfd_device_queue_manager.h"
  26. #include "kfd_priv.h"
  27. #include "kfd_kernel_queue.h"
  28. static inline struct process_queue_node *get_queue_by_qid(
  29. struct process_queue_manager *pqm, unsigned int qid)
  30. {
  31. struct process_queue_node *pqn;
  32. BUG_ON(!pqm);
  33. list_for_each_entry(pqn, &pqm->queues, process_queue_list) {
  34. if (pqn->q && pqn->q->properties.queue_id == qid)
  35. return pqn;
  36. if (pqn->kq && pqn->kq->queue->properties.queue_id == qid)
  37. return pqn;
  38. }
  39. return NULL;
  40. }
  41. static int find_available_queue_slot(struct process_queue_manager *pqm,
  42. unsigned int *qid)
  43. {
  44. unsigned long found;
  45. BUG_ON(!pqm || !qid);
  46. pr_debug("kfd: in %s\n", __func__);
  47. found = find_first_zero_bit(pqm->queue_slot_bitmap,
  48. max_num_of_queues_per_process);
  49. pr_debug("kfd: the new slot id %lu\n", found);
  50. if (found >= max_num_of_queues_per_process) {
  51. pr_info("amdkfd: Can not open more queues for process with pasid %d\n",
  52. pqm->process->pasid);
  53. return -ENOMEM;
  54. }
  55. set_bit(found, pqm->queue_slot_bitmap);
  56. *qid = found;
  57. return 0;
  58. }
  59. int pqm_init(struct process_queue_manager *pqm, struct kfd_process *p)
  60. {
  61. BUG_ON(!pqm);
  62. INIT_LIST_HEAD(&pqm->queues);
  63. pqm->queue_slot_bitmap =
  64. kzalloc(DIV_ROUND_UP(max_num_of_queues_per_process,
  65. BITS_PER_BYTE), GFP_KERNEL);
  66. if (pqm->queue_slot_bitmap == NULL)
  67. return -ENOMEM;
  68. pqm->process = p;
  69. return 0;
  70. }
  71. void pqm_uninit(struct process_queue_manager *pqm)
  72. {
  73. int retval;
  74. struct process_queue_node *pqn, *next;
  75. BUG_ON(!pqm);
  76. pr_debug("In func %s\n", __func__);
  77. list_for_each_entry_safe(pqn, next, &pqm->queues, process_queue_list) {
  78. retval = pqm_destroy_queue(
  79. pqm,
  80. (pqn->q != NULL) ?
  81. pqn->q->properties.queue_id :
  82. pqn->kq->queue->properties.queue_id);
  83. if (retval != 0) {
  84. pr_err("kfd: failed to destroy queue\n");
  85. return;
  86. }
  87. }
  88. kfree(pqm->queue_slot_bitmap);
  89. pqm->queue_slot_bitmap = NULL;
  90. }
  91. static int create_cp_queue(struct process_queue_manager *pqm,
  92. struct kfd_dev *dev, struct queue **q,
  93. struct queue_properties *q_properties,
  94. struct file *f, unsigned int qid)
  95. {
  96. int retval;
  97. retval = 0;
  98. /* Doorbell initialized in user space*/
  99. q_properties->doorbell_ptr = NULL;
  100. q_properties->doorbell_off =
  101. kfd_queue_id_to_doorbell(dev, pqm->process, qid);
  102. /* let DQM handle it*/
  103. q_properties->vmid = 0;
  104. q_properties->queue_id = qid;
  105. q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
  106. retval = init_queue(q, *q_properties);
  107. if (retval != 0)
  108. goto err_init_queue;
  109. (*q)->device = dev;
  110. (*q)->process = pqm->process;
  111. pr_debug("kfd: PQM After init queue");
  112. return retval;
  113. err_init_queue:
  114. return retval;
  115. }
  116. int pqm_create_queue(struct process_queue_manager *pqm,
  117. struct kfd_dev *dev,
  118. struct file *f,
  119. struct queue_properties *properties,
  120. unsigned int flags,
  121. enum kfd_queue_type type,
  122. unsigned int *qid)
  123. {
  124. int retval;
  125. struct kfd_process_device *pdd;
  126. struct queue_properties q_properties;
  127. struct queue *q;
  128. struct process_queue_node *pqn;
  129. struct kernel_queue *kq;
  130. BUG_ON(!pqm || !dev || !properties || !qid);
  131. memset(&q_properties, 0, sizeof(struct queue_properties));
  132. memcpy(&q_properties, properties, sizeof(struct queue_properties));
  133. q = NULL;
  134. kq = NULL;
  135. pdd = kfd_get_process_device_data(dev, pqm->process, 1);
  136. BUG_ON(!pdd);
  137. retval = find_available_queue_slot(pqm, qid);
  138. if (retval != 0)
  139. return retval;
  140. if (list_empty(&pqm->queues)) {
  141. pdd->qpd.pqm = pqm;
  142. dev->dqm->register_process(dev->dqm, &pdd->qpd);
  143. }
  144. pqn = kzalloc(sizeof(struct process_queue_node), GFP_KERNEL);
  145. if (!pqn) {
  146. retval = -ENOMEM;
  147. goto err_allocate_pqn;
  148. }
  149. switch (type) {
  150. case KFD_QUEUE_TYPE_COMPUTE:
  151. /* check if there is over subscription */
  152. if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) &&
  153. ((dev->dqm->processes_count >= VMID_PER_DEVICE) ||
  154. (dev->dqm->queue_count >= PIPE_PER_ME_CP_SCHEDULING * QUEUES_PER_PIPE))) {
  155. pr_err("kfd: over-subscription is not allowed in radeon_kfd.sched_policy == 1\n");
  156. retval = -EPERM;
  157. goto err_create_queue;
  158. }
  159. retval = create_cp_queue(pqm, dev, &q, &q_properties, f, *qid);
  160. if (retval != 0)
  161. goto err_create_queue;
  162. pqn->q = q;
  163. pqn->kq = NULL;
  164. retval = dev->dqm->create_queue(dev->dqm, q, &pdd->qpd,
  165. &q->properties.vmid);
  166. print_queue(q);
  167. break;
  168. case KFD_QUEUE_TYPE_DIQ:
  169. kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_DIQ);
  170. if (kq == NULL) {
  171. retval = -ENOMEM;
  172. goto err_create_queue;
  173. }
  174. kq->queue->properties.queue_id = *qid;
  175. pqn->kq = kq;
  176. pqn->q = NULL;
  177. retval = dev->dqm->create_kernel_queue(dev->dqm, kq, &pdd->qpd);
  178. break;
  179. default:
  180. BUG();
  181. break;
  182. }
  183. if (retval != 0) {
  184. pr_err("kfd: error dqm create queue\n");
  185. goto err_create_queue;
  186. }
  187. pr_debug("kfd: PQM After DQM create queue\n");
  188. list_add(&pqn->process_queue_list, &pqm->queues);
  189. if (q) {
  190. *properties = q->properties;
  191. pr_debug("kfd: PQM done creating queue\n");
  192. print_queue_properties(properties);
  193. }
  194. return retval;
  195. err_create_queue:
  196. kfree(pqn);
  197. err_allocate_pqn:
  198. clear_bit(*qid, pqm->queue_slot_bitmap);
  199. return retval;
  200. }
  201. int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid)
  202. {
  203. struct process_queue_node *pqn;
  204. struct kfd_process_device *pdd;
  205. struct device_queue_manager *dqm;
  206. struct kfd_dev *dev;
  207. int retval;
  208. dqm = NULL;
  209. BUG_ON(!pqm);
  210. retval = 0;
  211. pr_debug("kfd: In Func %s\n", __func__);
  212. pqn = get_queue_by_qid(pqm, qid);
  213. if (pqn == NULL) {
  214. pr_err("kfd: queue id does not match any known queue\n");
  215. return -EINVAL;
  216. }
  217. dev = NULL;
  218. if (pqn->kq)
  219. dev = pqn->kq->dev;
  220. if (pqn->q)
  221. dev = pqn->q->device;
  222. BUG_ON(!dev);
  223. pdd = kfd_get_process_device_data(dev, pqm->process, 1);
  224. BUG_ON(!pdd);
  225. if (pqn->kq) {
  226. /* destroy kernel queue (DIQ) */
  227. dqm = pqn->kq->dev->dqm;
  228. dqm->destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd);
  229. kernel_queue_uninit(pqn->kq);
  230. }
  231. if (pqn->q) {
  232. dqm = pqn->q->device->dqm;
  233. retval = dqm->destroy_queue(dqm, &pdd->qpd, pqn->q);
  234. if (retval != 0)
  235. return retval;
  236. uninit_queue(pqn->q);
  237. }
  238. list_del(&pqn->process_queue_list);
  239. kfree(pqn);
  240. clear_bit(qid, pqm->queue_slot_bitmap);
  241. if (list_empty(&pqm->queues))
  242. dqm->unregister_process(dqm, &pdd->qpd);
  243. return retval;
  244. }
  245. int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid,
  246. struct queue_properties *p)
  247. {
  248. int retval;
  249. struct process_queue_node *pqn;
  250. BUG_ON(!pqm);
  251. pqn = get_queue_by_qid(pqm, qid);
  252. BUG_ON(!pqn);
  253. pqn->q->properties.queue_address = p->queue_address;
  254. pqn->q->properties.queue_size = p->queue_size;
  255. pqn->q->properties.queue_percent = p->queue_percent;
  256. pqn->q->properties.priority = p->priority;
  257. retval = pqn->q->device->dqm->update_queue(pqn->q->device->dqm, pqn->q);
  258. if (retval != 0)
  259. return retval;
  260. return 0;
  261. }
  262. static __attribute__((unused)) struct kernel_queue *pqm_get_kernel_queue(
  263. struct process_queue_manager *pqm,
  264. unsigned int qid)
  265. {
  266. struct process_queue_node *pqn;
  267. BUG_ON(!pqm);
  268. pqn = get_queue_by_qid(pqm, qid);
  269. if (pqn && pqn->kq)
  270. return pqn->kq;
  271. return NULL;
  272. }