net/mlx4: support secondary process
[dpdk.git] / drivers / net / mlx4 / mlx4.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2012 6WIND S.A.
3  * Copyright 2012 Mellanox Technologies, Ltd
4  */
5
6 /**
7  * @file
8  * mlx4 driver initialization.
9  */
10
11 #include <assert.h>
12 #include <dlfcn.h>
13 #include <errno.h>
14 #include <inttypes.h>
15 #include <stddef.h>
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/mman.h>
21 #include <unistd.h>
22
23 /* Verbs headers do not support -pedantic. */
24 #ifdef PEDANTIC
25 #pragma GCC diagnostic ignored "-Wpedantic"
26 #endif
27 #include <infiniband/verbs.h>
28 #ifdef PEDANTIC
29 #pragma GCC diagnostic error "-Wpedantic"
30 #endif
31
32 #include <rte_common.h>
33 #include <rte_config.h>
34 #include <rte_dev.h>
35 #include <rte_errno.h>
36 #include <rte_ethdev_driver.h>
37 #include <rte_ethdev_pci.h>
38 #include <rte_ether.h>
39 #include <rte_flow.h>
40 #include <rte_interrupts.h>
41 #include <rte_kvargs.h>
42 #include <rte_malloc.h>
43 #include <rte_mbuf.h>
44
45 #include "mlx4.h"
46 #include "mlx4_glue.h"
47 #include "mlx4_flow.h"
48 #include "mlx4_mr.h"
49 #include "mlx4_rxtx.h"
50 #include "mlx4_utils.h"
51
52 static const char *MZ_MLX4_PMD_SHARED_DATA = "mlx4_pmd_shared_data";
53
54 /* Shared memory between primary and secondary processes. */
55 struct mlx4_shared_data *mlx4_shared_data;
56
57 /* Spinlock for mlx4_shared_data allocation. */
58 static rte_spinlock_t mlx4_shared_data_lock = RTE_SPINLOCK_INITIALIZER;
59
60 /* Process local data for secondary processes. */
61 static struct mlx4_local_data mlx4_local_data;
62
63 /** Configuration structure for device arguments. */
64 struct mlx4_conf {
65         struct {
66                 uint32_t present; /**< Bit-field for existing ports. */
67                 uint32_t enabled; /**< Bit-field for user-enabled ports. */
68         } ports;
69 };
70
71 /* Available parameters list. */
72 const char *pmd_mlx4_init_params[] = {
73         MLX4_PMD_PORT_KVARG,
74         NULL,
75 };
76
77 static void mlx4_dev_stop(struct rte_eth_dev *dev);
78
79 /**
80  * Initialize shared data between primary and secondary process.
81  *
82  * A memzone is reserved by primary process and secondary processes attach to
83  * the memzone.
84  *
85  * @return
86  *   0 on success, a negative errno value otherwise and rte_errno is set.
87  */
88 static int
89 mlx4_init_shared_data(void)
90 {
91         const struct rte_memzone *mz;
92         int ret = 0;
93
94         rte_spinlock_lock(&mlx4_shared_data_lock);
95         if (mlx4_shared_data == NULL) {
96                 if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
97                         /* Allocate shared memory. */
98                         mz = rte_memzone_reserve(MZ_MLX4_PMD_SHARED_DATA,
99                                                  sizeof(*mlx4_shared_data),
100                                                  SOCKET_ID_ANY, 0);
101                         if (mz == NULL) {
102                                 ERROR("Cannot allocate mlx4 shared data\n");
103                                 ret = -rte_errno;
104                                 goto error;
105                         }
106                         mlx4_shared_data = mz->addr;
107                         memset(mlx4_shared_data, 0, sizeof(*mlx4_shared_data));
108                         rte_spinlock_init(&mlx4_shared_data->lock);
109                 } else {
110                         /* Lookup allocated shared memory. */
111                         mz = rte_memzone_lookup(MZ_MLX4_PMD_SHARED_DATA);
112                         if (mz == NULL) {
113                                 ERROR("Cannot attach mlx4 shared data\n");
114                                 ret = -rte_errno;
115                                 goto error;
116                         }
117                         mlx4_shared_data = mz->addr;
118                         memset(&mlx4_local_data, 0, sizeof(mlx4_local_data));
119                 }
120         }
121 error:
122         rte_spinlock_unlock(&mlx4_shared_data_lock);
123         return ret;
124 }
125
126 /**
127  * Uninitialize shared data between primary and secondary process.
128  *
129  * The pointer of secondary process is dereferenced and primary process frees
130  * the memzone.
131  */
132 static void
133 mlx4_uninit_shared_data(void)
134 {
135         const struct rte_memzone *mz;
136
137         rte_spinlock_lock(&mlx4_shared_data_lock);
138         if (mlx4_shared_data) {
139                 if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
140                         mz = rte_memzone_lookup(MZ_MLX4_PMD_SHARED_DATA);
141                         rte_memzone_free(mz);
142                 } else {
143                         memset(&mlx4_local_data, 0, sizeof(mlx4_local_data));
144                 }
145                 mlx4_shared_data = NULL;
146         }
147         rte_spinlock_unlock(&mlx4_shared_data_lock);
148 }
149
150 #ifdef HAVE_IBV_MLX4_BUF_ALLOCATORS
151 /**
152  * Verbs callback to allocate a memory. This function should allocate the space
153  * according to the size provided residing inside a huge page.
154  * Please note that all allocation must respect the alignment from libmlx4
155  * (i.e. currently sysconf(_SC_PAGESIZE)).
156  *
157  * @param[in] size
158  *   The size in bytes of the memory to allocate.
159  * @param[in] data
160  *   A pointer to the callback data.
161  *
162  * @return
163  *   Allocated buffer, NULL otherwise and rte_errno is set.
164  */
165 static void *
166 mlx4_alloc_verbs_buf(size_t size, void *data)
167 {
168         struct mlx4_priv *priv = data;
169         void *ret;
170         size_t alignment = sysconf(_SC_PAGESIZE);
171         unsigned int socket = SOCKET_ID_ANY;
172
173         if (priv->verbs_alloc_ctx.type == MLX4_VERBS_ALLOC_TYPE_TX_QUEUE) {
174                 const struct txq *txq = priv->verbs_alloc_ctx.obj;
175
176                 socket = txq->socket;
177         } else if (priv->verbs_alloc_ctx.type ==
178                    MLX4_VERBS_ALLOC_TYPE_RX_QUEUE) {
179                 const struct rxq *rxq = priv->verbs_alloc_ctx.obj;
180
181                 socket = rxq->socket;
182         }
183         assert(data != NULL);
184         ret = rte_malloc_socket(__func__, size, alignment, socket);
185         if (!ret && size)
186                 rte_errno = ENOMEM;
187         return ret;
188 }
189
190 /**
191  * Verbs callback to free a memory.
192  *
193  * @param[in] ptr
194  *   A pointer to the memory to free.
195  * @param[in] data
196  *   A pointer to the callback data.
197  */
198 static void
199 mlx4_free_verbs_buf(void *ptr, void *data __rte_unused)
200 {
201         assert(data != NULL);
202         rte_free(ptr);
203 }
204 #endif
205
206 /**
207  * DPDK callback for Ethernet device configuration.
208  *
209  * @param dev
210  *   Pointer to Ethernet device structure.
211  *
212  * @return
213  *   0 on success, negative errno value otherwise and rte_errno is set.
214  */
215 static int
216 mlx4_dev_configure(struct rte_eth_dev *dev)
217 {
218         struct mlx4_priv *priv = dev->data->dev_private;
219         struct rte_flow_error error;
220         int ret;
221
222         /* Prepare internal flow rules. */
223         ret = mlx4_flow_sync(priv, &error);
224         if (ret) {
225                 ERROR("cannot set up internal flow rules (code %d, \"%s\"),"
226                       " flow error type %d, cause %p, message: %s",
227                       -ret, strerror(-ret), error.type, error.cause,
228                       error.message ? error.message : "(unspecified)");
229                 goto exit;
230         }
231         ret = mlx4_intr_install(priv);
232         if (ret)
233                 ERROR("%p: interrupt handler installation failed",
234                       (void *)dev);
235 exit:
236         return ret;
237 }
238
239 /**
240  * DPDK callback to start the device.
241  *
242  * Simulate device start by initializing common RSS resources and attaching
243  * all configured flows.
244  *
245  * @param dev
246  *   Pointer to Ethernet device structure.
247  *
248  * @return
249  *   0 on success, negative errno value otherwise and rte_errno is set.
250  */
251 static int
252 mlx4_dev_start(struct rte_eth_dev *dev)
253 {
254         struct mlx4_priv *priv = dev->data->dev_private;
255         struct rte_flow_error error;
256         int ret;
257
258         if (priv->started)
259                 return 0;
260         DEBUG("%p: attaching configured flows to all RX queues", (void *)dev);
261         priv->started = 1;
262         ret = mlx4_tx_uar_remap(dev, priv->ctx->cmd_fd);
263         if (ret) {
264                 ERROR("%p: cannot remap UAR", (void *)dev);
265                 goto err;
266         }
267         ret = mlx4_rss_init(priv);
268         if (ret) {
269                 ERROR("%p: cannot initialize RSS resources: %s",
270                       (void *)dev, strerror(-ret));
271                 goto err;
272         }
273 #ifndef NDEBUG
274         mlx4_mr_dump_dev(dev);
275 #endif
276         ret = mlx4_rxq_intr_enable(priv);
277         if (ret) {
278                 ERROR("%p: interrupt handler installation failed",
279                      (void *)dev);
280                 goto err;
281         }
282         ret = mlx4_flow_sync(priv, &error);
283         if (ret) {
284                 ERROR("%p: cannot attach flow rules (code %d, \"%s\"),"
285                       " flow error type %d, cause %p, message: %s",
286                       (void *)dev,
287                       -ret, strerror(-ret), error.type, error.cause,
288                       error.message ? error.message : "(unspecified)");
289                 goto err;
290         }
291         rte_wmb();
292         dev->tx_pkt_burst = mlx4_tx_burst;
293         dev->rx_pkt_burst = mlx4_rx_burst;
294         /* Enable datapath on secondary process. */
295         mlx4_mp_req_start_rxtx(dev);
296         return 0;
297 err:
298         mlx4_dev_stop(dev);
299         return ret;
300 }
301
302 /**
303  * DPDK callback to stop the device.
304  *
305  * Simulate device stop by detaching all configured flows.
306  *
307  * @param dev
308  *   Pointer to Ethernet device structure.
309  */
310 static void
311 mlx4_dev_stop(struct rte_eth_dev *dev)
312 {
313         struct mlx4_priv *priv = dev->data->dev_private;
314         const size_t page_size = sysconf(_SC_PAGESIZE);
315         int i;
316
317         if (!priv->started)
318                 return;
319         DEBUG("%p: detaching flows from all RX queues", (void *)dev);
320         priv->started = 0;
321         dev->tx_pkt_burst = mlx4_tx_burst_removed;
322         dev->rx_pkt_burst = mlx4_rx_burst_removed;
323         rte_wmb();
324         /* Disable datapath on secondary process. */
325         mlx4_mp_req_stop_rxtx(dev);
326         mlx4_flow_sync(priv, NULL);
327         mlx4_rxq_intr_disable(priv);
328         mlx4_rss_deinit(priv);
329         for (i = 0; i != dev->data->nb_tx_queues; ++i) {
330                 struct txq *txq;
331
332                 txq = dev->data->tx_queues[i];
333                 if (!txq)
334                         continue;
335                 munmap((void *)RTE_ALIGN_FLOOR((uintptr_t)txq->msq.db,
336                                                page_size), page_size);
337         }
338 }
339
340 /**
341  * DPDK callback to close the device.
342  *
343  * Destroy all queues and objects, free memory.
344  *
345  * @param dev
346  *   Pointer to Ethernet device structure.
347  */
348 static void
349 mlx4_dev_close(struct rte_eth_dev *dev)
350 {
351         struct mlx4_priv *priv = dev->data->dev_private;
352         unsigned int i;
353
354         DEBUG("%p: closing device \"%s\"",
355               (void *)dev,
356               ((priv->ctx != NULL) ? priv->ctx->device->name : ""));
357         dev->rx_pkt_burst = mlx4_rx_burst_removed;
358         dev->tx_pkt_burst = mlx4_tx_burst_removed;
359         rte_wmb();
360         /* Disable datapath on secondary process. */
361         mlx4_mp_req_stop_rxtx(dev);
362         mlx4_flow_clean(priv);
363         mlx4_rss_deinit(priv);
364         for (i = 0; i != dev->data->nb_rx_queues; ++i)
365                 mlx4_rx_queue_release(dev->data->rx_queues[i]);
366         for (i = 0; i != dev->data->nb_tx_queues; ++i)
367                 mlx4_tx_queue_release(dev->data->tx_queues[i]);
368         mlx4_mr_release(dev);
369         if (priv->pd != NULL) {
370                 assert(priv->ctx != NULL);
371                 claim_zero(mlx4_glue->dealloc_pd(priv->pd));
372                 claim_zero(mlx4_glue->close_device(priv->ctx));
373         } else
374                 assert(priv->ctx == NULL);
375         mlx4_intr_uninstall(priv);
376         memset(priv, 0, sizeof(*priv));
377 }
378
379 static const struct eth_dev_ops mlx4_dev_ops = {
380         .dev_configure = mlx4_dev_configure,
381         .dev_start = mlx4_dev_start,
382         .dev_stop = mlx4_dev_stop,
383         .dev_set_link_down = mlx4_dev_set_link_down,
384         .dev_set_link_up = mlx4_dev_set_link_up,
385         .dev_close = mlx4_dev_close,
386         .link_update = mlx4_link_update,
387         .promiscuous_enable = mlx4_promiscuous_enable,
388         .promiscuous_disable = mlx4_promiscuous_disable,
389         .allmulticast_enable = mlx4_allmulticast_enable,
390         .allmulticast_disable = mlx4_allmulticast_disable,
391         .mac_addr_remove = mlx4_mac_addr_remove,
392         .mac_addr_add = mlx4_mac_addr_add,
393         .mac_addr_set = mlx4_mac_addr_set,
394         .stats_get = mlx4_stats_get,
395         .stats_reset = mlx4_stats_reset,
396         .fw_version_get = mlx4_fw_version_get,
397         .dev_infos_get = mlx4_dev_infos_get,
398         .dev_supported_ptypes_get = mlx4_dev_supported_ptypes_get,
399         .vlan_filter_set = mlx4_vlan_filter_set,
400         .rx_queue_setup = mlx4_rx_queue_setup,
401         .tx_queue_setup = mlx4_tx_queue_setup,
402         .rx_queue_release = mlx4_rx_queue_release,
403         .tx_queue_release = mlx4_tx_queue_release,
404         .flow_ctrl_get = mlx4_flow_ctrl_get,
405         .flow_ctrl_set = mlx4_flow_ctrl_set,
406         .mtu_set = mlx4_mtu_set,
407         .filter_ctrl = mlx4_filter_ctrl,
408         .rx_queue_intr_enable = mlx4_rx_intr_enable,
409         .rx_queue_intr_disable = mlx4_rx_intr_disable,
410         .is_removed = mlx4_is_removed,
411 };
412
413 /* Available operations from secondary process. */
414 static const struct eth_dev_ops mlx4_dev_sec_ops = {
415         .stats_get = mlx4_stats_get,
416         .stats_reset = mlx4_stats_reset,
417         .fw_version_get = mlx4_fw_version_get,
418         .dev_infos_get = mlx4_dev_infos_get,
419 };
420
421 /**
422  * Get PCI information from struct ibv_device.
423  *
424  * @param device
425  *   Pointer to Ethernet device structure.
426  * @param[out] pci_addr
427  *   PCI bus address output buffer.
428  *
429  * @return
430  *   0 on success, negative errno value otherwise and rte_errno is set.
431  */
432 static int
433 mlx4_ibv_device_to_pci_addr(const struct ibv_device *device,
434                             struct rte_pci_addr *pci_addr)
435 {
436         FILE *file;
437         char line[32];
438         MKSTR(path, "%s/device/uevent", device->ibdev_path);
439
440         file = fopen(path, "rb");
441         if (file == NULL) {
442                 rte_errno = errno;
443                 return -rte_errno;
444         }
445         while (fgets(line, sizeof(line), file) == line) {
446                 size_t len = strlen(line);
447                 int ret;
448
449                 /* Truncate long lines. */
450                 if (len == (sizeof(line) - 1))
451                         while (line[(len - 1)] != '\n') {
452                                 ret = fgetc(file);
453                                 if (ret == EOF)
454                                         break;
455                                 line[(len - 1)] = ret;
456                         }
457                 /* Extract information. */
458                 if (sscanf(line,
459                            "PCI_SLOT_NAME="
460                            "%" SCNx32 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8 "\n",
461                            &pci_addr->domain,
462                            &pci_addr->bus,
463                            &pci_addr->devid,
464                            &pci_addr->function) == 4) {
465                         ret = 0;
466                         break;
467                 }
468         }
469         fclose(file);
470         return 0;
471 }
472
473 /**
474  * Verify and store value for device argument.
475  *
476  * @param[in] key
477  *   Key argument to verify.
478  * @param[in] val
479  *   Value associated with key.
480  * @param[in, out] conf
481  *   Shared configuration data.
482  *
483  * @return
484  *   0 on success, negative errno value otherwise and rte_errno is set.
485  */
486 static int
487 mlx4_arg_parse(const char *key, const char *val, struct mlx4_conf *conf)
488 {
489         unsigned long tmp;
490
491         errno = 0;
492         tmp = strtoul(val, NULL, 0);
493         if (errno) {
494                 rte_errno = errno;
495                 WARN("%s: \"%s\" is not a valid integer", key, val);
496                 return -rte_errno;
497         }
498         if (strcmp(MLX4_PMD_PORT_KVARG, key) == 0) {
499                 uint32_t ports = rte_log2_u32(conf->ports.present + 1);
500
501                 if (tmp >= ports) {
502                         ERROR("port index %lu outside range [0,%" PRIu32 ")",
503                               tmp, ports);
504                         return -EINVAL;
505                 }
506                 if (!(conf->ports.present & (1 << tmp))) {
507                         rte_errno = EINVAL;
508                         ERROR("invalid port index %lu", tmp);
509                         return -rte_errno;
510                 }
511                 conf->ports.enabled |= 1 << tmp;
512         } else {
513                 rte_errno = EINVAL;
514                 WARN("%s: unknown parameter", key);
515                 return -rte_errno;
516         }
517         return 0;
518 }
519
520 /**
521  * Parse device parameters.
522  *
523  * @param devargs
524  *   Device arguments structure.
525  *
526  * @return
527  *   0 on success, negative errno value otherwise and rte_errno is set.
528  */
529 static int
530 mlx4_args(struct rte_devargs *devargs, struct mlx4_conf *conf)
531 {
532         struct rte_kvargs *kvlist;
533         unsigned int arg_count;
534         int ret = 0;
535         int i;
536
537         if (devargs == NULL)
538                 return 0;
539         kvlist = rte_kvargs_parse(devargs->args, pmd_mlx4_init_params);
540         if (kvlist == NULL) {
541                 rte_errno = EINVAL;
542                 ERROR("failed to parse kvargs");
543                 return -rte_errno;
544         }
545         /* Process parameters. */
546         for (i = 0; pmd_mlx4_init_params[i]; ++i) {
547                 arg_count = rte_kvargs_count(kvlist, MLX4_PMD_PORT_KVARG);
548                 while (arg_count-- > 0) {
549                         ret = rte_kvargs_process(kvlist,
550                                                  MLX4_PMD_PORT_KVARG,
551                                                  (int (*)(const char *,
552                                                           const char *,
553                                                           void *))
554                                                  mlx4_arg_parse,
555                                                  conf);
556                         if (ret != 0)
557                                 goto free_kvlist;
558                 }
559         }
560 free_kvlist:
561         rte_kvargs_free(kvlist);
562         return ret;
563 }
564
565 /**
566  * Interpret RSS capabilities reported by device.
567  *
568  * This function returns the set of usable Verbs RSS hash fields, kernel
569  * quirks taken into account.
570  *
571  * @param ctx
572  *   Verbs context.
573  * @param pd
574  *   Verbs protection domain.
575  * @param device_attr_ex
576  *   Extended device attributes to interpret.
577  *
578  * @return
579  *   Usable RSS hash fields mask in Verbs format.
580  */
581 static uint64_t
582 mlx4_hw_rss_sup(struct ibv_context *ctx, struct ibv_pd *pd,
583                 struct ibv_device_attr_ex *device_attr_ex)
584 {
585         uint64_t hw_rss_sup = device_attr_ex->rss_caps.rx_hash_fields_mask;
586         struct ibv_cq *cq = NULL;
587         struct ibv_wq *wq = NULL;
588         struct ibv_rwq_ind_table *ind = NULL;
589         struct ibv_qp *qp = NULL;
590
591         if (!hw_rss_sup) {
592                 WARN("no RSS capabilities reported; disabling support for UDP"
593                      " RSS and inner VXLAN RSS");
594                 return IBV_RX_HASH_SRC_IPV4 | IBV_RX_HASH_DST_IPV4 |
595                         IBV_RX_HASH_SRC_IPV6 | IBV_RX_HASH_DST_IPV6 |
596                         IBV_RX_HASH_SRC_PORT_TCP | IBV_RX_HASH_DST_PORT_TCP;
597         }
598         if (!(hw_rss_sup & IBV_RX_HASH_INNER))
599                 return hw_rss_sup;
600         /*
601          * Although reported as supported, missing code in some Linux
602          * versions (v4.15, v4.16) prevents the creation of hash QPs with
603          * inner capability.
604          *
605          * There is no choice but to attempt to instantiate a temporary RSS
606          * context in order to confirm its support.
607          */
608         cq = mlx4_glue->create_cq(ctx, 1, NULL, NULL, 0);
609         wq = cq ? mlx4_glue->create_wq
610                 (ctx,
611                  &(struct ibv_wq_init_attr){
612                         .wq_type = IBV_WQT_RQ,
613                         .max_wr = 1,
614                         .max_sge = 1,
615                         .pd = pd,
616                         .cq = cq,
617                  }) : NULL;
618         ind = wq ? mlx4_glue->create_rwq_ind_table
619                 (ctx,
620                  &(struct ibv_rwq_ind_table_init_attr){
621                         .log_ind_tbl_size = 0,
622                         .ind_tbl = &wq,
623                         .comp_mask = 0,
624                  }) : NULL;
625         qp = ind ? mlx4_glue->create_qp_ex
626                 (ctx,
627                  &(struct ibv_qp_init_attr_ex){
628                         .comp_mask =
629                                 (IBV_QP_INIT_ATTR_PD |
630                                  IBV_QP_INIT_ATTR_RX_HASH |
631                                  IBV_QP_INIT_ATTR_IND_TABLE),
632                         .qp_type = IBV_QPT_RAW_PACKET,
633                         .pd = pd,
634                         .rwq_ind_tbl = ind,
635                         .rx_hash_conf = {
636                                 .rx_hash_function = IBV_RX_HASH_FUNC_TOEPLITZ,
637                                 .rx_hash_key_len = MLX4_RSS_HASH_KEY_SIZE,
638                                 .rx_hash_key = mlx4_rss_hash_key_default,
639                                 .rx_hash_fields_mask = hw_rss_sup,
640                         },
641                  }) : NULL;
642         if (!qp) {
643                 WARN("disabling unusable inner RSS capability due to kernel"
644                      " quirk");
645                 hw_rss_sup &= ~IBV_RX_HASH_INNER;
646         } else {
647                 claim_zero(mlx4_glue->destroy_qp(qp));
648         }
649         if (ind)
650                 claim_zero(mlx4_glue->destroy_rwq_ind_table(ind));
651         if (wq)
652                 claim_zero(mlx4_glue->destroy_wq(wq));
653         if (cq)
654                 claim_zero(mlx4_glue->destroy_cq(cq));
655         return hw_rss_sup;
656 }
657
658 static struct rte_pci_driver mlx4_driver;
659
660 static int
661 find_lower_va_bound(const struct rte_memseg_list *msl,
662                 const struct rte_memseg *ms, void *arg)
663 {
664         void **addr = arg;
665
666         if (msl->external)
667                 return 0;
668         if (*addr == NULL)
669                 *addr = ms->addr;
670         else
671                 *addr = RTE_MIN(*addr, ms->addr);
672
673         return 0;
674 }
675
676 /**
677  * Reserve UAR address space for primary process.
678  *
679  * Process local resource is used by both primary and secondary to avoid
680  * duplicate reservation. The space has to be available on both primary and
681  * secondary process, TXQ UAR maps to this area using fixed mmap w/o double
682  * check.
683  *
684  * @return
685  *   0 on success, a negative errno value otherwise and rte_errno is set.
686  */
687 static int
688 mlx4_uar_init_primary(void)
689 {
690         struct mlx4_shared_data *sd = mlx4_shared_data;
691         void *addr = (void *)0;
692
693         if (sd->uar_base)
694                 return 0;
695         /* find out lower bound of hugepage segments */
696         rte_memseg_walk(find_lower_va_bound, &addr);
697         /* keep distance to hugepages to minimize potential conflicts. */
698         addr = RTE_PTR_SUB(addr, (uintptr_t)(MLX4_UAR_OFFSET + MLX4_UAR_SIZE));
699         /* anonymous mmap, no real memory consumption. */
700         addr = mmap(addr, MLX4_UAR_SIZE,
701                     PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
702         if (addr == MAP_FAILED) {
703                 ERROR("failed to reserve UAR address space, please"
704                       " adjust MLX4_UAR_SIZE or try --base-virtaddr");
705                 rte_errno = ENOMEM;
706                 return -rte_errno;
707         }
708         /* Accept either same addr or a new addr returned from mmap if target
709          * range occupied.
710          */
711         INFO("reserved UAR address space: %p", addr);
712         sd->uar_base = addr; /* for primary and secondary UAR re-mmap. */
713         return 0;
714 }
715
716 /**
717  * Unmap UAR address space reserved for primary process.
718  */
719 static void
720 mlx4_uar_uninit_primary(void)
721 {
722         struct mlx4_shared_data *sd = mlx4_shared_data;
723
724         if (!sd->uar_base)
725                 return;
726         munmap(sd->uar_base, MLX4_UAR_SIZE);
727         sd->uar_base = NULL;
728 }
729
730 /**
731  * Reserve UAR address space for secondary process, align with primary process.
732  *
733  * @return
734  *   0 on success, a negative errno value otherwise and rte_errno is set.
735  */
736 static int
737 mlx4_uar_init_secondary(void)
738 {
739         struct mlx4_shared_data *sd = mlx4_shared_data;
740         struct mlx4_local_data *ld = &mlx4_local_data;
741         void *addr;
742
743         if (ld->uar_base) { /* Already reserved. */
744                 assert(sd->uar_base == ld->uar_base);
745                 return 0;
746         }
747         assert(sd->uar_base);
748         /* anonymous mmap, no real memory consumption. */
749         addr = mmap(sd->uar_base, MLX4_UAR_SIZE,
750                     PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
751         if (addr == MAP_FAILED) {
752                 ERROR("UAR mmap failed: %p size: %llu",
753                       sd->uar_base, MLX4_UAR_SIZE);
754                 rte_errno = ENXIO;
755                 return -rte_errno;
756         }
757         if (sd->uar_base != addr) {
758                 ERROR("UAR address %p size %llu occupied, please"
759                       " adjust MLX4_UAR_OFFSET or try EAL parameter"
760                       " --base-virtaddr",
761                       sd->uar_base, MLX4_UAR_SIZE);
762                 rte_errno = ENXIO;
763                 return -rte_errno;
764         }
765         ld->uar_base = addr;
766         INFO("reserved UAR address space: %p", addr);
767         return 0;
768 }
769
770 /**
771  * Unmap UAR address space reserved for secondary process.
772  */
773 static void
774 mlx4_uar_uninit_secondary(void)
775 {
776         struct mlx4_local_data *ld = &mlx4_local_data;
777
778         if (!ld->uar_base)
779                 return;
780         munmap(ld->uar_base, MLX4_UAR_SIZE);
781         ld->uar_base = NULL;
782 }
783
784 /**
785  * PMD global initialization.
786  *
787  * Independent from individual device, this function initializes global
788  * per-PMD data structures distinguishing primary and secondary processes.
789  * Hence, each initialization is called once per a process.
790  *
791  * @return
792  *   0 on success, a negative errno value otherwise and rte_errno is set.
793  */
794 static int
795 mlx4_init_once(void)
796 {
797         struct mlx4_shared_data *sd;
798         struct mlx4_local_data *ld = &mlx4_local_data;
799         int ret;
800
801         if (mlx4_init_shared_data())
802                 return -rte_errno;
803         sd = mlx4_shared_data;
804         assert(sd);
805         rte_spinlock_lock(&sd->lock);
806         switch (rte_eal_process_type()) {
807         case RTE_PROC_PRIMARY:
808                 if (sd->init_done)
809                         break;
810                 LIST_INIT(&sd->mem_event_cb_list);
811                 rte_rwlock_init(&sd->mem_event_rwlock);
812                 rte_mem_event_callback_register("MLX4_MEM_EVENT_CB",
813                                                 mlx4_mr_mem_event_cb, NULL);
814                 mlx4_mp_init_primary();
815                 ret = mlx4_uar_init_primary();
816                 if (ret)
817                         goto error;
818                 sd->init_done = true;
819                 break;
820         case RTE_PROC_SECONDARY:
821                 if (ld->init_done)
822                         break;
823                 mlx4_mp_init_secondary();
824                 ret = mlx4_uar_init_secondary();
825                 if (ret)
826                         goto error;
827                 ++sd->secondary_cnt;
828                 ld->init_done = true;
829                 break;
830         default:
831                 break;
832         }
833         rte_spinlock_unlock(&sd->lock);
834         return 0;
835 error:
836         switch (rte_eal_process_type()) {
837         case RTE_PROC_PRIMARY:
838                 mlx4_uar_uninit_primary();
839                 mlx4_mp_uninit_primary();
840                 rte_mem_event_callback_unregister("MLX4_MEM_EVENT_CB", NULL);
841                 break;
842         case RTE_PROC_SECONDARY:
843                 mlx4_uar_uninit_secondary();
844                 mlx4_mp_uninit_secondary();
845                 break;
846         default:
847                 break;
848         }
849         rte_spinlock_unlock(&sd->lock);
850         mlx4_uninit_shared_data();
851         return -rte_errno;
852 }
853
854 /**
855  * DPDK callback to register a PCI device.
856  *
857  * This function creates an Ethernet device for each port of a given
858  * PCI device.
859  *
860  * @param[in] pci_drv
861  *   PCI driver structure (mlx4_driver).
862  * @param[in] pci_dev
863  *   PCI device information.
864  *
865  * @return
866  *   0 on success, negative errno value otherwise and rte_errno is set.
867  */
868 static int
869 mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
870 {
871         struct ibv_device **list;
872         struct ibv_device *ibv_dev;
873         int err = 0;
874         struct ibv_context *attr_ctx = NULL;
875         struct ibv_device_attr device_attr;
876         struct ibv_device_attr_ex device_attr_ex;
877         struct mlx4_conf conf = {
878                 .ports.present = 0,
879         };
880         unsigned int vf;
881         int i;
882
883         (void)pci_drv;
884         err = mlx4_init_once();
885         if (err) {
886                 ERROR("unable to init PMD global data: %s",
887                       strerror(rte_errno));
888                 return -rte_errno;
889         }
890         assert(pci_drv == &mlx4_driver);
891         list = mlx4_glue->get_device_list(&i);
892         if (list == NULL) {
893                 rte_errno = errno;
894                 assert(rte_errno);
895                 if (rte_errno == ENOSYS)
896                         ERROR("cannot list devices, is ib_uverbs loaded?");
897                 return -rte_errno;
898         }
899         assert(i >= 0);
900         /*
901          * For each listed device, check related sysfs entry against
902          * the provided PCI ID.
903          */
904         while (i != 0) {
905                 struct rte_pci_addr pci_addr;
906
907                 --i;
908                 DEBUG("checking device \"%s\"", list[i]->name);
909                 if (mlx4_ibv_device_to_pci_addr(list[i], &pci_addr))
910                         continue;
911                 if ((pci_dev->addr.domain != pci_addr.domain) ||
912                     (pci_dev->addr.bus != pci_addr.bus) ||
913                     (pci_dev->addr.devid != pci_addr.devid) ||
914                     (pci_dev->addr.function != pci_addr.function))
915                         continue;
916                 vf = (pci_dev->id.device_id ==
917                       PCI_DEVICE_ID_MELLANOX_CONNECTX3VF);
918                 INFO("PCI information matches, using device \"%s\" (VF: %s)",
919                      list[i]->name, (vf ? "true" : "false"));
920                 attr_ctx = mlx4_glue->open_device(list[i]);
921                 err = errno;
922                 break;
923         }
924         if (attr_ctx == NULL) {
925                 mlx4_glue->free_device_list(list);
926                 switch (err) {
927                 case 0:
928                         rte_errno = ENODEV;
929                         ERROR("cannot access device, is mlx4_ib loaded?");
930                         return -rte_errno;
931                 case EINVAL:
932                         rte_errno = EINVAL;
933                         ERROR("cannot use device, are drivers up to date?");
934                         return -rte_errno;
935                 }
936                 assert(err > 0);
937                 rte_errno = err;
938                 return -rte_errno;
939         }
940         ibv_dev = list[i];
941         DEBUG("device opened");
942         if (mlx4_glue->query_device(attr_ctx, &device_attr)) {
943                 err = ENODEV;
944                 goto error;
945         }
946         INFO("%u port(s) detected", device_attr.phys_port_cnt);
947         conf.ports.present |= (UINT64_C(1) << device_attr.phys_port_cnt) - 1;
948         if (mlx4_args(pci_dev->device.devargs, &conf)) {
949                 ERROR("failed to process device arguments");
950                 err = EINVAL;
951                 goto error;
952         }
953         /* Use all ports when none are defined */
954         if (!conf.ports.enabled)
955                 conf.ports.enabled = conf.ports.present;
956         /* Retrieve extended device attributes. */
957         if (mlx4_glue->query_device_ex(attr_ctx, NULL, &device_attr_ex)) {
958                 err = ENODEV;
959                 goto error;
960         }
961         assert(device_attr.max_sge >= MLX4_MAX_SGE);
962         for (i = 0; i < device_attr.phys_port_cnt; i++) {
963                 uint32_t port = i + 1; /* ports are indexed from one */
964                 struct ibv_context *ctx = NULL;
965                 struct ibv_port_attr port_attr;
966                 struct ibv_pd *pd = NULL;
967                 struct mlx4_priv *priv = NULL;
968                 struct rte_eth_dev *eth_dev = NULL;
969                 struct ether_addr mac;
970                 char name[RTE_ETH_NAME_MAX_LEN];
971
972                 /* If port is not enabled, skip. */
973                 if (!(conf.ports.enabled & (1 << i)))
974                         continue;
975                 DEBUG("using port %u", port);
976                 ctx = mlx4_glue->open_device(ibv_dev);
977                 if (ctx == NULL) {
978                         err = ENODEV;
979                         goto port_error;
980                 }
981                 snprintf(name, sizeof(name), "%s port %u",
982                          mlx4_glue->get_device_name(ibv_dev), port);
983                 if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
984                         eth_dev = rte_eth_dev_attach_secondary(name);
985                         if (eth_dev == NULL) {
986                                 ERROR("can not attach rte ethdev");
987                                 rte_errno = ENOMEM;
988                                 err = rte_errno;
989                                 goto error;
990                         }
991                         priv = eth_dev->data->dev_private;
992                         if (!priv->verbs_alloc_ctx.enabled) {
993                                 ERROR("secondary process is not supported"
994                                       " due to lack of external allocator"
995                                       " from Verbs");
996                                 rte_errno = ENOTSUP;
997                                 err = rte_errno;
998                                 goto error;
999                         }
1000                         eth_dev->device = &pci_dev->device;
1001                         eth_dev->dev_ops = &mlx4_dev_sec_ops;
1002                         /* Receive command fd from primary process. */
1003                         err = mlx4_mp_req_verbs_cmd_fd(eth_dev);
1004                         if (err < 0) {
1005                                 err = rte_errno;
1006                                 goto error;
1007                         }
1008                         /* Remap UAR for Tx queues. */
1009                         err = mlx4_tx_uar_remap(eth_dev, err);
1010                         if (err) {
1011                                 err = rte_errno;
1012                                 goto error;
1013                         }
1014                         /*
1015                          * Ethdev pointer is still required as input since
1016                          * the primary device is not accessible from the
1017                          * secondary process.
1018                          */
1019                         eth_dev->tx_pkt_burst = mlx4_tx_burst;
1020                         eth_dev->rx_pkt_burst = mlx4_rx_burst;
1021                         claim_zero(mlx4_glue->close_device(ctx));
1022                         rte_eth_copy_pci_info(eth_dev, pci_dev);
1023                         rte_eth_dev_probing_finish(eth_dev);
1024                         continue;
1025                 }
1026                 /* Check port status. */
1027                 err = mlx4_glue->query_port(ctx, port, &port_attr);
1028                 if (err) {
1029                         err = ENODEV;
1030                         ERROR("port query failed: %s", strerror(err));
1031                         goto port_error;
1032                 }
1033                 if (port_attr.link_layer != IBV_LINK_LAYER_ETHERNET) {
1034                         err = ENOTSUP;
1035                         ERROR("port %d is not configured in Ethernet mode",
1036                               port);
1037                         goto port_error;
1038                 }
1039                 if (port_attr.state != IBV_PORT_ACTIVE)
1040                         DEBUG("port %d is not active: \"%s\" (%d)",
1041                               port, mlx4_glue->port_state_str(port_attr.state),
1042                               port_attr.state);
1043                 /* Make asynchronous FD non-blocking to handle interrupts. */
1044                 err = mlx4_fd_set_non_blocking(ctx->async_fd);
1045                 if (err) {
1046                         ERROR("cannot make asynchronous FD non-blocking: %s",
1047                               strerror(err));
1048                         goto port_error;
1049                 }
1050                 /* Allocate protection domain. */
1051                 pd = mlx4_glue->alloc_pd(ctx);
1052                 if (pd == NULL) {
1053                         err = ENOMEM;
1054                         ERROR("PD allocation failure");
1055                         goto port_error;
1056                 }
1057                 /* from rte_ethdev.c */
1058                 priv = rte_zmalloc("ethdev private structure",
1059                                    sizeof(*priv),
1060                                    RTE_CACHE_LINE_SIZE);
1061                 if (priv == NULL) {
1062                         err = ENOMEM;
1063                         ERROR("priv allocation failure");
1064                         goto port_error;
1065                 }
1066                 priv->ctx = ctx;
1067                 priv->device_attr = device_attr;
1068                 priv->port = port;
1069                 priv->pd = pd;
1070                 priv->mtu = ETHER_MTU;
1071                 priv->vf = vf;
1072                 priv->hw_csum = !!(device_attr.device_cap_flags &
1073                                    IBV_DEVICE_RAW_IP_CSUM);
1074                 DEBUG("checksum offloading is %ssupported",
1075                       (priv->hw_csum ? "" : "not "));
1076                 /* Only ConnectX-3 Pro supports tunneling. */
1077                 priv->hw_csum_l2tun =
1078                         priv->hw_csum &&
1079                         (device_attr.vendor_part_id ==
1080                          PCI_DEVICE_ID_MELLANOX_CONNECTX3PRO);
1081                 DEBUG("L2 tunnel checksum offloads are %ssupported",
1082                       priv->hw_csum_l2tun ? "" : "not ");
1083                 priv->hw_rss_sup = mlx4_hw_rss_sup(priv->ctx, priv->pd,
1084                                                    &device_attr_ex);
1085                 DEBUG("supported RSS hash fields mask: %016" PRIx64,
1086                       priv->hw_rss_sup);
1087                 priv->hw_rss_max_qps =
1088                         device_attr_ex.rss_caps.max_rwq_indirection_table_size;
1089                 DEBUG("MAX RSS queues %d", priv->hw_rss_max_qps);
1090                 priv->hw_fcs_strip = !!(device_attr_ex.raw_packet_caps &
1091                                         IBV_RAW_PACKET_CAP_SCATTER_FCS);
1092                 DEBUG("FCS stripping toggling is %ssupported",
1093                       priv->hw_fcs_strip ? "" : "not ");
1094                 priv->tso =
1095                         ((device_attr_ex.tso_caps.max_tso > 0) &&
1096                          (device_attr_ex.tso_caps.supported_qpts &
1097                           (1 << IBV_QPT_RAW_PACKET)));
1098                 if (priv->tso)
1099                         priv->tso_max_payload_sz =
1100                                         device_attr_ex.tso_caps.max_tso;
1101                 DEBUG("TSO is %ssupported",
1102                       priv->tso ? "" : "not ");
1103                 /* Configure the first MAC address by default. */
1104                 err = mlx4_get_mac(priv, &mac.addr_bytes);
1105                 if (err) {
1106                         ERROR("cannot get MAC address, is mlx4_en loaded?"
1107                               " (error: %s)", strerror(err));
1108                         goto port_error;
1109                 }
1110                 INFO("port %u MAC address is %02x:%02x:%02x:%02x:%02x:%02x",
1111                      priv->port,
1112                      mac.addr_bytes[0], mac.addr_bytes[1],
1113                      mac.addr_bytes[2], mac.addr_bytes[3],
1114                      mac.addr_bytes[4], mac.addr_bytes[5]);
1115                 /* Register MAC address. */
1116                 priv->mac[0] = mac;
1117 #ifndef NDEBUG
1118                 {
1119                         char ifname[IF_NAMESIZE];
1120
1121                         if (mlx4_get_ifname(priv, &ifname) == 0)
1122                                 DEBUG("port %u ifname is \"%s\"",
1123                                       priv->port, ifname);
1124                         else
1125                                 DEBUG("port %u ifname is unknown", priv->port);
1126                 }
1127 #endif
1128                 /* Get actual MTU if possible. */
1129                 mlx4_mtu_get(priv, &priv->mtu);
1130                 DEBUG("port %u MTU is %u", priv->port, priv->mtu);
1131                 eth_dev = rte_eth_dev_allocate(name);
1132                 if (eth_dev == NULL) {
1133                         err = ENOMEM;
1134                         ERROR("can not allocate rte ethdev");
1135                         goto port_error;
1136                 }
1137                 eth_dev->data->dev_private = priv;
1138                 eth_dev->data->mac_addrs = priv->mac;
1139                 eth_dev->device = &pci_dev->device;
1140                 rte_eth_copy_pci_info(eth_dev, pci_dev);
1141                 /* Initialize local interrupt handle for current port. */
1142                 priv->intr_handle = (struct rte_intr_handle){
1143                         .fd = -1,
1144                         .type = RTE_INTR_HANDLE_EXT,
1145                 };
1146                 /*
1147                  * Override ethdev interrupt handle pointer with private
1148                  * handle instead of that of the parent PCI device used by
1149                  * default. This prevents it from being shared between all
1150                  * ports of the same PCI device since each of them is
1151                  * associated its own Verbs context.
1152                  *
1153                  * Rx interrupts in particular require this as the PMD has
1154                  * no control over the registration of queue interrupts
1155                  * besides setting up eth_dev->intr_handle, the rest is
1156                  * handled by rte_intr_rx_ctl().
1157                  */
1158                 eth_dev->intr_handle = &priv->intr_handle;
1159                 priv->dev_data = eth_dev->data;
1160                 eth_dev->dev_ops = &mlx4_dev_ops;
1161 #ifdef HAVE_IBV_MLX4_BUF_ALLOCATORS
1162                 /* Hint libmlx4 to use PMD allocator for data plane resources */
1163                 struct mlx4dv_ctx_allocators alctr = {
1164                         .alloc = &mlx4_alloc_verbs_buf,
1165                         .free = &mlx4_free_verbs_buf,
1166                         .data = priv,
1167                 };
1168                 err = mlx4_glue->dv_set_context_attr
1169                         (ctx, MLX4DV_SET_CTX_ATTR_BUF_ALLOCATORS,
1170                          (void *)((uintptr_t)&alctr));
1171                 if (err)
1172                         WARN("Verbs external allocator is not supported");
1173                 else
1174                         priv->verbs_alloc_ctx.enabled = 1;
1175 #endif
1176                 /* Bring Ethernet device up. */
1177                 DEBUG("forcing Ethernet interface up");
1178                 mlx4_dev_set_link_up(eth_dev);
1179                 /* Update link status once if waiting for LSC. */
1180                 if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
1181                         mlx4_link_update(eth_dev, 0);
1182                 /*
1183                  * Once the device is added to the list of memory event
1184                  * callback, its global MR cache table cannot be expanded
1185                  * on the fly because of deadlock. If it overflows, lookup
1186                  * should be done by searching MR list linearly, which is slow.
1187                  */
1188                 err = mlx4_mr_btree_init(&priv->mr.cache,
1189                                          MLX4_MR_BTREE_CACHE_N * 2,
1190                                          eth_dev->device->numa_node);
1191                 if (err) {
1192                         /* rte_errno is already set. */
1193                         goto port_error;
1194                 }
1195                 /* Add device to memory callback list. */
1196                 rte_rwlock_write_lock(&mlx4_shared_data->mem_event_rwlock);
1197                 LIST_INSERT_HEAD(&mlx4_shared_data->mem_event_cb_list,
1198                                  priv, mem_event_cb);
1199                 rte_rwlock_write_unlock(&mlx4_shared_data->mem_event_rwlock);
1200                 rte_eth_dev_probing_finish(eth_dev);
1201                 continue;
1202 port_error:
1203                 rte_free(priv);
1204                 if (eth_dev != NULL)
1205                         eth_dev->data->dev_private = NULL;
1206                 if (pd)
1207                         claim_zero(mlx4_glue->dealloc_pd(pd));
1208                 if (ctx)
1209                         claim_zero(mlx4_glue->close_device(ctx));
1210                 if (eth_dev != NULL) {
1211                         /* mac_addrs must not be freed because part of dev_private */
1212                         eth_dev->data->mac_addrs = NULL;
1213                         rte_eth_dev_release_port(eth_dev);
1214                 }
1215                 break;
1216         }
1217         /*
1218          * XXX if something went wrong in the loop above, there is a resource
1219          * leak (ctx, pd, priv, dpdk ethdev) but we can do nothing about it as
1220          * long as the dpdk does not provide a way to deallocate a ethdev and a
1221          * way to enumerate the registered ethdevs to free the previous ones.
1222          */
1223 error:
1224         if (attr_ctx)
1225                 claim_zero(mlx4_glue->close_device(attr_ctx));
1226         if (list)
1227                 mlx4_glue->free_device_list(list);
1228         if (err)
1229                 rte_errno = err;
1230         return -err;
1231 }
1232
1233 static const struct rte_pci_id mlx4_pci_id_map[] = {
1234         {
1235                 RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
1236                                PCI_DEVICE_ID_MELLANOX_CONNECTX3)
1237         },
1238         {
1239                 RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
1240                                PCI_DEVICE_ID_MELLANOX_CONNECTX3PRO)
1241         },
1242         {
1243                 RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
1244                                PCI_DEVICE_ID_MELLANOX_CONNECTX3VF)
1245         },
1246         {
1247                 .vendor_id = 0
1248         }
1249 };
1250
1251 static struct rte_pci_driver mlx4_driver = {
1252         .driver = {
1253                 .name = MLX4_DRIVER_NAME
1254         },
1255         .id_table = mlx4_pci_id_map,
1256         .probe = mlx4_pci_probe,
1257         .drv_flags = RTE_PCI_DRV_INTR_LSC |
1258                      RTE_PCI_DRV_INTR_RMV,
1259 };
1260
1261 #ifdef RTE_IBVERBS_LINK_DLOPEN
1262
1263 /**
1264  * Suffix RTE_EAL_PMD_PATH with "-glue".
1265  *
1266  * This function performs a sanity check on RTE_EAL_PMD_PATH before
1267  * suffixing its last component.
1268  *
1269  * @param buf[out]
1270  *   Output buffer, should be large enough otherwise NULL is returned.
1271  * @param size
1272  *   Size of @p out.
1273  *
1274  * @return
1275  *   Pointer to @p buf or @p NULL in case suffix cannot be appended.
1276  */
1277 static char *
1278 mlx4_glue_path(char *buf, size_t size)
1279 {
1280         static const char *const bad[] = { "/", ".", "..", NULL };
1281         const char *path = RTE_EAL_PMD_PATH;
1282         size_t len = strlen(path);
1283         size_t off;
1284         int i;
1285
1286         while (len && path[len - 1] == '/')
1287                 --len;
1288         for (off = len; off && path[off - 1] != '/'; --off)
1289                 ;
1290         for (i = 0; bad[i]; ++i)
1291                 if (!strncmp(path + off, bad[i], (int)(len - off)))
1292                         goto error;
1293         i = snprintf(buf, size, "%.*s-glue", (int)len, path);
1294         if (i == -1 || (size_t)i >= size)
1295                 goto error;
1296         return buf;
1297 error:
1298         ERROR("unable to append \"-glue\" to last component of"
1299               " RTE_EAL_PMD_PATH (\"" RTE_EAL_PMD_PATH "\"),"
1300               " please re-configure DPDK");
1301         return NULL;
1302 }
1303
1304 /**
1305  * Initialization routine for run-time dependency on rdma-core.
1306  */
1307 static int
1308 mlx4_glue_init(void)
1309 {
1310         char glue_path[sizeof(RTE_EAL_PMD_PATH) - 1 + sizeof("-glue")];
1311         const char *path[] = {
1312                 /*
1313                  * A basic security check is necessary before trusting
1314                  * MLX4_GLUE_PATH, which may override RTE_EAL_PMD_PATH.
1315                  */
1316                 (geteuid() == getuid() && getegid() == getgid() ?
1317                  getenv("MLX4_GLUE_PATH") : NULL),
1318                 /*
1319                  * When RTE_EAL_PMD_PATH is set, use its glue-suffixed
1320                  * variant, otherwise let dlopen() look up libraries on its
1321                  * own.
1322                  */
1323                 (*RTE_EAL_PMD_PATH ?
1324                  mlx4_glue_path(glue_path, sizeof(glue_path)) : ""),
1325         };
1326         unsigned int i = 0;
1327         void *handle = NULL;
1328         void **sym;
1329         const char *dlmsg;
1330
1331         while (!handle && i != RTE_DIM(path)) {
1332                 const char *end;
1333                 size_t len;
1334                 int ret;
1335
1336                 if (!path[i]) {
1337                         ++i;
1338                         continue;
1339                 }
1340                 end = strpbrk(path[i], ":;");
1341                 if (!end)
1342                         end = path[i] + strlen(path[i]);
1343                 len = end - path[i];
1344                 ret = 0;
1345                 do {
1346                         char name[ret + 1];
1347
1348                         ret = snprintf(name, sizeof(name), "%.*s%s" MLX4_GLUE,
1349                                        (int)len, path[i],
1350                                        (!len || *(end - 1) == '/') ? "" : "/");
1351                         if (ret == -1)
1352                                 break;
1353                         if (sizeof(name) != (size_t)ret + 1)
1354                                 continue;
1355                         DEBUG("looking for rdma-core glue as \"%s\"", name);
1356                         handle = dlopen(name, RTLD_LAZY);
1357                         break;
1358                 } while (1);
1359                 path[i] = end + 1;
1360                 if (!*end)
1361                         ++i;
1362         }
1363         if (!handle) {
1364                 rte_errno = EINVAL;
1365                 dlmsg = dlerror();
1366                 if (dlmsg)
1367                         WARN("cannot load glue library: %s", dlmsg);
1368                 goto glue_error;
1369         }
1370         sym = dlsym(handle, "mlx4_glue");
1371         if (!sym || !*sym) {
1372                 rte_errno = EINVAL;
1373                 dlmsg = dlerror();
1374                 if (dlmsg)
1375                         ERROR("cannot resolve glue symbol: %s", dlmsg);
1376                 goto glue_error;
1377         }
1378         mlx4_glue = *sym;
1379         return 0;
1380 glue_error:
1381         if (handle)
1382                 dlclose(handle);
1383         WARN("cannot initialize PMD due to missing run-time"
1384              " dependency on rdma-core libraries (libibverbs,"
1385              " libmlx4)");
1386         return -rte_errno;
1387 }
1388
1389 #endif
1390
1391 /**
1392  * Driver initialization routine.
1393  */
1394 RTE_INIT(rte_mlx4_pmd_init)
1395 {
1396         /*
1397          * MLX4_DEVICE_FATAL_CLEANUP tells ibv_destroy functions we
1398          * want to get success errno value in case of calling them
1399          * when the device was removed.
1400          */
1401         setenv("MLX4_DEVICE_FATAL_CLEANUP", "1", 1);
1402         /*
1403          * RDMAV_HUGEPAGES_SAFE tells ibv_fork_init() we intend to use
1404          * huge pages. Calling ibv_fork_init() during init allows
1405          * applications to use fork() safely for purposes other than
1406          * using this PMD, which is not supported in forked processes.
1407          */
1408         setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
1409 #ifdef RTE_IBVERBS_LINK_DLOPEN
1410         if (mlx4_glue_init())
1411                 return;
1412         assert(mlx4_glue);
1413 #endif
1414 #ifndef NDEBUG
1415         /* Glue structure must not contain any NULL pointers. */
1416         {
1417                 unsigned int i;
1418
1419                 for (i = 0; i != sizeof(*mlx4_glue) / sizeof(void *); ++i)
1420                         assert(((const void *const *)mlx4_glue)[i]);
1421         }
1422 #endif
1423         if (strcmp(mlx4_glue->version, MLX4_GLUE_VERSION)) {
1424                 ERROR("rdma-core glue \"%s\" mismatch: \"%s\" is required",
1425                       mlx4_glue->version, MLX4_GLUE_VERSION);
1426                 return;
1427         }
1428         mlx4_glue->fork_init();
1429         rte_pci_register(&mlx4_driver);
1430 }
1431
1432 RTE_PMD_EXPORT_NAME(net_mlx4, __COUNTER__);
1433 RTE_PMD_REGISTER_PCI_TABLE(net_mlx4, mlx4_pci_id_map);
1434 RTE_PMD_REGISTER_KMOD_DEP(net_mlx4,
1435         "* ib_uverbs & mlx4_en & mlx4_core & mlx4_ib");