infini_fpga.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
  3. * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
  4. *
  5. * This software is available to you under a choice of one of two
  6. * licenses. You may choose to be licensed under the terms of the GNU
  7. * General Public License (GPL) Version 2, available from the file
  8. * COPYING in the main directory of this source tree, or the
  9. * OpenIB.org BSD license below:
  10. *
  11. * Redistribution and use in source and binary forms, with or
  12. * without modification, are permitted provided that the following
  13. * conditions are met:
  14. *
  15. * - Redistributions of source code must retain the above
  16. * copyright notice, this list of conditions and the following
  17. * disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials
  22. * provided with the distribution.
  23. *
  24. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  28. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  29. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  30. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  31. * SOFTWARE.
  32. */
  33. #include <linux/mm.h>
  34. #include <linux/dma-mapping.h>
  35. #include <linux/module.h>
  36. #include <linux/init.h>
  37. #include <linux/slab.h>
  38. #include <linux/errno.h>
  39. #include <linux/export.h>
  40. #include <linux/hugetlb.h>
  41. #include <linux/atomic.h>
  42. #include <nv-p2p.h>
  43. #include <rdma/peer_mem.h>
  44. #include <linux/pcidriver.h>
  45. #define DRV_NAME "alps_mem"
  46. #define DRV_VERSION "1.0"
  47. #define DRV_RELDATE __DATE__
  48. #define peer_err(FMT, ARGS...) printk(KERN_ERR DRV_NAME " %s:%d " FMT, __FUNCTION__, __LINE__, ## ARGS)
  49. MODULE_AUTHOR("Timo Dritschler");
  50. MODULE_DESCRIPTION("ALPS pcie memory plug-in for Mellanox InfiniBand");
  51. MODULE_LICENSE("GPL 2.2");
  52. MODULE_VERSION(DRV_VERSION);
  53. #define GPU_PAGE_SHIFT 16
  54. #define GPU_PAGE_SIZE ((u64)1 << GPU_PAGE_SHIFT)
  55. #define GPU_PAGE_OFFSET (GPU_PAGE_SIZE-1)
  56. #define GPU_PAGE_MASK (~GPU_PAGE_OFFSET)
  57. invalidate_peer_memory mem_invalidate_callback;
  58. static void *reg_handle;
  59. struct nv_mem_context {
  60. struct nvidia_p2p_page_table *page_table;
  61. void *core_context;
  62. u64 page_virt_start;
  63. u64 page_virt_end;
  64. size_t mapped_size;
  65. unsigned long npages;
  66. unsigned long page_size;
  67. int is_callback;
  68. int sg_allocated;
  69. };
  70. static void nv_get_p2p_free_callback(void *data)
  71. {
  72. int ret = 0;
  73. struct nv_mem_context *nv_mem_context = (struct nv_mem_context *)data;
  74. struct nvidia_p2p_page_table *page_table = NULL;
  75. __module_get(THIS_MODULE);
  76. if (!nv_mem_context) {
  77. peer_err("nv_get_p2p_free_callback -- invalid nv_mem_context\n");
  78. goto out;
  79. }
  80. if (!nv_mem_context->page_table) {
  81. peer_err("nv_get_p2p_free_callback -- invalid page_table\n");
  82. goto out;
  83. }
  84. /* Save page_table locally to prevent it being freed as part of nv_mem_release
  85. in case it's called internally by that callback.
  86. */
  87. page_table = nv_mem_context->page_table;
  88. /* For now don't set nv_mem_context->page_table to NULL,
  89. * confirmed by NVIDIA that inflight put_pages with valid pointer will fail gracefully.
  90. */
  91. ACCESS_ONCE(nv_mem_context->is_callback) = 1;
  92. (*mem_invalidate_callback) (reg_handle, nv_mem_context->core_context);
  93. ret = nvidia_p2p_free_page_table(page_table);
  94. if (ret)
  95. peer_err("nv_get_p2p_free_callback -- error %d while calling nvidia_p2p_free_page_table()\n", ret);
  96. out:
  97. module_put(THIS_MODULE);
  98. return;
  99. }
  100. /* At that function we don't call IB core - no ticket exists */
  101. static void nv_mem_dummy_callback(void *data)
  102. {
  103. struct nv_mem_context *nv_mem_context = (struct nv_mem_context *)data;
  104. int ret = 0;
  105. __module_get(THIS_MODULE);
  106. ret = nvidia_p2p_free_page_table(nv_mem_context->page_table);
  107. if (ret)
  108. peer_err("nv_mem_dummy_callback -- error %d while calling nvidia_p2p_free_page_table()\n", ret);
  109. module_put(THIS_MODULE);
  110. return;
  111. }
  112. /* acquire return code: 1 mine, 0 - not mine */
  113. static int nv_mem_acquire(unsigned long addr, size_t size, void *peer_mem_private_data,
  114. char *peer_mem_name, void **client_context)
  115. {
  116. int ret = 0;
  117. struct nv_mem_context *nv_mem_context;
  118. nv_mem_context = kzalloc(sizeof *nv_mem_context, GFP_KERNEL);
  119. if (!nv_mem_context)
  120. /* Error case handled as not mine */
  121. return 0;
  122. nv_mem_context->page_virt_start = addr & GPU_PAGE_MASK;
  123. nv_mem_context->page_virt_end = (addr + size + GPU_PAGE_SIZE - 1) & GPU_PAGE_MASK;
  124. nv_mem_context->mapped_size = nv_mem_context->page_virt_end - nv_mem_context->page_virt_start;
  125. ret = nvidia_p2p_get_pages(0, 0, nv_mem_context->page_virt_start, nv_mem_context->mapped_size,
  126. &nv_mem_context->page_table, nv_mem_dummy_callback, nv_mem_context);
  127. if (ret < 0)
  128. goto err;
  129. ret = nvidia_p2p_put_pages(0, 0, nv_mem_context->page_virt_start,
  130. nv_mem_context->page_table);
  131. if (ret < 0) {
  132. /* Not expected, however in case callback was called on that buffer just before
  133. put pages we'll expect to fail gracefully (confirmed by NVIDIA) and return an error.
  134. */
  135. peer_err("nv_mem_acquire -- error %d while calling nvidia_p2p_put_pages()\n", ret);
  136. goto err;
  137. }
  138. /* 1 means mine */
  139. *client_context = nv_mem_context;
  140. __module_get(THIS_MODULE);
  141. return 1;
  142. err:
  143. kfree(nv_mem_context);
  144. /* Error case handled as not mine */
  145. return 0;
  146. }
  147. static int nv_dma_map(struct sg_table *sg_head, void *context,
  148. struct device *dma_device, int dmasync,
  149. int *nmap)
  150. {
  151. int i, ret;
  152. struct scatterlist *sg;
  153. struct nv_mem_context *nv_mem_context =
  154. (struct nv_mem_context *) context;
  155. struct nvidia_p2p_page_table *page_table = nv_mem_context->page_table;
  156. if (nv_mem_context->page_table->page_size != NVIDIA_P2P_PAGE_SIZE_64KB) {
  157. peer_err("nv_dma_map -- assumption of 64KB pages failed size_id=%u\n",
  158. nv_mem_context->page_table->page_size);
  159. return -EINVAL;
  160. }
  161. nv_mem_context->npages = PAGE_ALIGN(nv_mem_context->mapped_size) >>
  162. GPU_PAGE_SHIFT;
  163. if (nv_mem_context->page_table->entries != nv_mem_context->npages) {
  164. peer_err("nv_dma_map -- unexpected number of page table entries got=%u, expected=%lu\n",
  165. nv_mem_context->page_table->entries,
  166. nv_mem_context->npages);
  167. return -EINVAL;
  168. }
  169. ret = sg_alloc_table(sg_head, nv_mem_context->npages, GFP_KERNEL);
  170. if (ret)
  171. return ret;
  172. nv_mem_context->sg_allocated = 1;
  173. for_each_sg(sg_head->sgl, sg, nv_mem_context->npages, i) {
  174. sg_set_page(sg, NULL, nv_mem_context->page_size, 0);
  175. sg->dma_address = page_table->pages[i]->physical_address;
  176. sg->dma_length = nv_mem_context->page_size;
  177. }
  178. *nmap = nv_mem_context->npages;
  179. return 0;
  180. }
  181. static int nv_dma_unmap(struct sg_table *sg_head, void *context,
  182. struct device *dma_device)
  183. {
  184. return 0;
  185. }
  186. static void nv_mem_put_pages(struct sg_table *sg_head, void *context)
  187. {
  188. int ret = 0;
  189. struct nv_mem_context *nv_mem_context =
  190. (struct nv_mem_context *) context;
  191. if (ACCESS_ONCE(nv_mem_context->is_callback))
  192. goto out;
  193. ret = nvidia_p2p_put_pages(0, 0, nv_mem_context->page_virt_start,
  194. nv_mem_context->page_table);
  195. #ifdef _DEBUG_ONLY_
  196. /* Here we expect an error in real life cases that should be ignored - not printed.
  197. * (e.g. concurrent callback with that call)
  198. */
  199. if (ret < 0) {
  200. printk(KERN_ERR "error %d while calling nvidia_p2p_put_pages, page_table=%p \n",
  201. ret, nv_mem_context->page_table);
  202. }
  203. #endif
  204. out:
  205. if (nv_mem_context->sg_allocated)
  206. sg_free_table(sg_head);
  207. return;
  208. }
  209. static void nv_mem_release(void *context)
  210. {
  211. struct nv_mem_context *nv_mem_context =
  212. (struct nv_mem_context *) context;
  213. kfree(nv_mem_context);
  214. module_put(THIS_MODULE);
  215. return;
  216. }
  217. static int nv_mem_get_pages(unsigned long addr,
  218. size_t size, int write, int force,
  219. struct sg_table *sg_head,
  220. void *client_context,
  221. void *core_context)
  222. {
  223. int ret;
  224. struct nv_mem_context *nv_mem_context;
  225. nv_mem_context = (struct nv_mem_context *)client_context;
  226. if (!nv_mem_context)
  227. return -EINVAL;
  228. nv_mem_context->core_context = core_context;
  229. nv_mem_context->page_size = GPU_PAGE_SIZE;
  230. ret = nvidia_p2p_get_pages(0, 0, nv_mem_context->page_virt_start, nv_mem_context->mapped_size,
  231. &nv_mem_context->page_table, nv_get_p2p_free_callback, nv_mem_context);
  232. if (ret < 0) {
  233. peer_err("nv_mem_get_pages -- error %d while calling nvidia_p2p_get_pages()\n", ret);
  234. return ret;
  235. }
  236. /* No extra access to nv_mem_context->page_table here as we are
  237. called not under a lock and may race with inflight invalidate callback on that buffer.
  238. Extra handling was delayed to be done under nv_dma_map.
  239. */
  240. return 0;
  241. }
  242. static unsigned long nv_mem_get_page_size(void *context)
  243. {
  244. struct nv_mem_context *nv_mem_context =
  245. (struct nv_mem_context *)context;
  246. return nv_mem_context->page_size;
  247. }
  248. static struct peer_memory_client nv_mem_client = {
  249. .acquire = nv_mem_acquire,
  250. .get_pages = nv_mem_get_pages,
  251. .dma_map = nv_dma_map,
  252. .dma_unmap = nv_dma_unmap,
  253. .put_pages = nv_mem_put_pages,
  254. .get_page_size = nv_mem_get_page_size,
  255. .release = nv_mem_release,
  256. };
  257. static int __init nv_mem_client_init(void)
  258. {
  259. strcpy(nv_mem_client.name, DRV_NAME);
  260. strcpy(nv_mem_client.version, DRV_VERSION);
  261. reg_handle = ib_register_peer_memory_client(&nv_mem_client,
  262. &mem_invalidate_callback);
  263. if (!reg_handle)
  264. return -EINVAL;
  265. return 0;
  266. }
  267. static void __exit nv_mem_client_cleanup(void)
  268. {
  269. ib_unregister_peer_memory_client(reg_handle);
  270. }
  271. module_init(nv_mem_client_init);
  272. module_exit(nv_mem_client_cleanup);