msm_fence.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2013-2016 Red Hat
  4. * Author: Rob Clark <[email protected]>
  5. */
  6. #include <linux/dma-fence.h>
  7. #include "msm_drv.h"
  8. #include "msm_fence.h"
  9. struct msm_fence_context *
  10. msm_fence_context_alloc(struct drm_device *dev, volatile uint32_t *fenceptr,
  11. const char *name)
  12. {
  13. struct msm_fence_context *fctx;
  14. static int index = 0;
  15. fctx = kzalloc(sizeof(*fctx), GFP_KERNEL);
  16. if (!fctx)
  17. return ERR_PTR(-ENOMEM);
  18. fctx->dev = dev;
  19. strscpy(fctx->name, name, sizeof(fctx->name));
  20. fctx->context = dma_fence_context_alloc(1);
  21. fctx->index = index++;
  22. fctx->fenceptr = fenceptr;
  23. spin_lock_init(&fctx->spinlock);
  24. /*
  25. * Start out close to the 32b fence rollover point, so we can
  26. * catch bugs with fence comparisons.
  27. */
  28. fctx->last_fence = 0xffffff00;
  29. fctx->completed_fence = fctx->last_fence;
  30. *fctx->fenceptr = fctx->last_fence;
  31. return fctx;
  32. }
  33. void msm_fence_context_free(struct msm_fence_context *fctx)
  34. {
  35. kfree(fctx);
  36. }
  37. bool msm_fence_completed(struct msm_fence_context *fctx, uint32_t fence)
  38. {
  39. /*
  40. * Note: Check completed_fence first, as fenceptr is in a write-combine
  41. * mapping, so it will be more expensive to read.
  42. */
  43. return (int32_t)(fctx->completed_fence - fence) >= 0 ||
  44. (int32_t)(*fctx->fenceptr - fence) >= 0;
  45. }
  46. /* called from irq handler and workqueue (in recover path) */
  47. void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence)
  48. {
  49. unsigned long flags;
  50. spin_lock_irqsave(&fctx->spinlock, flags);
  51. if (fence_after(fence, fctx->completed_fence))
  52. fctx->completed_fence = fence;
  53. spin_unlock_irqrestore(&fctx->spinlock, flags);
  54. }
  55. struct msm_fence {
  56. struct dma_fence base;
  57. struct msm_fence_context *fctx;
  58. };
  59. static inline struct msm_fence *to_msm_fence(struct dma_fence *fence)
  60. {
  61. return container_of(fence, struct msm_fence, base);
  62. }
  63. static const char *msm_fence_get_driver_name(struct dma_fence *fence)
  64. {
  65. return "msm";
  66. }
  67. static const char *msm_fence_get_timeline_name(struct dma_fence *fence)
  68. {
  69. struct msm_fence *f = to_msm_fence(fence);
  70. return f->fctx->name;
  71. }
  72. static bool msm_fence_signaled(struct dma_fence *fence)
  73. {
  74. struct msm_fence *f = to_msm_fence(fence);
  75. return msm_fence_completed(f->fctx, f->base.seqno);
  76. }
  77. static const struct dma_fence_ops msm_fence_ops = {
  78. .get_driver_name = msm_fence_get_driver_name,
  79. .get_timeline_name = msm_fence_get_timeline_name,
  80. .signaled = msm_fence_signaled,
  81. };
  82. struct dma_fence *
  83. msm_fence_alloc(struct msm_fence_context *fctx)
  84. {
  85. struct msm_fence *f;
  86. f = kzalloc(sizeof(*f), GFP_KERNEL);
  87. if (!f)
  88. return ERR_PTR(-ENOMEM);
  89. f->fctx = fctx;
  90. dma_fence_init(&f->base, &msm_fence_ops, &fctx->spinlock,
  91. fctx->context, ++fctx->last_fence);
  92. return &f->base;
  93. }