Initial repository content import
[opteya:ib-hw-nes-create-qp-null.git] / ib-hw-nes-create-qp-null.c
1 /* ib-hw-nes-create-qp-null.c - make nes driver return NULL
2  *
3  * Copyright (c) 2014 OPTEYA SAS
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  * Author: Yann Droneaud <ydroneaud@opteya.com>
34  *
35  */
36
37 #if HAVE_CONFIG_H
38 #  include <config.h>
39 #endif
40
41 #include <stddef.h>
42 #include <stdint.h>
43
44 #include <stdio.h>
45
46 #include <errno.h>
47 #include <string.h>
48
49 #include <sys/mman.h>
50 #include <unistd.h>
51
52 #include <assert.h>
53
54 #include <infiniband/kern-abi.h>
55 #include <infiniband/verbs.h>
56
57 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
58
59 /* from libibverbs, file src/ibverbs.h  */
60 #define IBV_INIT_CMD(cmd, size, opcode)                 \
61 do {                                                    \
62         (cmd)->command = IB_USER_VERBS_CMD_##opcode;    \
63         (cmd)->in_words  = (size) / 4;                  \
64         (cmd)->out_words = 0;                           \
65 } while (0)
66
67 #define IBV_INIT_CMD_RESP(cmd, size, opcode, out, outsize)      \
68 do {                                                            \
69         (cmd)->command = IB_USER_VERBS_CMD_##opcode;            \
70         (cmd)->in_words  = (size) / 4;                          \
71         (cmd)->out_words = (outsize) / 4;                       \
72         (cmd)->response  = (uintptr_t) (out);                   \
73 } while (0)
74
75 /* Need 5 pages [M M M] */
76 #define PAGES_COUNT 5
77
78 #if 0
79 /* define UNMAPPED_RESPONSE to make it impossible to uverbs
80  * to return the result (if any) of qp creation:
81  * in this case, it will make uverbs_create_qp() call
82  * ib_destroy_qp() on NULL, but only if a page were mapped
83  * at 0x0.
84  */
85 #define UNMAPPED_RESPONSE 1
86 #endif
87
88 int
89 main(void)
90 {
91         struct ibv_context *context;
92         struct ibv_device **dev_list;
93         int dev_count;
94
95         struct ibv_create_qp       create_qp_cmd;
96         struct ibv_create_qp      *create_qp_cmd_ptr;
97         struct ibv_create_qp_resp  create_qp_resp;
98         struct ibv_create_qp_resp *create_qp_resp_ptr;
99
100         struct ibv_destroy_qp      destroy_qp_cmd;
101         struct ibv_destroy_qp_resp destroy_qp_resp;
102
103         struct ibv_pd *pd;
104         struct ibv_cq *cq;
105
106         uint8_t *pages_mmap[PAGES_COUNT];
107
108         unsigned int i;
109
110         int err;
111         int ret;
112         ssize_t sret;
113
114         long size;
115         size_t page_size;
116
117         size = sysconf(_SC_PAGESIZE);
118         if (size < 0) {
119                 err = errno;
120                 fprintf(stderr, "Failed to get page size: %d (%s)\n", err, strerror(errno));
121                 return 1;
122         }
123
124         page_size = (size_t) size;
125
126         assert(page_size >= sizeof(struct ibv_create_qp));
127         assert(page_size >= sizeof(struct ibv_create_qp_resp));
128
129         dev_count = 0;
130         dev_list = ibv_get_device_list(&dev_count);
131         if (dev_list == NULL) {
132                 fprintf(stderr, "No infiniband/RDMA support ?\n");
133                 goto leave0;
134         }
135
136         if (dev_count <= 0) {
137                 fprintf(stderr, "No infiniband/RDMA adapter\n");
138                 goto leave1;
139         }
140
141         printf("Opening %s\n", ibv_get_device_name(dev_list[0]));
142
143         context = ibv_open_device(dev_list[0]);
144         if (context == NULL) {
145                 fprintf(stderr, "Failed to open first infiniband/RDMA adapter\n");
146                 goto leave1;
147         }
148
149         pd = ibv_alloc_pd(context);
150         if (pd == NULL) {
151                 fprintf(stderr, "Can't allocate protection domain\n");
152                 goto leave2;
153         }
154
155         cq = ibv_create_cq(context, 1, NULL, NULL, 0);
156         if (cq == NULL) {
157                 fprintf(stderr, "Can't create completion queue\n");
158                 goto leave3;
159         }
160
161         /* allocate some pages [MMMMM] */
162         pages_mmap[0] = mmap(NULL,
163                              ARRAY_SIZE(pages_mmap) * page_size,
164                              PROT_READ | PROT_WRITE,
165                              MAP_PRIVATE | MAP_ANONYMOUS,
166                              -1, 0);
167         if (pages_mmap[0] == MAP_FAILED) {
168                 err = errno;
169                 fprintf(stderr, "mmap() failed: %d (%s)\n", err, strerror(err));
170                 goto leave4;
171         }
172
173         assert(pages_mmap[0] != NULL); /* having pages @ 0x0 will make thing worse */
174
175         printf("Memory mapped @ %p [page 0]\n", pages_mmap[0]);
176
177         for(i = 1; i < ARRAY_SIZE(pages_mmap); i++) {
178                 pages_mmap[i] = pages_mmap[i - 1] + page_size;
179                 printf("              @ %p [page %u]\n", pages_mmap[i], i);
180         }
181
182         /* create holes [M M M] */
183         for(i = 1; i < ARRAY_SIZE(pages_mmap); i += 2) {
184
185                 printf("    Unmapping @ %p [page %u]\n", pages_mmap[i], i);
186
187                 ret = mprotect(pages_mmap[i], page_size, PROT_NONE);
188                 if (ret != 0) {
189                         err = errno;
190                         fprintf(stderr, "mprotect() failed: %d (%s)\n", err, strerror(err));
191                         goto leave5;
192                 }
193 #if 1
194                 ret = munmap(pages_mmap[i], page_size);
195                 if (ret != 0) {
196                         err = errno;
197                         fprintf(stderr, "munmap() failed: %d (%s)\n", err, strerror(err));
198                         goto leave5;
199                 }
200 #endif
201         }
202
203 #if defined(UNMAPPED_RESPONSE)
204         /* response buffer, in hole */
205         create_qp_resp_ptr = (struct ibv_create_qp_resp *)pages_mmap[3];
206         printf("Using unmmaped page @ %p [page %u] for response\n", pages_mmap[3], 3);
207         printf("           Response @ %p [page %u]\n", create_qp_resp_ptr, 3);
208 #else
209         /* response buffer on hole boundary */
210         create_qp_resp_ptr = (struct ibv_create_qp_resp *)(pages_mmap[3] - sizeof(struct ibv_create_qp_resp));
211         printf("Using unmmaped page @ %p [page %u] for response\n", pages_mmap[3], 3);
212         printf("           Response @ %p [page %u]\n", create_qp_resp_ptr, 2);
213 #endif
214
215         /* set up command: no provider (eg. hw) specific command fields included */
216         IBV_INIT_CMD_RESP(&create_qp_cmd, sizeof(struct ibv_create_qp),
217                           CREATE_QP,
218                           create_qp_resp_ptr, sizeof(struct ibv_create_qp_resp));
219
220         create_qp_cmd.user_handle = getpid(); /* not used kernel side ? */
221
222         create_qp_cmd.pd_handle = pd->handle;
223
224         create_qp_cmd.send_cq_handle = cq->handle;
225         create_qp_cmd.recv_cq_handle = cq->handle;
226
227         create_qp_cmd.srq_handle = 0;
228
229         create_qp_cmd.max_send_wr = 1;
230         create_qp_cmd.max_recv_wr = 1;
231         create_qp_cmd.max_send_sge = 1;
232         create_qp_cmd.max_recv_sge = 1;
233         create_qp_cmd.max_inline_data = 0;
234
235         create_qp_cmd.sq_sig_all = 0;
236         create_qp_cmd.qp_type = IBV_QPT_RC;
237         create_qp_cmd.is_srq = 0;
238         create_qp_cmd.reserved = 0;
239
240         /* command buffer, at hole boundary */
241         create_qp_cmd_ptr = (struct ibv_create_qp *)(pages_mmap[1] - sizeof(struct ibv_create_qp));
242         printf("Using unmmaped page @ %p [page %u] for command\n", pages_mmap[1], 1);
243         printf("            Command @ %p [page %u]\n", create_qp_cmd_ptr, 0);
244
245         /* copy command at end of page */
246         memcpy(create_qp_cmd_ptr, &create_qp_cmd, sizeof(struct ibv_create_qp));
247
248         printf("CREATE_QP : ");
249
250         errno = 0;
251         sret = write(context->cmd_fd, create_qp_cmd_ptr, sizeof(struct ibv_create_qp));
252         err = errno;
253
254         printf(" sret = %zi errno = %d : ", sret, err);
255         if (sret == sizeof(struct ibv_create_qp)) {
256                 printf(" SUCCESS\n");
257         } else {
258                 printf(" FAILURE\n");
259                 goto leave5;
260         }
261
262 #if !defined(UNMAPPED_RESPONSE)
263         /* copy response from end of page */
264         memcpy(&create_qp_resp, create_qp_resp_ptr, sizeof(struct ibv_create_qp_resp));
265
266         /* destroy the QP which could have been created */
267         IBV_INIT_CMD_RESP(&destroy_qp_cmd, sizeof(struct ibv_destroy_qp),
268                           DESTROY_QP,
269                           &destroy_qp_resp, sizeof(struct ibv_destroy_qp_resp));
270
271         destroy_qp_cmd.qp_handle = create_qp_resp.qp_handle;
272         destroy_qp_cmd.reserved = 0;
273
274         printf("DESTROY_QP : ");
275
276         errno = 0;
277         sret = write(context->cmd_fd, &destroy_qp_cmd, sizeof(struct ibv_destroy_qp));
278         err = errno;
279
280         printf(" sret = %zi, errno = %d : ", sret, err);
281         if (sret == sizeof(struct ibv_destroy_qp)) {
282                 printf(" SUCCESS\n");
283         } else {
284                 printf(" FAILURE\n");
285         }
286 #endif /* !defined(UNMAPPED_RESPONSE) */
287
288 leave5:
289         munmap(pages_mmap[0], ARRAY_SIZE(pages_mmap) * page_size);
290
291 leave4:
292         ibv_destroy_cq(cq);
293
294 leave3:
295         ibv_dealloc_pd(pd);
296
297 leave2:
298         ibv_close_device(context);
299
300 leave1:
301         ibv_free_device_list(dev_list);
302
303 leave0:
304         return 0;
305 }