1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2014-2021 Netronome Systems, Inc.
5 * Small portions derived from code Copyright(c) 2010-2015 Intel Corporation.
9 * vim:shiftwidth=8:noexpandtab
11 * @file dpdk/pmd/nfp_cpp_bridge.c
13 * Netronome vNIC DPDK Poll-Mode Driver: CPP Bridge
16 #include <rte_service_component.h>
18 #include "nfpcore/nfp_cpp.h"
19 #include "nfpcore/nfp_mip.h"
20 #include "nfpcore/nfp_nsp.h"
23 #include "nfp_cpp_bridge.h"
25 #include <sys/ioctl.h>
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);
32 void nfp_register_cpp_service(struct nfp_cpp *cpp)
34 uint32_t *cpp_service_id = NULL;
35 struct rte_service_spec service;
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;
42 if (rte_service_component_register(&service,
44 RTE_LOG(WARNING, PMD, "NFP CPP bridge service register() failed");
46 RTE_LOG(DEBUG, PMD, "NFP CPP bridge service registered");
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.
55 nfp_cpp_bridge_serve_write(int sockfd, struct nfp_cpp *cpp)
57 struct nfp_cpp_area *area;
58 off_t offset, nfp_offset;
59 uint32_t cpp_id, pos, len;
61 size_t count, curlen, totlen = 0;
64 PMD_CPP_LOG(DEBUG, "%s: offset size %zu, count_size: %zu\n", __func__,
65 sizeof(off_t), sizeof(size_t));
67 /* Reading the count param */
68 err = recv(sockfd, &count, sizeof(off_t), 0);
69 if (err != sizeof(off_t))
74 /* Reading the offset param */
75 err = recv(sockfd, &offset, sizeof(off_t), 0);
76 if (err != sizeof(off_t))
79 /* Obtain target's CPP ID and offset in target */
80 cpp_id = (offset >> 40) << 8;
81 nfp_offset = offset & ((1ull << 40) - 1);
83 PMD_CPP_LOG(DEBUG, "%s: count %zu and offset %jd\n", __func__, count,
85 PMD_CPP_LOG(DEBUG, "%s: cpp_id %08x and nfp_offset %jd\n", __func__,
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));
96 /* configure a CPP PCIe2CPP BAR for mapping the CPP target */
97 area = nfp_cpp_area_alloc_with_name(cpp, cpp_id, "nfp.cdev",
100 RTE_LOG(ERR, PMD, "%s: area alloc fail\n", __func__);
104 /* mapping the target */
105 err = nfp_cpp_area_acquire(area);
107 RTE_LOG(ERR, PMD, "area acquire failed\n");
108 nfp_cpp_area_free(area);
112 for (pos = 0; pos < curlen; pos += len) {
114 if (len > sizeof(tmpbuf))
115 len = sizeof(tmpbuf);
117 PMD_CPP_LOG(DEBUG, "%s: Receive %u of %zu\n", __func__,
119 err = recv(sockfd, tmpbuf, len, MSG_WAITALL);
120 if (err != (int)len) {
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);
128 err = nfp_cpp_area_write(area, pos, tmpbuf, len);
130 RTE_LOG(ERR, PMD, "nfp_cpp_area_write error\n");
131 nfp_cpp_area_release(area);
132 nfp_cpp_area_free(area);
139 nfp_cpp_area_release(area);
140 nfp_cpp_area_free(area);
143 curlen = (count > NFP_CPP_MEMIO_BOUNDARY) ?
144 NFP_CPP_MEMIO_BOUNDARY : count;
151 * Serving a read request to NFP from host programs. The request
152 * sends the read size and the CPP target. The bridge makes use
153 * of CPP interface handler configured by the PMD setup. The read
154 * data is sent to the requester using the same socket.
157 nfp_cpp_bridge_serve_read(int sockfd, struct nfp_cpp *cpp)
159 struct nfp_cpp_area *area;
160 off_t offset, nfp_offset;
161 uint32_t cpp_id, pos, len;
163 size_t count, curlen, totlen = 0;
166 PMD_CPP_LOG(DEBUG, "%s: offset size %zu, count_size: %zu\n", __func__,
167 sizeof(off_t), sizeof(size_t));
169 /* Reading the count param */
170 err = recv(sockfd, &count, sizeof(off_t), 0);
171 if (err != sizeof(off_t))
176 /* Reading the offset param */
177 err = recv(sockfd, &offset, sizeof(off_t), 0);
178 if (err != sizeof(off_t))
181 /* Obtain target's CPP ID and offset in target */
182 cpp_id = (offset >> 40) << 8;
183 nfp_offset = offset & ((1ull << 40) - 1);
185 PMD_CPP_LOG(DEBUG, "%s: count %zu and offset %jd\n", __func__, count,
187 PMD_CPP_LOG(DEBUG, "%s: cpp_id %08x and nfp_offset %jd\n", __func__,
190 /* Adjust length if not aligned */
191 if (((nfp_offset + (off_t)count - 1) & ~(NFP_CPP_MEMIO_BOUNDARY - 1)) !=
192 (nfp_offset & ~(NFP_CPP_MEMIO_BOUNDARY - 1))) {
193 curlen = NFP_CPP_MEMIO_BOUNDARY -
194 (nfp_offset & (NFP_CPP_MEMIO_BOUNDARY - 1));
198 area = nfp_cpp_area_alloc_with_name(cpp, cpp_id, "nfp.cdev",
201 RTE_LOG(ERR, PMD, "%s: area alloc failed\n", __func__);
205 err = nfp_cpp_area_acquire(area);
207 RTE_LOG(ERR, PMD, "area acquire failed\n");
208 nfp_cpp_area_free(area);
212 for (pos = 0; pos < curlen; pos += len) {
214 if (len > sizeof(tmpbuf))
215 len = sizeof(tmpbuf);
217 err = nfp_cpp_area_read(area, pos, tmpbuf, len);
219 RTE_LOG(ERR, PMD, "nfp_cpp_area_read error\n");
220 nfp_cpp_area_release(area);
221 nfp_cpp_area_free(area);
224 PMD_CPP_LOG(DEBUG, "%s: sending %u of %zu\n", __func__,
227 err = send(sockfd, tmpbuf, len, 0);
228 if (err != (int)len) {
230 "%s: error when sending: %d of %zu\n",
231 __func__, err, count);
232 nfp_cpp_area_release(area);
233 nfp_cpp_area_free(area);
240 nfp_cpp_area_release(area);
241 nfp_cpp_area_free(area);
244 curlen = (count > NFP_CPP_MEMIO_BOUNDARY) ?
245 NFP_CPP_MEMIO_BOUNDARY : count;
251 * Serving a ioctl command from host NFP tools. This usually goes to
252 * a kernel driver char driver but it is not available when the PF is
253 * bound to the PMD. Currently just one ioctl command is served and it
254 * does not require any CPP access at all.
257 nfp_cpp_bridge_serve_ioctl(int sockfd, struct nfp_cpp *cpp)
259 uint32_t cmd, ident_size, tmp;
262 /* Reading now the IOCTL command */
263 err = recv(sockfd, &cmd, 4, 0);
265 RTE_LOG(ERR, PMD, "%s: read error from socket\n", __func__);
269 /* Only supporting NFP_IOCTL_CPP_IDENTIFICATION */
270 if (cmd != NFP_IOCTL_CPP_IDENTIFICATION) {
271 RTE_LOG(ERR, PMD, "%s: unknown cmd %d\n", __func__, cmd);
275 err = recv(sockfd, &ident_size, 4, 0);
277 RTE_LOG(ERR, PMD, "%s: read error from socket\n", __func__);
281 tmp = nfp_cpp_model(cpp);
283 PMD_CPP_LOG(DEBUG, "%s: sending NFP model %08x\n", __func__, tmp);
285 err = send(sockfd, &tmp, 4, 0);
287 RTE_LOG(ERR, PMD, "%s: error writing to socket\n", __func__);
291 tmp = cpp->interface;
293 PMD_CPP_LOG(DEBUG, "%s: sending NFP interface %08x\n", __func__, tmp);
295 err = send(sockfd, &tmp, 4, 0);
297 RTE_LOG(ERR, PMD, "%s: error writing to socket\n", __func__);
305 * This is the code to be executed by a service core. The CPP bridge interface
306 * is based on a unix socket and requests usually received by a kernel char
307 * driver, read, write and ioctl, are handled by the CPP bridge. NFP host tools
308 * can be executed with a wrapper library and LD_LIBRARY being completely
309 * unaware of the CPP bridge performing the NFP kernel char driver for CPP
313 nfp_cpp_bridge_service_func(void *args)
315 struct sockaddr address;
316 struct nfp_cpp *cpp = args;
317 int sockfd, datafd, op, ret;
319 unlink("/tmp/nfp_cpp");
320 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
322 RTE_LOG(ERR, PMD, "%s: socket creation error. Service failed\n",
327 memset(&address, 0, sizeof(struct sockaddr));
329 address.sa_family = AF_UNIX;
330 strcpy(address.sa_data, "/tmp/nfp_cpp");
332 ret = bind(sockfd, (const struct sockaddr *)&address,
333 sizeof(struct sockaddr));
335 RTE_LOG(ERR, PMD, "%s: bind error (%d). Service failed\n",
341 ret = listen(sockfd, 20);
343 RTE_LOG(ERR, PMD, "%s: listen error(%d). Service failed\n",
350 datafd = accept(sockfd, NULL, NULL);
352 RTE_LOG(ERR, PMD, "%s: accept call error (%d)\n",
354 RTE_LOG(ERR, PMD, "%s: service failed\n", __func__);
360 ret = recv(datafd, &op, 4, 0);
362 PMD_CPP_LOG(DEBUG, "%s: socket close\n",
367 PMD_CPP_LOG(DEBUG, "%s: getting op %u\n", __func__, op);
369 if (op == NFP_BRIDGE_OP_READ)
370 nfp_cpp_bridge_serve_read(datafd, cpp);
372 if (op == NFP_BRIDGE_OP_WRITE)
373 nfp_cpp_bridge_serve_write(datafd, cpp);
375 if (op == NFP_BRIDGE_OP_IOCTL)
376 nfp_cpp_bridge_serve_ioctl(datafd, cpp);
389 * c-file-style: "Linux"
390 * indent-tabs-mode: t