net/hns3: fix return value for unsupported tuple
[dpdk.git] / drivers / net / nfp / nfp_cpp_bridge.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2014-2021 Netronome Systems, Inc.
3  * All rights reserved.
4  *
5  * Small portions derived from code Copyright(c) 2010-2015 Intel Corporation.
6  */
7
8 /*
9  * vim:shiftwidth=8:noexpandtab
10  *
11  * @file dpdk/pmd/nfp_cpp_bridge.c
12  *
13  * Netronome vNIC DPDK Poll-Mode Driver: CPP Bridge
14  */
15
16 #include <rte_service_component.h>
17
18 #include "nfpcore/nfp_cpp.h"
19 #include "nfpcore/nfp_mip.h"
20 #include "nfpcore/nfp_nsp.h"
21
22 #include "nfp_logs.h"
23 #include "nfp_cpp_bridge.h"
24
25 #include <sys/ioctl.h>
26
27 /* Prototypes */
28 static int nfp_cpp_bridge_serve_write(int sockfd, struct nfp_cpp *cpp);
29 static int nfp_cpp_bridge_serve_read(int sockfd, struct nfp_cpp *cpp);
30 static int nfp_cpp_bridge_serve_ioctl(int sockfd, struct nfp_cpp *cpp);
31
32 void nfp_register_cpp_service(struct nfp_cpp *cpp)
33 {
34         uint32_t *cpp_service_id = NULL;
35         struct rte_service_spec service;
36
37         memset(&service, 0, sizeof(struct rte_service_spec));
38         snprintf(service.name, sizeof(service.name), "nfp_cpp_service");
39         service.callback = nfp_cpp_bridge_service_func;
40         service.callback_userdata = (void *)cpp;
41
42         if (rte_service_component_register(&service,
43                                            cpp_service_id))
44                 RTE_LOG(WARNING, PMD, "NFP CPP bridge service register() failed");
45         else
46                 RTE_LOG(DEBUG, PMD, "NFP CPP bridge service registered");
47 }
48
49 /*
50  * Serving a write request to NFP from host programs. The request
51  * sends the write size and the CPP target. The bridge makes use
52  * of CPP interface handler configured by the PMD setup.
53  */
54 static int
55 nfp_cpp_bridge_serve_write(int sockfd, struct nfp_cpp *cpp)
56 {
57         struct nfp_cpp_area *area;
58         off_t offset, nfp_offset;
59         uint32_t cpp_id, pos, len;
60         uint32_t tmpbuf[16];
61         size_t count, curlen;
62         int err = 0;
63
64         PMD_CPP_LOG(DEBUG, "%s: offset size %zu, count_size: %zu\n", __func__,
65                 sizeof(off_t), sizeof(size_t));
66
67         /* Reading the count param */
68         err = recv(sockfd, &count, sizeof(off_t), 0);
69         if (err != sizeof(off_t))
70                 return -EINVAL;
71
72         curlen = count;
73
74         /* Reading the offset param */
75         err = recv(sockfd, &offset, sizeof(off_t), 0);
76         if (err != sizeof(off_t))
77                 return -EINVAL;
78
79         /* Obtain target's CPP ID and offset in target */
80         cpp_id = (offset >> 40) << 8;
81         nfp_offset = offset & ((1ull << 40) - 1);
82
83         PMD_CPP_LOG(DEBUG, "%s: count %zu and offset %jd\n", __func__, count,
84                 offset);
85         PMD_CPP_LOG(DEBUG, "%s: cpp_id %08x and nfp_offset %jd\n", __func__,
86                 cpp_id, nfp_offset);
87
88         /* Adjust length if not aligned */
89         if (((nfp_offset + (off_t)count - 1) & ~(NFP_CPP_MEMIO_BOUNDARY - 1)) !=
90             (nfp_offset & ~(NFP_CPP_MEMIO_BOUNDARY - 1))) {
91                 curlen = NFP_CPP_MEMIO_BOUNDARY -
92                         (nfp_offset & (NFP_CPP_MEMIO_BOUNDARY - 1));
93         }
94
95         while (count > 0) {
96                 /* configure a CPP PCIe2CPP BAR for mapping the CPP target */
97                 area = nfp_cpp_area_alloc_with_name(cpp, cpp_id, "nfp.cdev",
98                                                     nfp_offset, curlen);
99                 if (!area) {
100                         RTE_LOG(ERR, PMD, "%s: area alloc fail\n", __func__);
101                         return -EIO;
102                 }
103
104                 /* mapping the target */
105                 err = nfp_cpp_area_acquire(area);
106                 if (err < 0) {
107                         RTE_LOG(ERR, PMD, "area acquire failed\n");
108                         nfp_cpp_area_free(area);
109                         return -EIO;
110                 }
111
112                 for (pos = 0; pos < curlen; pos += len) {
113                         len = curlen - pos;
114                         if (len > sizeof(tmpbuf))
115                                 len = sizeof(tmpbuf);
116
117                         PMD_CPP_LOG(DEBUG, "%s: Receive %u of %zu\n", __func__,
118                                            len, count);
119                         err = recv(sockfd, tmpbuf, len, MSG_WAITALL);
120                         if (err != (int)len) {
121                                 RTE_LOG(ERR, PMD,
122                                         "%s: error when receiving, %d of %zu\n",
123                                         __func__, err, count);
124                                 nfp_cpp_area_release(area);
125                                 nfp_cpp_area_free(area);
126                                 return -EIO;
127                         }
128                         err = nfp_cpp_area_write(area, pos, tmpbuf, len);
129                         if (err < 0) {
130                                 RTE_LOG(ERR, PMD, "nfp_cpp_area_write error\n");
131                                 nfp_cpp_area_release(area);
132                                 nfp_cpp_area_free(area);
133                                 return -EIO;
134                         }
135                 }
136
137                 nfp_offset += pos;
138                 nfp_cpp_area_release(area);
139                 nfp_cpp_area_free(area);
140
141                 count -= pos;
142                 curlen = (count > NFP_CPP_MEMIO_BOUNDARY) ?
143                          NFP_CPP_MEMIO_BOUNDARY : count;
144         }
145
146         return 0;
147 }
148
149 /*
150  * Serving a read request to NFP from host programs. The request
151  * sends the read size and the CPP target. The bridge makes use
152  * of CPP interface handler configured by the PMD setup. The read
153  * data is sent to the requester using the same socket.
154  */
155 static int
156 nfp_cpp_bridge_serve_read(int sockfd, struct nfp_cpp *cpp)
157 {
158         struct nfp_cpp_area *area;
159         off_t offset, nfp_offset;
160         uint32_t cpp_id, pos, len;
161         uint32_t tmpbuf[16];
162         size_t count, curlen;
163         int err = 0;
164
165         PMD_CPP_LOG(DEBUG, "%s: offset size %zu, count_size: %zu\n", __func__,
166                 sizeof(off_t), sizeof(size_t));
167
168         /* Reading the count param */
169         err = recv(sockfd, &count, sizeof(off_t), 0);
170         if (err != sizeof(off_t))
171                 return -EINVAL;
172
173         curlen = count;
174
175         /* Reading the offset param */
176         err = recv(sockfd, &offset, sizeof(off_t), 0);
177         if (err != sizeof(off_t))
178                 return -EINVAL;
179
180         /* Obtain target's CPP ID and offset in target */
181         cpp_id = (offset >> 40) << 8;
182         nfp_offset = offset & ((1ull << 40) - 1);
183
184         PMD_CPP_LOG(DEBUG, "%s: count %zu and offset %jd\n", __func__, count,
185                            offset);
186         PMD_CPP_LOG(DEBUG, "%s: cpp_id %08x and nfp_offset %jd\n", __func__,
187                            cpp_id, nfp_offset);
188
189         /* Adjust length if not aligned */
190         if (((nfp_offset + (off_t)count - 1) & ~(NFP_CPP_MEMIO_BOUNDARY - 1)) !=
191             (nfp_offset & ~(NFP_CPP_MEMIO_BOUNDARY - 1))) {
192                 curlen = NFP_CPP_MEMIO_BOUNDARY -
193                         (nfp_offset & (NFP_CPP_MEMIO_BOUNDARY - 1));
194         }
195
196         while (count > 0) {
197                 area = nfp_cpp_area_alloc_with_name(cpp, cpp_id, "nfp.cdev",
198                                                     nfp_offset, curlen);
199                 if (!area) {
200                         RTE_LOG(ERR, PMD, "%s: area alloc failed\n", __func__);
201                         return -EIO;
202                 }
203
204                 err = nfp_cpp_area_acquire(area);
205                 if (err < 0) {
206                         RTE_LOG(ERR, PMD, "area acquire failed\n");
207                         nfp_cpp_area_free(area);
208                         return -EIO;
209                 }
210
211                 for (pos = 0; pos < curlen; pos += len) {
212                         len = curlen - pos;
213                         if (len > sizeof(tmpbuf))
214                                 len = sizeof(tmpbuf);
215
216                         err = nfp_cpp_area_read(area, pos, tmpbuf, len);
217                         if (err < 0) {
218                                 RTE_LOG(ERR, PMD, "nfp_cpp_area_read error\n");
219                                 nfp_cpp_area_release(area);
220                                 nfp_cpp_area_free(area);
221                                 return -EIO;
222                         }
223                         PMD_CPP_LOG(DEBUG, "%s: sending %u of %zu\n", __func__,
224                                            len, count);
225
226                         err = send(sockfd, tmpbuf, len, 0);
227                         if (err != (int)len) {
228                                 RTE_LOG(ERR, PMD,
229                                         "%s: error when sending: %d of %zu\n",
230                                         __func__, err, count);
231                                 nfp_cpp_area_release(area);
232                                 nfp_cpp_area_free(area);
233                                 return -EIO;
234                         }
235                 }
236
237                 nfp_offset += pos;
238                 nfp_cpp_area_release(area);
239                 nfp_cpp_area_free(area);
240
241                 count -= pos;
242                 curlen = (count > NFP_CPP_MEMIO_BOUNDARY) ?
243                         NFP_CPP_MEMIO_BOUNDARY : count;
244         }
245         return 0;
246 }
247
248 /*
249  * Serving a ioctl command from host NFP tools. This usually goes to
250  * a kernel driver char driver but it is not available when the PF is
251  * bound to the PMD. Currently just one ioctl command is served and it
252  * does not require any CPP access at all.
253  */
254 static int
255 nfp_cpp_bridge_serve_ioctl(int sockfd, struct nfp_cpp *cpp)
256 {
257         uint32_t cmd, ident_size, tmp;
258         int err;
259
260         /* Reading now the IOCTL command */
261         err = recv(sockfd, &cmd, 4, 0);
262         if (err != 4) {
263                 RTE_LOG(ERR, PMD, "%s: read error from socket\n", __func__);
264                 return -EIO;
265         }
266
267         /* Only supporting NFP_IOCTL_CPP_IDENTIFICATION */
268         if (cmd != NFP_IOCTL_CPP_IDENTIFICATION) {
269                 RTE_LOG(ERR, PMD, "%s: unknown cmd %d\n", __func__, cmd);
270                 return -EINVAL;
271         }
272
273         err = recv(sockfd, &ident_size, 4, 0);
274         if (err != 4) {
275                 RTE_LOG(ERR, PMD, "%s: read error from socket\n", __func__);
276                 return -EIO;
277         }
278
279         tmp = nfp_cpp_model(cpp);
280
281         PMD_CPP_LOG(DEBUG, "%s: sending NFP model %08x\n", __func__, tmp);
282
283         err = send(sockfd, &tmp, 4, 0);
284         if (err != 4) {
285                 RTE_LOG(ERR, PMD, "%s: error writing to socket\n", __func__);
286                 return -EIO;
287         }
288
289         tmp = cpp->interface;
290
291         PMD_CPP_LOG(DEBUG, "%s: sending NFP interface %08x\n", __func__, tmp);
292
293         err = send(sockfd, &tmp, 4, 0);
294         if (err != 4) {
295                 RTE_LOG(ERR, PMD, "%s: error writing to socket\n", __func__);
296                 return -EIO;
297         }
298
299         return 0;
300 }
301
302 /*
303  * This is the code to be executed by a service core. The CPP bridge interface
304  * is based on a unix socket and requests usually received by a kernel char
305  * driver, read, write and ioctl, are handled by the CPP bridge. NFP host tools
306  * can be executed with a wrapper library and LD_LIBRARY being completely
307  * unaware of the CPP bridge performing the NFP kernel char driver for CPP
308  * accesses.
309  */
310 int32_t
311 nfp_cpp_bridge_service_func(void *args)
312 {
313         struct sockaddr address;
314         struct nfp_cpp *cpp = args;
315         int sockfd, datafd, op, ret;
316
317         unlink("/tmp/nfp_cpp");
318         sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
319         if (sockfd < 0) {
320                 RTE_LOG(ERR, PMD, "%s: socket creation error. Service failed\n",
321                         __func__);
322                 return -EIO;
323         }
324
325         memset(&address, 0, sizeof(struct sockaddr));
326
327         address.sa_family = AF_UNIX;
328         strcpy(address.sa_data, "/tmp/nfp_cpp");
329
330         ret = bind(sockfd, (const struct sockaddr *)&address,
331                    sizeof(struct sockaddr));
332         if (ret < 0) {
333                 RTE_LOG(ERR, PMD, "%s: bind error (%d). Service failed\n",
334                                   __func__, errno);
335                 close(sockfd);
336                 return ret;
337         }
338
339         ret = listen(sockfd, 20);
340         if (ret < 0) {
341                 RTE_LOG(ERR, PMD, "%s: listen error(%d). Service failed\n",
342                                   __func__, errno);
343                 close(sockfd);
344                 return ret;
345         }
346
347         for (;;) {
348                 datafd = accept(sockfd, NULL, NULL);
349                 if (datafd < 0) {
350                         RTE_LOG(ERR, PMD, "%s: accept call error (%d)\n",
351                                           __func__, errno);
352                         RTE_LOG(ERR, PMD, "%s: service failed\n", __func__);
353                         close(sockfd);
354                         return -EIO;
355                 }
356
357                 while (1) {
358                         ret = recv(datafd, &op, 4, 0);
359                         if (ret <= 0) {
360                                 PMD_CPP_LOG(DEBUG, "%s: socket close\n",
361                                                    __func__);
362                                 break;
363                         }
364
365                         PMD_CPP_LOG(DEBUG, "%s: getting op %u\n", __func__, op);
366
367                         if (op == NFP_BRIDGE_OP_READ)
368                                 nfp_cpp_bridge_serve_read(datafd, cpp);
369
370                         if (op == NFP_BRIDGE_OP_WRITE)
371                                 nfp_cpp_bridge_serve_write(datafd, cpp);
372
373                         if (op == NFP_BRIDGE_OP_IOCTL)
374                                 nfp_cpp_bridge_serve_ioctl(datafd, cpp);
375
376                         if (op == 0)
377                                 break;
378                 }
379                 close(datafd);
380         }
381         close(sockfd);
382
383         return 0;
384 }
385 /*
386  * Local variables:
387  * c-file-style: "Linux"
388  * indent-tabs-mode: t
389  * End:
390  */