uio_hv_generic.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * uio_hv_generic - generic UIO driver for VMBus
  3. *
  4. * Copyright (c) 2013-2016 Brocade Communications Systems, Inc.
  5. * Copyright (c) 2016, Microsoft Corporation.
  6. *
  7. *
  8. * This work is licensed under the terms of the GNU GPL, version 2.
  9. *
  10. * Since the driver does not declare any device ids, you must allocate
  11. * id and bind the device to the driver yourself. For example:
  12. *
  13. * # echo "f8615163-df3e-46c5-913f-f2d2f965ed0e" \
  14. * > /sys/bus/vmbus/drivers/uio_hv_generic
  15. * # echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 \
  16. * > /sys/bus/vmbus/drivers/hv_netvsc/unbind
  17. * # echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 \
  18. * > /sys/bus/vmbus/drivers/uio_hv_generic/bind
  19. */
  20. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  21. #include <linux/device.h>
  22. #include <linux/kernel.h>
  23. #include <linux/module.h>
  24. #include <linux/uio_driver.h>
  25. #include <linux/netdevice.h>
  26. #include <linux/if_ether.h>
  27. #include <linux/skbuff.h>
  28. #include <linux/hyperv.h>
  29. #include <linux/vmalloc.h>
  30. #include <linux/slab.h>
  31. #include "../hv/hyperv_vmbus.h"
  32. #define DRIVER_VERSION "0.02.0"
  33. #define DRIVER_AUTHOR "Stephen Hemminger <sthemmin at microsoft.com>"
  34. #define DRIVER_DESC "Generic UIO driver for VMBus devices"
  35. /*
  36. * List of resources to be mapped to user space
  37. * can be extended up to MAX_UIO_MAPS(5) items
  38. */
  39. enum hv_uio_map {
  40. TXRX_RING_MAP = 0,
  41. INT_PAGE_MAP,
  42. MON_PAGE_MAP,
  43. };
  44. #define HV_RING_SIZE 512
  45. struct hv_uio_private_data {
  46. struct uio_info info;
  47. struct hv_device *device;
  48. };
  49. static int
  50. hv_uio_mmap(struct uio_info *info, struct vm_area_struct *vma)
  51. {
  52. int mi;
  53. if (vma->vm_pgoff >= MAX_UIO_MAPS)
  54. return -EINVAL;
  55. if (info->mem[vma->vm_pgoff].size == 0)
  56. return -EINVAL;
  57. mi = (int)vma->vm_pgoff;
  58. return remap_pfn_range(vma, vma->vm_start,
  59. info->mem[mi].addr >> PAGE_SHIFT,
  60. vma->vm_end - vma->vm_start, vma->vm_page_prot);
  61. }
  62. /*
  63. * This is the irqcontrol callback to be registered to uio_info.
  64. * It can be used to disable/enable interrupt from user space processes.
  65. *
  66. * @param info
  67. * pointer to uio_info.
  68. * @param irq_state
  69. * state value. 1 to enable interrupt, 0 to disable interrupt.
  70. */
  71. static int
  72. hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
  73. {
  74. struct hv_uio_private_data *pdata = info->priv;
  75. struct hv_device *dev = pdata->device;
  76. dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state;
  77. virt_mb();
  78. return 0;
  79. }
  80. /*
  81. * Callback from vmbus_event when something is in inbound ring.
  82. */
  83. static void hv_uio_channel_cb(void *context)
  84. {
  85. struct hv_uio_private_data *pdata = context;
  86. struct hv_device *dev = pdata->device;
  87. dev->channel->inbound.ring_buffer->interrupt_mask = 1;
  88. virt_mb();
  89. uio_event_notify(&pdata->info);
  90. }
  91. static int
  92. hv_uio_probe(struct hv_device *dev,
  93. const struct hv_vmbus_device_id *dev_id)
  94. {
  95. struct hv_uio_private_data *pdata;
  96. int ret;
  97. pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
  98. if (!pdata)
  99. return -ENOMEM;
  100. ret = vmbus_open(dev->channel, HV_RING_SIZE * PAGE_SIZE,
  101. HV_RING_SIZE * PAGE_SIZE, NULL, 0,
  102. hv_uio_channel_cb, pdata);
  103. if (ret)
  104. goto fail;
  105. dev->channel->inbound.ring_buffer->interrupt_mask = 1;
  106. dev->channel->batched_reading = false;
  107. /* Fill general uio info */
  108. pdata->info.name = "uio_hv_generic";
  109. pdata->info.version = DRIVER_VERSION;
  110. pdata->info.irqcontrol = hv_uio_irqcontrol;
  111. pdata->info.mmap = hv_uio_mmap;
  112. pdata->info.irq = UIO_IRQ_CUSTOM;
  113. /* mem resources */
  114. pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings";
  115. pdata->info.mem[TXRX_RING_MAP].addr
  116. = virt_to_phys(dev->channel->ringbuffer_pages);
  117. pdata->info.mem[TXRX_RING_MAP].size
  118. = dev->channel->ringbuffer_pagecount * PAGE_SIZE;
  119. pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL;
  120. pdata->info.mem[INT_PAGE_MAP].name = "int_page";
  121. pdata->info.mem[INT_PAGE_MAP].addr =
  122. virt_to_phys(vmbus_connection.int_page);
  123. pdata->info.mem[INT_PAGE_MAP].size = PAGE_SIZE;
  124. pdata->info.mem[INT_PAGE_MAP].memtype = UIO_MEM_LOGICAL;
  125. pdata->info.mem[MON_PAGE_MAP].name = "monitor_pages";
  126. pdata->info.mem[MON_PAGE_MAP].addr =
  127. virt_to_phys(vmbus_connection.monitor_pages[1]);
  128. pdata->info.mem[MON_PAGE_MAP].size = PAGE_SIZE;
  129. pdata->info.mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL;
  130. pdata->info.priv = pdata;
  131. pdata->device = dev;
  132. ret = uio_register_device(&dev->device, &pdata->info);
  133. if (ret) {
  134. dev_err(&dev->device, "hv_uio register failed\n");
  135. goto fail_close;
  136. }
  137. hv_set_drvdata(dev, pdata);
  138. return 0;
  139. fail_close:
  140. vmbus_close(dev->channel);
  141. fail:
  142. kfree(pdata);
  143. return ret;
  144. }
  145. static int
  146. hv_uio_remove(struct hv_device *dev)
  147. {
  148. struct hv_uio_private_data *pdata = hv_get_drvdata(dev);
  149. if (!pdata)
  150. return 0;
  151. uio_unregister_device(&pdata->info);
  152. hv_set_drvdata(dev, NULL);
  153. vmbus_close(dev->channel);
  154. kfree(pdata);
  155. return 0;
  156. }
  157. static struct hv_driver hv_uio_drv = {
  158. .name = "uio_hv_generic",
  159. .id_table = NULL, /* only dynamic id's */
  160. .probe = hv_uio_probe,
  161. .remove = hv_uio_remove,
  162. };
  163. static int __init
  164. hyperv_module_init(void)
  165. {
  166. return vmbus_driver_register(&hv_uio_drv);
  167. }
  168. static void __exit
  169. hyperv_module_exit(void)
  170. {
  171. vmbus_driver_unregister(&hv_uio_drv);
  172. }
  173. module_init(hyperv_module_init);
  174. module_exit(hyperv_module_exit);
  175. MODULE_VERSION(DRIVER_VERSION);
  176. MODULE_LICENSE("GPL v2");
  177. MODULE_AUTHOR(DRIVER_AUTHOR);
  178. MODULE_DESCRIPTION(DRIVER_DESC);