mic_fops.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * Intel MIC Platform Software Stack (MPSS)
  3. *
  4. * Copyright(c) 2013 Intel Corporation.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License, version 2, as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * The full GNU General Public License is included in this distribution in
  16. * the file called "COPYING".
  17. *
  18. * Intel MIC Host driver.
  19. *
  20. */
  21. #include <linux/poll.h>
  22. #include <linux/mic_common.h>
  23. #include "../common/mic_dev.h"
  24. #include "mic_device.h"
  25. #include "mic_fops.h"
  26. #include "mic_virtio.h"
  27. int mic_open(struct inode *inode, struct file *f)
  28. {
  29. struct mic_vdev *mvdev;
  30. struct mic_device *mdev = container_of(inode->i_cdev,
  31. struct mic_device, cdev);
  32. mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL);
  33. if (!mvdev)
  34. return -ENOMEM;
  35. init_waitqueue_head(&mvdev->waitq);
  36. INIT_LIST_HEAD(&mvdev->list);
  37. mvdev->mdev = mdev;
  38. mvdev->virtio_id = -1;
  39. f->private_data = mvdev;
  40. return 0;
  41. }
  42. int mic_release(struct inode *inode, struct file *f)
  43. {
  44. struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
  45. if (-1 != mvdev->virtio_id)
  46. mic_virtio_del_device(mvdev);
  47. f->private_data = NULL;
  48. kfree(mvdev);
  49. return 0;
  50. }
  51. long mic_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
  52. {
  53. struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
  54. void __user *argp = (void __user *)arg;
  55. int ret;
  56. switch (cmd) {
  57. case MIC_VIRTIO_ADD_DEVICE:
  58. {
  59. ret = mic_virtio_add_device(mvdev, argp);
  60. if (ret < 0) {
  61. dev_err(mic_dev(mvdev),
  62. "%s %d errno ret %d\n",
  63. __func__, __LINE__, ret);
  64. return ret;
  65. }
  66. break;
  67. }
  68. case MIC_VIRTIO_COPY_DESC:
  69. {
  70. struct mic_copy_desc copy;
  71. ret = mic_vdev_inited(mvdev);
  72. if (ret)
  73. return ret;
  74. if (copy_from_user(&copy, argp, sizeof(copy)))
  75. return -EFAULT;
  76. dev_dbg(mic_dev(mvdev),
  77. "%s %d === iovcnt 0x%x vr_idx 0x%x update_used %d\n",
  78. __func__, __LINE__, copy.iovcnt, copy.vr_idx,
  79. copy.update_used);
  80. ret = mic_virtio_copy_desc(mvdev, &copy);
  81. if (ret < 0) {
  82. dev_err(mic_dev(mvdev),
  83. "%s %d errno ret %d\n",
  84. __func__, __LINE__, ret);
  85. return ret;
  86. }
  87. if (copy_to_user(
  88. &((struct mic_copy_desc __user *)argp)->out_len,
  89. &copy.out_len, sizeof(copy.out_len))) {
  90. dev_err(mic_dev(mvdev), "%s %d errno ret %d\n",
  91. __func__, __LINE__, -EFAULT);
  92. return -EFAULT;
  93. }
  94. break;
  95. }
  96. case MIC_VIRTIO_CONFIG_CHANGE:
  97. {
  98. ret = mic_vdev_inited(mvdev);
  99. if (ret)
  100. return ret;
  101. ret = mic_virtio_config_change(mvdev, argp);
  102. if (ret < 0) {
  103. dev_err(mic_dev(mvdev),
  104. "%s %d errno ret %d\n",
  105. __func__, __LINE__, ret);
  106. return ret;
  107. }
  108. break;
  109. }
  110. default:
  111. return -ENOIOCTLCMD;
  112. };
  113. return 0;
  114. }
  115. /*
  116. * We return POLLIN | POLLOUT from poll when new buffers are enqueued, and
  117. * not when previously enqueued buffers may be available. This means that
  118. * in the card->host (TX) path, when userspace is unblocked by poll it
  119. * must drain all available descriptors or it can stall.
  120. */
  121. unsigned int mic_poll(struct file *f, poll_table *wait)
  122. {
  123. struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
  124. int mask = 0;
  125. poll_wait(f, &mvdev->waitq, wait);
  126. if (mic_vdev_inited(mvdev)) {
  127. mask = POLLERR;
  128. } else if (mvdev->poll_wake) {
  129. mvdev->poll_wake = 0;
  130. mask = POLLIN | POLLOUT;
  131. }
  132. return mask;
  133. }
  134. static inline int
  135. mic_query_offset(struct mic_vdev *mvdev, unsigned long offset,
  136. unsigned long *size, unsigned long *pa)
  137. {
  138. struct mic_device *mdev = mvdev->mdev;
  139. unsigned long start = MIC_DP_SIZE;
  140. int i;
  141. /*
  142. * MMAP interface is as follows:
  143. * offset region
  144. * 0x0 virtio device_page
  145. * 0x1000 first vring
  146. * 0x1000 + size of 1st vring second vring
  147. * ....
  148. */
  149. if (!offset) {
  150. *pa = virt_to_phys(mdev->dp);
  151. *size = MIC_DP_SIZE;
  152. return 0;
  153. }
  154. for (i = 0; i < mvdev->dd->num_vq; i++) {
  155. struct mic_vringh *mvr = &mvdev->mvr[i];
  156. if (offset == start) {
  157. *pa = virt_to_phys(mvr->vring.va);
  158. *size = mvr->vring.len;
  159. return 0;
  160. }
  161. start += mvr->vring.len;
  162. }
  163. return -1;
  164. }
  165. /*
  166. * Maps the device page and virtio rings to user space for readonly access.
  167. */
  168. int
  169. mic_mmap(struct file *f, struct vm_area_struct *vma)
  170. {
  171. struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
  172. unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
  173. unsigned long pa, size = vma->vm_end - vma->vm_start, size_rem = size;
  174. int i, err;
  175. err = mic_vdev_inited(mvdev);
  176. if (err)
  177. return err;
  178. if (vma->vm_flags & VM_WRITE)
  179. return -EACCES;
  180. while (size_rem) {
  181. i = mic_query_offset(mvdev, offset, &size, &pa);
  182. if (i < 0)
  183. return -EINVAL;
  184. err = remap_pfn_range(vma, vma->vm_start + offset,
  185. pa >> PAGE_SHIFT, size, vma->vm_page_prot);
  186. if (err)
  187. return err;
  188. dev_dbg(mic_dev(mvdev),
  189. "%s %d type %d size 0x%lx off 0x%lx pa 0x%lx vma 0x%lx\n",
  190. __func__, __LINE__, mvdev->virtio_id, size, offset,
  191. pa, vma->vm_start + offset);
  192. size_rem -= size;
  193. offset += size;
  194. }
  195. return 0;
  196. }