ae4dma-dev.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * AMD AE4DMA driver
  4. *
  5. * Copyright (c) 2024, Advanced Micro Devices, Inc.
  6. * All Rights Reserved.
  7. *
  8. * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
  9. */
  10. #include "ae4dma.h"
  11. static unsigned int max_hw_q = 1;
  12. module_param(max_hw_q, uint, 0444);
  13. MODULE_PARM_DESC(max_hw_q, "max hw queues supported by engine (any non-zero value, default: 1)");
  14. static void ae4_pending_work(struct work_struct *work)
  15. {
  16. struct ae4_cmd_queue *ae4cmd_q = container_of(work, struct ae4_cmd_queue, p_work.work);
  17. struct pt_cmd_queue *cmd_q = &ae4cmd_q->cmd_q;
  18. struct pt_cmd *cmd;
  19. u32 cridx;
  20. for (;;) {
  21. wait_event_interruptible(ae4cmd_q->q_w,
  22. ((atomic64_read(&ae4cmd_q->done_cnt)) <
  23. atomic64_read(&ae4cmd_q->intr_cnt)));
  24. atomic64_inc(&ae4cmd_q->done_cnt);
  25. mutex_lock(&ae4cmd_q->cmd_lock);
  26. cridx = readl(cmd_q->reg_control + AE4_RD_IDX_OFF);
  27. while ((ae4cmd_q->dridx != cridx) && !list_empty(&ae4cmd_q->cmd)) {
  28. cmd = list_first_entry(&ae4cmd_q->cmd, struct pt_cmd, entry);
  29. list_del(&cmd->entry);
  30. ae4_check_status_error(ae4cmd_q, ae4cmd_q->dridx);
  31. cmd->pt_cmd_callback(cmd->data, cmd->ret);
  32. ae4cmd_q->q_cmd_count--;
  33. ae4cmd_q->dridx = (ae4cmd_q->dridx + 1) % CMD_Q_LEN;
  34. complete_all(&ae4cmd_q->cmp);
  35. }
  36. mutex_unlock(&ae4cmd_q->cmd_lock);
  37. }
  38. }
  39. static irqreturn_t ae4_core_irq_handler(int irq, void *data)
  40. {
  41. struct ae4_cmd_queue *ae4cmd_q = data;
  42. struct pt_cmd_queue *cmd_q;
  43. struct pt_device *pt;
  44. u32 status;
  45. cmd_q = &ae4cmd_q->cmd_q;
  46. pt = cmd_q->pt;
  47. pt->total_interrupts++;
  48. atomic64_inc(&ae4cmd_q->intr_cnt);
  49. status = readl(cmd_q->reg_control + AE4_INTR_STS_OFF);
  50. if (status & BIT(0)) {
  51. status &= GENMASK(31, 1);
  52. writel(status, cmd_q->reg_control + AE4_INTR_STS_OFF);
  53. }
  54. wake_up(&ae4cmd_q->q_w);
  55. return IRQ_HANDLED;
  56. }
  57. void ae4_destroy_work(struct ae4_device *ae4)
  58. {
  59. struct ae4_cmd_queue *ae4cmd_q;
  60. int i;
  61. for (i = 0; i < ae4->cmd_q_count; i++) {
  62. ae4cmd_q = &ae4->ae4cmd_q[i];
  63. if (!ae4cmd_q->pws)
  64. break;
  65. cancel_delayed_work_sync(&ae4cmd_q->p_work);
  66. destroy_workqueue(ae4cmd_q->pws);
  67. }
  68. }
  69. int ae4_core_init(struct ae4_device *ae4)
  70. {
  71. struct pt_device *pt = &ae4->pt;
  72. struct ae4_cmd_queue *ae4cmd_q;
  73. struct device *dev = pt->dev;
  74. struct pt_cmd_queue *cmd_q;
  75. int i, ret = 0;
  76. writel(max_hw_q, pt->io_regs);
  77. for (i = 0; i < max_hw_q; i++) {
  78. ae4cmd_q = &ae4->ae4cmd_q[i];
  79. ae4cmd_q->id = ae4->cmd_q_count;
  80. ae4->cmd_q_count++;
  81. cmd_q = &ae4cmd_q->cmd_q;
  82. cmd_q->pt = pt;
  83. cmd_q->reg_control = pt->io_regs + ((i + 1) * AE4_Q_SZ);
  84. ret = devm_request_irq(dev, ae4->ae4_irq[i], ae4_core_irq_handler, 0,
  85. dev_name(pt->dev), ae4cmd_q);
  86. if (ret)
  87. return ret;
  88. cmd_q->qsize = Q_SIZE(sizeof(struct ae4dma_desc));
  89. cmd_q->qbase = dmam_alloc_coherent(dev, cmd_q->qsize, &cmd_q->qbase_dma,
  90. GFP_KERNEL);
  91. if (!cmd_q->qbase)
  92. return -ENOMEM;
  93. }
  94. for (i = 0; i < ae4->cmd_q_count; i++) {
  95. ae4cmd_q = &ae4->ae4cmd_q[i];
  96. cmd_q = &ae4cmd_q->cmd_q;
  97. cmd_q->reg_control = pt->io_regs + ((i + 1) * AE4_Q_SZ);
  98. /* Update the device registers with queue information. */
  99. writel(CMD_Q_LEN, cmd_q->reg_control + AE4_MAX_IDX_OFF);
  100. cmd_q->qdma_tail = cmd_q->qbase_dma;
  101. writel(lower_32_bits(cmd_q->qdma_tail), cmd_q->reg_control + AE4_Q_BASE_L_OFF);
  102. writel(upper_32_bits(cmd_q->qdma_tail), cmd_q->reg_control + AE4_Q_BASE_H_OFF);
  103. INIT_LIST_HEAD(&ae4cmd_q->cmd);
  104. init_waitqueue_head(&ae4cmd_q->q_w);
  105. ae4cmd_q->pws = alloc_ordered_workqueue("ae4dma_%d", WQ_MEM_RECLAIM, ae4cmd_q->id);
  106. if (!ae4cmd_q->pws) {
  107. ae4_destroy_work(ae4);
  108. return -ENOMEM;
  109. }
  110. INIT_DELAYED_WORK(&ae4cmd_q->p_work, ae4_pending_work);
  111. queue_delayed_work(ae4cmd_q->pws, &ae4cmd_q->p_work, usecs_to_jiffies(100));
  112. init_completion(&ae4cmd_q->cmp);
  113. }
  114. ret = pt_dmaengine_register(pt);
  115. if (ret)
  116. ae4_destroy_work(ae4);
  117. else
  118. ptdma_debugfs_setup(pt);
  119. return ret;
  120. }