mic_fops.c 5.1 KB

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