New upstream version 17.11-rc3
[deb_dpdk.git] / drivers / net / mlx4 / mlx4_utils.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2017 6WIND S.A.
5  *   Copyright 2017 Mellanox
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of 6WIND S.A. nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 /**
35  * @file
36  * Utility functions used by the mlx4 driver.
37  */
38
39 #include <assert.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <stddef.h>
43 #include <stdint.h>
44
45 #include <rte_errno.h>
46 #include <rte_malloc.h>
47 #include <rte_memory.h>
48
49 #include "mlx4_utils.h"
50
51 /**
52  * Make a file descriptor non-blocking.
53  *
54  * @param fd
55  *   File descriptor to alter.
56  *
57  * @return
58  *   0 on success, negative errno value otherwise and rte_errno is set.
59  */
60 int
61 mlx4_fd_set_non_blocking(int fd)
62 {
63         int ret = fcntl(fd, F_GETFL);
64
65         if (ret != -1 && !fcntl(fd, F_SETFL, ret | O_NONBLOCK))
66                 return 0;
67         assert(errno);
68         rte_errno = errno;
69         return -rte_errno;
70 }
71
72 /**
73  * Internal helper to allocate memory once for several disparate objects.
74  *
75  * The most restrictive alignment constraint for standard objects is assumed
76  * to be sizeof(double) and is used as a default value.
77  *
78  * C11 code would include stdalign.h and use alignof(max_align_t) however
79  * we'll stick with C99 for the time being.
80  */
81 static inline size_t
82 mlx4_mallocv_inline(const char *type, const struct mlx4_malloc_vec *vec,
83                     unsigned int cnt, int zero, int socket)
84 {
85         unsigned int i;
86         size_t size;
87         size_t least;
88         uint8_t *data = NULL;
89         int fill = !vec[0].addr;
90
91 fill:
92         size = 0;
93         least = 0;
94         for (i = 0; i < cnt; ++i) {
95                 size_t align = (uintptr_t)vec[i].align;
96
97                 if (!align) {
98                         align = sizeof(double);
99                 } else if (!rte_is_power_of_2(align)) {
100                         rte_errno = EINVAL;
101                         goto error;
102                 }
103                 if (least < align)
104                         least = align;
105                 align = RTE_ALIGN_CEIL(size, align);
106                 size = align + vec[i].size;
107                 if (fill && vec[i].addr)
108                         *vec[i].addr = data + align;
109         }
110         if (fill)
111                 return size;
112         if (!zero)
113                 data = rte_malloc_socket(type, size, least, socket);
114         else
115                 data = rte_zmalloc_socket(type, size, least, socket);
116         if (data) {
117                 fill = 1;
118                 goto fill;
119         }
120         rte_errno = ENOMEM;
121 error:
122         for (i = 0; i != cnt; ++i)
123                 if (vec[i].addr)
124                         *vec[i].addr = NULL;
125         return 0;
126 }
127
128 /**
129  * Allocate memory once for several disparate objects.
130  *
131  * This function adds iovec-like semantics (e.g. readv()) to rte_malloc().
132  * Memory is allocated once for several contiguous objects of nonuniform
133  * sizes and alignment constraints.
134  *
135  * Each entry of @p vec describes the size, alignment constraint and
136  * provides a buffer address where the resulting object pointer must be
137  * stored.
138  *
139  * The buffer of the first entry is guaranteed to point to the beginning of
140  * the allocated region and is safe to use with rte_free().
141  *
142  * NULL buffers are silently ignored.
143  *
144  * Providing a NULL buffer in the first entry prevents this function from
145  * allocating any memory but has otherwise no effect on its behavior. In
146  * this case, the contents of remaining non-NULL buffers are updated with
147  * addresses relative to zero (i.e. offsets that would have been used during
148  * the allocation).
149  *
150  * @param[in] type
151  *   A string identifying the type of allocated objects (useful for debug
152  *   purposes, such as identifying the cause of a memory leak). Can be NULL.
153  * @param[in, out] vec
154  *   Description of objects to allocate memory for.
155  * @param cnt
156  *   Number of entries in @p vec.
157  *
158  * @return
159  *   Size in bytes of the allocated region including any padding. In case of
160  *   error, rte_errno is set, 0 is returned and NULL is stored in the
161  *   non-NULL buffers pointed by @p vec.
162  *
163  * @see struct mlx4_malloc_vec
164  * @see rte_malloc()
165  */
166 size_t
167 mlx4_mallocv(const char *type, const struct mlx4_malloc_vec *vec,
168              unsigned int cnt)
169 {
170         return mlx4_mallocv_inline(type, vec, cnt, 0, SOCKET_ID_ANY);
171 }
172
173 /**
174  * Combines the semantics of mlx4_mallocv() with those of rte_zmalloc().
175  *
176  * @see mlx4_mallocv()
177  * @see rte_zmalloc()
178  */
179 size_t
180 mlx4_zmallocv(const char *type, const struct mlx4_malloc_vec *vec,
181               unsigned int cnt)
182 {
183         return mlx4_mallocv_inline(type, vec, cnt, 1, SOCKET_ID_ANY);
184 }
185
186 /**
187  * Socket-aware version of mlx4_mallocv().
188  *
189  * This function takes one additional parameter.
190  *
191  * @param socket
192  *   NUMA socket to allocate memory on. If SOCKET_ID_ANY is used, this
193  *   function will behave the same as mlx4_mallocv().
194  *
195  * @see mlx4_mallocv()
196  * @see rte_malloc_socket()
197  */
198 size_t
199 mlx4_mallocv_socket(const char *type, const struct mlx4_malloc_vec *vec,
200                     unsigned int cnt, int socket)
201 {
202         return mlx4_mallocv_inline(type, vec, cnt, 0, socket);
203 }
204
205 /**
206  * Combines the semantics of mlx4_mallocv_socket() with those of
207  * mlx4_zmalloc_socket().
208  *
209  * @see mlx4_mallocv_socket()
210  * @see rte_zmalloc_socket()
211  */
212 size_t
213 mlx4_zmallocv_socket(const char *type, const struct mlx4_malloc_vec *vec,
214                      unsigned int cnt, int socket)
215 {
216         return mlx4_mallocv_inline(type, vec, cnt, 1, socket);
217 }