dpu_hw_blk.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
  13. #include <linux/mutex.h>
  14. #include <linux/errno.h>
  15. #include <linux/slab.h>
  16. #include "dpu_hw_mdss.h"
  17. #include "dpu_hw_blk.h"
  18. /* Serialization lock for dpu_hw_blk_list */
  19. static DEFINE_MUTEX(dpu_hw_blk_lock);
  20. /* List of all hw block objects */
  21. static LIST_HEAD(dpu_hw_blk_list);
  22. /**
  23. * dpu_hw_blk_init - initialize hw block object
  24. * @type: hw block type - enum dpu_hw_blk_type
  25. * @id: instance id of the hw block
  26. * @ops: Pointer to block operations
  27. * return: 0 if success; error code otherwise
  28. */
  29. int dpu_hw_blk_init(struct dpu_hw_blk *hw_blk, u32 type, int id,
  30. struct dpu_hw_blk_ops *ops)
  31. {
  32. if (!hw_blk) {
  33. pr_err("invalid parameters\n");
  34. return -EINVAL;
  35. }
  36. INIT_LIST_HEAD(&hw_blk->list);
  37. hw_blk->type = type;
  38. hw_blk->id = id;
  39. atomic_set(&hw_blk->refcount, 0);
  40. if (ops)
  41. hw_blk->ops = *ops;
  42. mutex_lock(&dpu_hw_blk_lock);
  43. list_add(&hw_blk->list, &dpu_hw_blk_list);
  44. mutex_unlock(&dpu_hw_blk_lock);
  45. return 0;
  46. }
  47. /**
  48. * dpu_hw_blk_destroy - destroy hw block object.
  49. * @hw_blk: pointer to hw block object
  50. * return: none
  51. */
  52. void dpu_hw_blk_destroy(struct dpu_hw_blk *hw_blk)
  53. {
  54. if (!hw_blk) {
  55. pr_err("invalid parameters\n");
  56. return;
  57. }
  58. if (atomic_read(&hw_blk->refcount))
  59. pr_err("hw_blk:%d.%d invalid refcount\n", hw_blk->type,
  60. hw_blk->id);
  61. mutex_lock(&dpu_hw_blk_lock);
  62. list_del(&hw_blk->list);
  63. mutex_unlock(&dpu_hw_blk_lock);
  64. }
  65. /**
  66. * dpu_hw_blk_get - get hw_blk from free pool
  67. * @hw_blk: if specified, increment reference count only
  68. * @type: if hw_blk is not specified, allocate the next available of this type
  69. * @id: if specified (>= 0), allocate the given instance of the above type
  70. * return: pointer to hw block object
  71. */
  72. struct dpu_hw_blk *dpu_hw_blk_get(struct dpu_hw_blk *hw_blk, u32 type, int id)
  73. {
  74. struct dpu_hw_blk *curr;
  75. int rc, refcount;
  76. if (!hw_blk) {
  77. mutex_lock(&dpu_hw_blk_lock);
  78. list_for_each_entry(curr, &dpu_hw_blk_list, list) {
  79. if ((curr->type != type) ||
  80. (id >= 0 && curr->id != id) ||
  81. (id < 0 &&
  82. atomic_read(&curr->refcount)))
  83. continue;
  84. hw_blk = curr;
  85. break;
  86. }
  87. mutex_unlock(&dpu_hw_blk_lock);
  88. }
  89. if (!hw_blk) {
  90. pr_debug("no hw_blk:%d\n", type);
  91. return NULL;
  92. }
  93. refcount = atomic_inc_return(&hw_blk->refcount);
  94. if (refcount == 1 && hw_blk->ops.start) {
  95. rc = hw_blk->ops.start(hw_blk);
  96. if (rc) {
  97. pr_err("failed to start hw_blk:%d rc:%d\n", type, rc);
  98. goto error_start;
  99. }
  100. }
  101. pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type,
  102. hw_blk->id, refcount);
  103. return hw_blk;
  104. error_start:
  105. dpu_hw_blk_put(hw_blk);
  106. return ERR_PTR(rc);
  107. }
  108. /**
  109. * dpu_hw_blk_put - put hw_blk to free pool if decremented refcount is zero
  110. * @hw_blk: hw block to be freed
  111. * @free_blk: function to be called when reference count goes to zero
  112. */
  113. void dpu_hw_blk_put(struct dpu_hw_blk *hw_blk)
  114. {
  115. if (!hw_blk) {
  116. pr_err("invalid parameters\n");
  117. return;
  118. }
  119. pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type, hw_blk->id,
  120. atomic_read(&hw_blk->refcount));
  121. if (!atomic_read(&hw_blk->refcount)) {
  122. pr_err("hw_blk:%d.%d invalid put\n", hw_blk->type, hw_blk->id);
  123. return;
  124. }
  125. if (atomic_dec_return(&hw_blk->refcount))
  126. return;
  127. if (hw_blk->ops.stop)
  128. hw_blk->ops.stop(hw_blk);
  129. }