Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2014-2021 Netronome Systems, Inc.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "nfp_cpp_bridge.h"
7 : :
8 : : #include <unistd.h>
9 : : #include <sys/ioctl.h>
10 : :
11 : : #include <rte_service_component.h>
12 : :
13 : : #include "nfpcore/nfp_cpp.h"
14 : : #include "nfp_logs.h"
15 : :
16 : : #define NFP_CPP_MEMIO_BOUNDARY (1 << 20)
17 : : #define NFP_BRIDGE_OP_READ 20
18 : : #define NFP_BRIDGE_OP_WRITE 30
19 : : #define NFP_BRIDGE_OP_IOCTL 40
20 : :
21 : : #define NFP_IOCTL 'n'
22 : : #define NFP_IOCTL_CPP_IDENTIFICATION _IOW(NFP_IOCTL, 0x8f, uint32_t)
23 : :
24 : : /* Prototypes */
25 : : static int nfp_cpp_bridge_service_func(void *args);
26 : :
27 : : int
28 : 0 : nfp_map_service(uint32_t service_id)
29 : : {
30 : : int32_t ret;
31 : : uint32_t slcore = 0;
32 : : int32_t slcore_count;
33 : : uint8_t service_count;
34 : : const char *service_name;
35 : : uint32_t slcore_array[RTE_MAX_LCORE];
36 : : uint8_t min_service_count = UINT8_MAX;
37 : :
38 : 0 : slcore_count = rte_service_lcore_list(slcore_array, RTE_MAX_LCORE);
39 [ # # ]: 0 : if (slcore_count <= 0) {
40 : 0 : PMD_INIT_LOG(DEBUG, "No service cores found");
41 : 0 : return -ENOENT;
42 : : }
43 : :
44 : : /*
45 : : * Find a service core with the least number of services already
46 : : * registered to it.
47 : : */
48 [ # # ]: 0 : while (slcore_count--) {
49 : 0 : service_count = rte_service_lcore_count_services(slcore_array[slcore_count]);
50 [ # # ]: 0 : if (service_count < min_service_count) {
51 : 0 : slcore = slcore_array[slcore_count];
52 : : min_service_count = service_count;
53 : : }
54 : : }
55 : :
56 : 0 : service_name = rte_service_get_name(service_id);
57 : 0 : PMD_INIT_LOG(INFO, "Mapping service %s to core %u", service_name, slcore);
58 : :
59 : 0 : ret = rte_service_map_lcore_set(service_id, slcore, 1);
60 [ # # ]: 0 : if (ret != 0) {
61 : 0 : PMD_INIT_LOG(DEBUG, "Could not map flower service");
62 : 0 : return -ENOENT;
63 : : }
64 : :
65 : 0 : rte_service_runstate_set(service_id, 1);
66 : 0 : rte_service_component_runstate_set(service_id, 1);
67 : 0 : rte_service_lcore_start(slcore);
68 [ # # ]: 0 : if (rte_service_may_be_active(slcore) != 0)
69 : 0 : PMD_INIT_LOG(INFO, "The service %s is running", service_name);
70 : : else
71 : 0 : PMD_INIT_LOG(ERR, "The service %s is not running", service_name);
72 : :
73 : : return 0;
74 : : }
75 : :
76 : : int
77 : 0 : nfp_enable_cpp_service(struct nfp_pf_dev *pf_dev)
78 : : {
79 : : int ret;
80 : 0 : uint32_t service_id = 0;
81 : 0 : struct rte_service_spec cpp_service = {
82 : : .name = "nfp_cpp_service",
83 : : .callback = nfp_cpp_bridge_service_func,
84 : : };
85 : :
86 : 0 : cpp_service.callback_userdata = (void *)pf_dev;
87 : :
88 : : /* Register the cpp service */
89 : 0 : ret = rte_service_component_register(&cpp_service, &service_id);
90 [ # # ]: 0 : if (ret != 0) {
91 : 0 : PMD_INIT_LOG(WARNING, "Could not register nfp cpp service");
92 : 0 : return -EINVAL;
93 : : }
94 : :
95 : 0 : pf_dev->cpp_bridge_id = service_id;
96 : 0 : PMD_INIT_LOG(INFO, "NFP cpp service registered");
97 : :
98 : : /* Map it to available service core */
99 : 0 : ret = nfp_map_service(service_id);
100 [ # # ]: 0 : if (ret != 0) {
101 : 0 : PMD_INIT_LOG(DEBUG, "Could not map nfp cpp service");
102 : 0 : return -EINVAL;
103 : : }
104 : :
105 : : return 0;
106 : : }
107 : :
108 : : /*
109 : : * Serving a write request to NFP from host programs. The request
110 : : * sends the write size and the CPP target. The bridge makes use
111 : : * of CPP interface handler configured by the PMD setup.
112 : : */
113 : : static int
114 : 0 : nfp_cpp_bridge_serve_write(int sockfd,
115 : : struct nfp_cpp *cpp)
116 : : {
117 : : int err;
118 : : off_t offset;
119 : : uint32_t pos;
120 : : uint32_t len;
121 : : size_t count;
122 : : size_t curlen;
123 : : uint32_t cpp_id;
124 : : off_t nfp_offset;
125 : : uint32_t tmpbuf[16];
126 : : struct nfp_cpp_area *area;
127 : :
128 : 0 : PMD_CPP_LOG(DEBUG, "%s: offset size %zu, count_size: %zu", __func__,
129 : : sizeof(off_t), sizeof(size_t));
130 : :
131 : : /* Reading the count param */
132 : 0 : err = recv(sockfd, &count, sizeof(off_t), 0);
133 [ # # ]: 0 : if (err != sizeof(off_t))
134 : : return -EINVAL;
135 : :
136 : 0 : curlen = count;
137 : :
138 : : /* Reading the offset param */
139 : 0 : err = recv(sockfd, &offset, sizeof(off_t), 0);
140 [ # # ]: 0 : if (err != sizeof(off_t))
141 : : return -EINVAL;
142 : :
143 : : /* Obtain target's CPP ID and offset in target */
144 : 0 : cpp_id = (offset >> 40) << 8;
145 : 0 : nfp_offset = offset & ((1ull << 40) - 1);
146 : :
147 : 0 : PMD_CPP_LOG(DEBUG, "%s: count %zu and offset %jd", __func__, count,
148 : : offset);
149 : 0 : PMD_CPP_LOG(DEBUG, "%s: cpp_id %08x and nfp_offset %jd", __func__,
150 : : cpp_id, nfp_offset);
151 : :
152 : : /* Adjust length if not aligned */
153 [ # # ]: 0 : if (((nfp_offset + (off_t)count - 1) & ~(NFP_CPP_MEMIO_BOUNDARY - 1)) !=
154 : : (nfp_offset & ~(NFP_CPP_MEMIO_BOUNDARY - 1))) {
155 : 0 : curlen = NFP_CPP_MEMIO_BOUNDARY -
156 : 0 : (nfp_offset & (NFP_CPP_MEMIO_BOUNDARY - 1));
157 : : }
158 : :
159 [ # # ]: 0 : while (count > 0) {
160 : : /* Configure a CPP PCIe2CPP BAR for mapping the CPP target */
161 : 0 : area = nfp_cpp_area_alloc_with_name(cpp, cpp_id, "nfp.cdev",
162 : : nfp_offset, curlen);
163 [ # # ]: 0 : if (area == NULL) {
164 : 0 : PMD_CPP_LOG(ERR, "area alloc fail");
165 : 0 : return -EIO;
166 : : }
167 : :
168 : : /* Mapping the target */
169 : 0 : err = nfp_cpp_area_acquire(area);
170 [ # # ]: 0 : if (err < 0) {
171 : 0 : PMD_CPP_LOG(ERR, "area acquire failed");
172 : 0 : nfp_cpp_area_free(area);
173 : 0 : return -EIO;
174 : : }
175 : :
176 [ # # ]: 0 : for (pos = 0; pos < curlen; pos += len) {
177 : 0 : len = curlen - pos;
178 : : if (len > sizeof(tmpbuf))
179 : : len = sizeof(tmpbuf);
180 : :
181 : 0 : PMD_CPP_LOG(DEBUG, "%s: Receive %u of %zu", __func__,
182 : : len, count);
183 : 0 : err = recv(sockfd, tmpbuf, len, MSG_WAITALL);
184 [ # # ]: 0 : if (err != (int)len) {
185 : 0 : PMD_CPP_LOG(ERR, "error when receiving, %d of %zu",
186 : : err, count);
187 : 0 : nfp_cpp_area_release(area);
188 : 0 : nfp_cpp_area_free(area);
189 : 0 : return -EIO;
190 : : }
191 : :
192 : 0 : err = nfp_cpp_area_write(area, pos, tmpbuf, len);
193 [ # # ]: 0 : if (err < 0) {
194 : 0 : PMD_CPP_LOG(ERR, "nfp_cpp_area_write error");
195 : 0 : nfp_cpp_area_release(area);
196 : 0 : nfp_cpp_area_free(area);
197 : 0 : return -EIO;
198 : : }
199 : : }
200 : :
201 : 0 : nfp_offset += pos;
202 : 0 : nfp_cpp_area_release(area);
203 : 0 : nfp_cpp_area_free(area);
204 : :
205 : 0 : count -= pos;
206 : 0 : curlen = (count > NFP_CPP_MEMIO_BOUNDARY) ?
207 : : NFP_CPP_MEMIO_BOUNDARY : count;
208 : : }
209 : :
210 : : return 0;
211 : : }
212 : :
213 : : /*
214 : : * Serving a read request to NFP from host programs. The request
215 : : * sends the read size and the CPP target. The bridge makes use
216 : : * of CPP interface handler configured by the PMD setup. The read
217 : : * data is sent to the requester using the same socket.
218 : : */
219 : : static int
220 : 0 : nfp_cpp_bridge_serve_read(int sockfd,
221 : : struct nfp_cpp *cpp)
222 : : {
223 : : int err;
224 : : off_t offset;
225 : : uint32_t pos;
226 : : uint32_t len;
227 : : size_t count;
228 : : size_t curlen;
229 : : uint32_t cpp_id;
230 : : off_t nfp_offset;
231 : : uint32_t tmpbuf[16];
232 : : struct nfp_cpp_area *area;
233 : :
234 : 0 : PMD_CPP_LOG(DEBUG, "%s: offset size %zu, count_size: %zu", __func__,
235 : : sizeof(off_t), sizeof(size_t));
236 : :
237 : : /* Reading the count param */
238 : 0 : err = recv(sockfd, &count, sizeof(off_t), 0);
239 [ # # ]: 0 : if (err != sizeof(off_t))
240 : : return -EINVAL;
241 : :
242 : 0 : curlen = count;
243 : :
244 : : /* Reading the offset param */
245 : 0 : err = recv(sockfd, &offset, sizeof(off_t), 0);
246 [ # # ]: 0 : if (err != sizeof(off_t))
247 : : return -EINVAL;
248 : :
249 : : /* Obtain target's CPP ID and offset in target */
250 : 0 : cpp_id = (offset >> 40) << 8;
251 : 0 : nfp_offset = offset & ((1ull << 40) - 1);
252 : :
253 : 0 : PMD_CPP_LOG(DEBUG, "%s: count %zu and offset %jd", __func__, count,
254 : : offset);
255 : 0 : PMD_CPP_LOG(DEBUG, "%s: cpp_id %08x and nfp_offset %jd", __func__,
256 : : cpp_id, nfp_offset);
257 : :
258 : : /* Adjust length if not aligned */
259 [ # # ]: 0 : if (((nfp_offset + (off_t)count - 1) & ~(NFP_CPP_MEMIO_BOUNDARY - 1)) !=
260 : : (nfp_offset & ~(NFP_CPP_MEMIO_BOUNDARY - 1))) {
261 : 0 : curlen = NFP_CPP_MEMIO_BOUNDARY -
262 : 0 : (nfp_offset & (NFP_CPP_MEMIO_BOUNDARY - 1));
263 : : }
264 : :
265 [ # # ]: 0 : while (count > 0) {
266 : 0 : area = nfp_cpp_area_alloc_with_name(cpp, cpp_id, "nfp.cdev",
267 : : nfp_offset, curlen);
268 [ # # ]: 0 : if (area == NULL) {
269 : 0 : PMD_CPP_LOG(ERR, "area alloc failed");
270 : 0 : return -EIO;
271 : : }
272 : :
273 : 0 : err = nfp_cpp_area_acquire(area);
274 [ # # ]: 0 : if (err < 0) {
275 : 0 : PMD_CPP_LOG(ERR, "area acquire failed");
276 : 0 : nfp_cpp_area_free(area);
277 : 0 : return -EIO;
278 : : }
279 : :
280 [ # # ]: 0 : for (pos = 0; pos < curlen; pos += len) {
281 : 0 : len = curlen - pos;
282 : : if (len > sizeof(tmpbuf))
283 : : len = sizeof(tmpbuf);
284 : :
285 : 0 : err = nfp_cpp_area_read(area, pos, tmpbuf, len);
286 [ # # ]: 0 : if (err < 0) {
287 : 0 : PMD_CPP_LOG(ERR, "nfp_cpp_area_read error");
288 : 0 : nfp_cpp_area_release(area);
289 : 0 : nfp_cpp_area_free(area);
290 : 0 : return -EIO;
291 : : }
292 : 0 : PMD_CPP_LOG(DEBUG, "%s: sending %u of %zu", __func__,
293 : : len, count);
294 : :
295 : 0 : err = send(sockfd, tmpbuf, len, 0);
296 [ # # ]: 0 : if (err != (int)len) {
297 : 0 : PMD_CPP_LOG(ERR, "error when sending: %d of %zu",
298 : : err, count);
299 : 0 : nfp_cpp_area_release(area);
300 : 0 : nfp_cpp_area_free(area);
301 : 0 : return -EIO;
302 : : }
303 : : }
304 : :
305 : 0 : nfp_offset += pos;
306 : 0 : nfp_cpp_area_release(area);
307 : 0 : nfp_cpp_area_free(area);
308 : :
309 : 0 : count -= pos;
310 : 0 : curlen = (count > NFP_CPP_MEMIO_BOUNDARY) ?
311 : : NFP_CPP_MEMIO_BOUNDARY : count;
312 : : }
313 : :
314 : : return 0;
315 : : }
316 : :
317 : : /*
318 : : * Serving a ioctl command from host NFP tools. This usually goes to
319 : : * a kernel driver char driver but it is not available when the PF is
320 : : * bound to the PMD. Currently just one ioctl command is served and it
321 : : * does not require any CPP access at all.
322 : : */
323 : : static int
324 : 0 : nfp_cpp_bridge_serve_ioctl(int sockfd,
325 : : struct nfp_cpp *cpp)
326 : : {
327 : : int err;
328 : : uint32_t cmd;
329 : : uint32_t tmp;
330 : : uint32_t ident_size;
331 : :
332 : : /* Reading now the IOCTL command */
333 : 0 : err = recv(sockfd, &cmd, 4, 0);
334 [ # # ]: 0 : if (err != 4) {
335 : 0 : PMD_CPP_LOG(ERR, "read error from socket");
336 : 0 : return -EIO;
337 : : }
338 : :
339 : : /* Only supporting NFP_IOCTL_CPP_IDENTIFICATION */
340 [ # # ]: 0 : if (cmd != NFP_IOCTL_CPP_IDENTIFICATION) {
341 : 0 : PMD_CPP_LOG(ERR, "unknown cmd %d", cmd);
342 : 0 : return -EINVAL;
343 : : }
344 : :
345 : 0 : err = recv(sockfd, &ident_size, 4, 0);
346 [ # # ]: 0 : if (err != 4) {
347 : 0 : PMD_CPP_LOG(ERR, "read error from socket");
348 : 0 : return -EIO;
349 : : }
350 : :
351 : 0 : tmp = nfp_cpp_model(cpp);
352 : :
353 : 0 : PMD_CPP_LOG(DEBUG, "%s: sending NFP model %08x", __func__, tmp);
354 : :
355 : 0 : err = send(sockfd, &tmp, 4, 0);
356 [ # # ]: 0 : if (err != 4) {
357 : 0 : PMD_CPP_LOG(ERR, "error writing to socket");
358 : 0 : return -EIO;
359 : : }
360 : :
361 : 0 : tmp = nfp_cpp_interface(cpp);
362 : :
363 : 0 : PMD_CPP_LOG(DEBUG, "%s: sending NFP interface %08x", __func__, tmp);
364 : :
365 : 0 : err = send(sockfd, &tmp, 4, 0);
366 [ # # ]: 0 : if (err != 4) {
367 : 0 : PMD_CPP_LOG(ERR, "error writing to socket");
368 : 0 : return -EIO;
369 : : }
370 : :
371 : : return 0;
372 : : }
373 : :
374 : : /*
375 : : * This is the code to be executed by a service core. The CPP bridge interface
376 : : * is based on a unix socket and requests usually received by a kernel char
377 : : * driver, read, write and ioctl, are handled by the CPP bridge. NFP host tools
378 : : * can be executed with a wrapper library and LD_LIBRARY being completely
379 : : * unaware of the CPP bridge performing the NFP kernel char driver for CPP
380 : : * accesses.
381 : : */
382 : : static int
383 : 0 : nfp_cpp_bridge_service_func(void *args)
384 : : {
385 : : int op;
386 : : int ret;
387 : : int sockfd;
388 : : int datafd;
389 : : struct nfp_cpp *cpp;
390 : : struct sockaddr address;
391 : : struct nfp_pf_dev *pf_dev;
392 : 0 : struct timeval timeout = {1, 0};
393 : :
394 : 0 : unlink("/tmp/nfp_cpp");
395 : :
396 : 0 : sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
397 [ # # ]: 0 : if (sockfd < 0) {
398 : 0 : PMD_CPP_LOG(ERR, "socket creation error. Service failed");
399 : 0 : return -EIO;
400 : : }
401 : :
402 : 0 : setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
403 : :
404 : : memset(&address, 0, sizeof(struct sockaddr));
405 : :
406 : 0 : address.sa_family = AF_UNIX;
407 : : strcpy(address.sa_data, "/tmp/nfp_cpp");
408 : :
409 : 0 : ret = bind(sockfd, (const struct sockaddr *)&address,
410 : : sizeof(struct sockaddr));
411 [ # # ]: 0 : if (ret < 0) {
412 : 0 : PMD_CPP_LOG(ERR, "bind error (%d). Service failed", errno);
413 : 0 : close(sockfd);
414 : 0 : return ret;
415 : : }
416 : :
417 : 0 : ret = listen(sockfd, 20);
418 [ # # ]: 0 : if (ret < 0) {
419 : 0 : PMD_CPP_LOG(ERR, "listen error(%d). Service failed", errno);
420 : 0 : close(sockfd);
421 : 0 : return ret;
422 : : }
423 : :
424 : : pf_dev = args;
425 : 0 : cpp = pf_dev->cpp;
426 [ # # ]: 0 : while (rte_service_runstate_get(pf_dev->cpp_bridge_id) != 0) {
427 : 0 : datafd = accept(sockfd, NULL, NULL);
428 [ # # ]: 0 : if (datafd < 0) {
429 [ # # ]: 0 : if (errno == EAGAIN || errno == EWOULDBLOCK)
430 : 0 : continue;
431 : :
432 : 0 : PMD_CPP_LOG(ERR, "accept call error (%d)", errno);
433 : 0 : PMD_CPP_LOG(ERR, "service failed");
434 : 0 : close(sockfd);
435 : 0 : return -EIO;
436 : : }
437 : :
438 : : for (;;) {
439 : 0 : ret = recv(datafd, &op, 4, 0);
440 [ # # ]: 0 : if (ret <= 0) {
441 : 0 : PMD_CPP_LOG(DEBUG, "%s: socket close", __func__);
442 : 0 : break;
443 : : }
444 : :
445 : 0 : PMD_CPP_LOG(DEBUG, "%s: getting op %u", __func__, op);
446 : :
447 [ # # ]: 0 : if (op == NFP_BRIDGE_OP_READ)
448 : 0 : nfp_cpp_bridge_serve_read(datafd, cpp);
449 : :
450 [ # # ]: 0 : if (op == NFP_BRIDGE_OP_WRITE)
451 : 0 : nfp_cpp_bridge_serve_write(datafd, cpp);
452 : :
453 [ # # ]: 0 : if (op == NFP_BRIDGE_OP_IOCTL)
454 : 0 : nfp_cpp_bridge_serve_ioctl(datafd, cpp);
455 : :
456 [ # # ]: 0 : if (op == 0)
457 : : break;
458 : : }
459 : :
460 : 0 : close(datafd);
461 : : }
462 : :
463 : 0 : close(sockfd);
464 : :
465 : 0 : return 0;
466 : : }
|