vha_info.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/device.h>
  4. #include <linux/mm.h>
  5. #include <linux/string.h>
  6. #include <linux/kobject.h>
  7. #include <linux/uaccess.h>
  8. #include <linux/slab.h>
  9. #include <linux/miscdevice.h>
  10. #include <linux/kfifo.h>
  11. #include <linux/atomic.h>
  12. #include <linux/version.h>
  13. #include <linux/fs.h>
  14. #include <uapi/vha.h>
  15. #include "vha_common.h"
  16. MODULE_LICENSE("GPL v2");
  17. MODULE_AUTHOR("Imagination");
  18. #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0)
  19. MODULE_IMPORT_NS(VHA_CORE);
  20. #endif
  21. static uint64_t gettimestamp64(void)
  22. {
  23. #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
  24. struct timespec64 ts;
  25. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
  26. ktime_get_boottime_ts64(&ts);
  27. #else /* < LINUX_VERSION_CODE < 4.18.0 & LINUX_VERSION_CODE >= 3.17.0 */
  28. getnstimeofday64(&ts);
  29. #endif
  30. #else /* < LINUX_VERSION_CODE < 3.17.0 */
  31. struct timespec64 ts;
  32. ktime_get_ts64(&ts);
  33. #endif
  34. return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
  35. }
  36. /*
  37. * This kernel module is dependent on vha.ko. it hooks into vha.ko, in order to
  38. * provide timing information about HW events to PVRScope
  39. */
  40. /* fifo contains up to 2k events */
  41. #define NUM_FIFO_RECORDS 2048
  42. /* for simplicity, only allow a single connection to this device */
  43. static atomic_t open_count;
  44. /* unique sequence number for each event, for detecting loss of events */
  45. static atomic_t seqno;
  46. /* the event fifo contains VHA timing event information */
  47. static DEFINE_KFIFO(vha_events_fifo, struct vha_timing_data, NUM_FIFO_RECORDS);
  48. /* push event data into the fifo */
  49. static void add_timing_event(uint32_t devid, int type, uint32_t cycles)
  50. {
  51. struct vha_timing_data record;
  52. uint64_t timestamp = gettimestamp64();
  53. record.evt_type = VHA_EVENT_TIMING;
  54. record.seqno = atomic_inc_return(&seqno);
  55. record.timestamp_hi = timestamp >> 32;
  56. record.timestamp_lo = timestamp & 0xffffffff;
  57. record.dev_id = devid;
  58. record.type = type;
  59. record.cycles = cycles;
  60. /* should be filled from vha_trace_ctx.
  61. * at kernel level it could use task_tgid_nr(current);
  62. */
  63. record.pid = 0;
  64. /*record.tid = (unsigned)task_pid_nr(current); */
  65. #if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
  66. if (kfifo_put(&vha_events_fifo, &record) != 1)
  67. #else
  68. if (kfifo_put(&vha_events_fifo, record) != 1)
  69. #endif
  70. pr_err("%s: failed to record event into fifo\n", __func__);
  71. }
  72. /* push SUBMIT event into the fifo */
  73. static void observe_enqueue_event(uint32_t devid, uint32_t sessionid, uint32_t cmdid, uint32_t priority)
  74. {
  75. add_timing_event(devid, VHA_EVENT_TYPE_ENQUEUE, 0);
  76. }
  77. /* push SUBMIT event into the fifo */
  78. static void observe_submitted_event(uint32_t devid, uint32_t sessionid, uint32_t cmdid, bool last_subsegment, uint32_t priority)
  79. {
  80. add_timing_event(devid, VHA_EVENT_TYPE_SUBMIT, 0);
  81. }
  82. /* push COMPLETED event into the fifo */
  83. static void observe_completed_event(uint32_t devid, uint32_t sessionid, uint32_t cmdid,
  84. uint64_t status, uint64_t cycles, uint64_t mem_usage, uint32_t priority)
  85. {
  86. /* only successful events are logged */
  87. if (status == 0) {
  88. add_timing_event(devid, VHA_EVENT_TYPE_COMPLETE, (uint32_t)cycles);
  89. }
  90. }
  91. /* push ERROR event into the fifo */
  92. static void observe_error_event(uint32_t devid, uint32_t sessionid, uint32_t cmdid, uint64_t status)
  93. {
  94. add_timing_event(devid, VHA_EVENT_TYPE_ERROR, 0);
  95. }
  96. static int vhainfo_open(struct inode *inode, struct file *filep)
  97. {
  98. struct miscdevice *misc = filep->private_data;
  99. if (atomic_inc_return(&open_count) != 1) {
  100. dev_err(misc->this_device, "%s: 1 connection already\n",
  101. __func__);
  102. atomic_dec(&open_count);
  103. return -EALREADY;
  104. }
  105. /* register as observer of VHA events */
  106. vha_observe_event_enqueue(&observe_enqueue_event);
  107. vha_observe_event_submit(&observe_submitted_event);
  108. vha_observe_event_complete(&observe_completed_event);
  109. vha_observe_event_error(&observe_error_event);
  110. return nonseekable_open(inode, filep);
  111. }
  112. static int vhainfo_release(struct inode *inode, struct file *filep)
  113. {
  114. /* unregister for VHA events */
  115. vha_observe_event_submit(NULL);
  116. vha_observe_event_complete(NULL);
  117. atomic_dec(&open_count);
  118. return 0;
  119. }
  120. /* read from event fifo:
  121. * returns number of chars added to buffer
  122. * or 0 if fifo empty
  123. * or -ve error code
  124. */
  125. static ssize_t vhainfo_read(struct file *filep,
  126. char __user *buf, size_t count, loff_t *ppos)
  127. {
  128. unsigned int copied = 0;
  129. int ret;
  130. ret = kfifo_to_user(&vha_events_fifo, buf, count, &copied);
  131. if(copied > 0)
  132. printk("read(): wants %lu read %d\n", count, copied);
  133. if (ret)
  134. return ret;
  135. return copied;
  136. }
  137. static const struct file_operations vhainfo_fops = {
  138. .owner = THIS_MODULE,
  139. .open = vhainfo_open,
  140. .release = vhainfo_release,
  141. .read = vhainfo_read,
  142. .llseek = no_llseek,
  143. };
  144. static struct miscdevice vhainfomisc = {
  145. .name = VHA_SCOPE_DEV_NAME,
  146. .fops = &vhainfo_fops,
  147. .minor = MISC_DYNAMIC_MINOR,
  148. };
  149. static int __init vhainfo_init(void)
  150. {
  151. int ret = 0;
  152. ret = misc_register(&vhainfomisc);
  153. if (ret)
  154. pr_err("%s: misc_register failed\n", __func__);
  155. return ret;
  156. }
  157. static void __exit vhainfo_exit(void)
  158. {
  159. misc_deregister(&vhainfomisc);
  160. }
  161. module_init(vhainfo_init);
  162. module_exit(vhainfo_exit);