1 /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2 *
3 * Copyright 2011-2016 Freescale Semiconductor Inc.
4 * Copyright 2017,2020,2022,2024 NXP
5 *
6 */
7 #include <assert.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <sys/ioctl.h>
11 #include <rte_ethdev.h>
12
13 #include "process.h"
14
15 #include <fsl_usd.h>
16 #include "rte_dpaa_logs.h"
17
18 /* As higher-level drivers will be built on top of this (dma_mem, qbman, ...),
19 * it's preferable that the process driver itself not provide any exported API.
20 * As such, combined with the fact that none of these operations are
21 * performance critical, it is justified to use lazy initialisation, so that's
22 * what the lock is for.
23 */
24 static int fd = -1;
25 static pthread_mutex_t fd_init_lock = PTHREAD_MUTEX_INITIALIZER;
26
check_fd(void)27 static int check_fd(void)
28 {
29 int ret;
30
31 ret = pthread_mutex_lock(&fd_init_lock);
32 assert(!ret);
33
34 /* check again with the lock held */
35 if (fd < 0)
36 fd = open(PROCESS_PATH, O_RDWR);
37
38 ret = pthread_mutex_unlock(&fd_init_lock);
39 assert(!ret);
40
41 return (fd >= 0) ? 0 : -ENODEV;
42 }
43
44 #define DPAA_IOCTL_MAGIC 'u'
45 struct dpaa_ioctl_id_alloc {
46 uint32_t base; /* Return value, the start of the allocated range */
47 enum dpaa_id_type id_type; /* what kind of resource(s) to allocate */
48 uint32_t num; /* how many IDs to allocate (and return value) */
49 uint32_t align; /* must be a power of 2, 0 is treated like 1 */
50 int partial; /* whether to allow less than 'num' */
51 };
52
53 struct dpaa_ioctl_id_release {
54 /* Input; */
55 enum dpaa_id_type id_type;
56 uint32_t base;
57 uint32_t num;
58 };
59
60 struct dpaa_ioctl_id_reserve {
61 enum dpaa_id_type id_type;
62 uint32_t base;
63 uint32_t num;
64 };
65
66 #define DPAA_IOCTL_ID_ALLOC \
67 _IOWR(DPAA_IOCTL_MAGIC, 0x01, struct dpaa_ioctl_id_alloc)
68 #define DPAA_IOCTL_ID_RELEASE \
69 _IOW(DPAA_IOCTL_MAGIC, 0x02, struct dpaa_ioctl_id_release)
70 #define DPAA_IOCTL_ID_RESERVE \
71 _IOW(DPAA_IOCTL_MAGIC, 0x0A, struct dpaa_ioctl_id_reserve)
72
process_alloc(enum dpaa_id_type id_type,uint32_t * base,uint32_t num,uint32_t align,int partial)73 int process_alloc(enum dpaa_id_type id_type, uint32_t *base, uint32_t num,
74 uint32_t align, int partial)
75 {
76 struct dpaa_ioctl_id_alloc id = {
77 .id_type = id_type,
78 .num = num,
79 .align = align,
80 .partial = partial
81 };
82 int ret = check_fd();
83
84 if (ret)
85 return ret;
86 ret = ioctl(fd, DPAA_IOCTL_ID_ALLOC, &id);
87 if (ret)
88 return ret;
89 for (ret = 0; ret < (int)id.num; ret++)
90 base[ret] = id.base + ret;
91 return id.num;
92 }
93
process_release(enum dpaa_id_type id_type,uint32_t base,uint32_t num)94 void process_release(enum dpaa_id_type id_type, uint32_t base, uint32_t num)
95 {
96 struct dpaa_ioctl_id_release id = {
97 .id_type = id_type,
98 .base = base,
99 .num = num
100 };
101 int ret = check_fd();
102
103 if (ret) {
104 DPAA_BUS_ERR("Process FD failure");
105 return;
106 }
107 ret = ioctl(fd, DPAA_IOCTL_ID_RELEASE, &id);
108 if (ret)
109 DPAA_BUS_ERR("Process FD ioctl failure type %d base 0x%x num %d",
110 id_type, base, num);
111 }
112
process_reserve(enum dpaa_id_type id_type,uint32_t base,uint32_t num)113 int process_reserve(enum dpaa_id_type id_type, uint32_t base, uint32_t num)
114 {
115 struct dpaa_ioctl_id_reserve id = {
116 .id_type = id_type,
117 .base = base,
118 .num = num
119 };
120 int ret = check_fd();
121
122 if (ret)
123 return ret;
124 return ioctl(fd, DPAA_IOCTL_ID_RESERVE, &id);
125 }
126
127 /***************************************/
128 /* Mapping and using QMan/BMan portals */
129 /***************************************/
130
131 #define DPAA_IOCTL_PORTAL_MAP \
132 _IOWR(DPAA_IOCTL_MAGIC, 0x07, struct dpaa_ioctl_portal_map)
133 #define DPAA_IOCTL_PORTAL_UNMAP \
134 _IOW(DPAA_IOCTL_MAGIC, 0x08, struct dpaa_portal_map)
135
process_portal_map(struct dpaa_ioctl_portal_map * params)136 int process_portal_map(struct dpaa_ioctl_portal_map *params)
137 {
138 int ret = check_fd();
139
140 if (ret)
141 return ret;
142
143 ret = ioctl(fd, DPAA_IOCTL_PORTAL_MAP, params);
144 if (ret) {
145 perror("ioctl(DPAA_IOCTL_PORTAL_MAP)");
146 return ret;
147 }
148 return 0;
149 }
150
process_portal_unmap(struct dpaa_portal_map * map)151 int process_portal_unmap(struct dpaa_portal_map *map)
152 {
153 int ret = check_fd();
154
155 if (ret)
156 return ret;
157
158 ret = ioctl(fd, DPAA_IOCTL_PORTAL_UNMAP, map);
159 if (ret) {
160 perror("ioctl(DPAA_IOCTL_PORTAL_UNMAP)");
161 return ret;
162 }
163 return 0;
164 }
165
166 #define DPAA_IOCTL_PORTAL_IRQ_MAP \
167 _IOW(DPAA_IOCTL_MAGIC, 0x09, struct dpaa_ioctl_irq_map)
168
process_portal_irq_map(int ifd,struct dpaa_ioctl_irq_map * map)169 int process_portal_irq_map(int ifd, struct dpaa_ioctl_irq_map *map)
170 {
171 map->fd = fd;
172 return ioctl(ifd, DPAA_IOCTL_PORTAL_IRQ_MAP, map);
173 }
174
process_portal_irq_unmap(int ifd)175 int process_portal_irq_unmap(int ifd)
176 {
177 return close(ifd);
178 }
179
180 struct dpaa_ioctl_raw_portal {
181 /* inputs */
182 enum dpaa_portal_type type; /* Type of portal to allocate */
183
184 uint8_t enable_stash; /* set to non zero to turn on stashing */
185 /* Stashing attributes for the portal */
186 uint32_t cpu;
187 uint32_t cache;
188 uint32_t window;
189 /* Specifies the stash request queue this portal should use */
190 uint8_t sdest;
191
192 /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX
193 * for don't care. The portal index will be populated by the
194 * driver when the ioctl() successfully completes.
195 */
196 uint32_t index;
197
198 /* outputs */
199 uint64_t cinh;
200 uint64_t cena;
201 };
202
203 #define DPAA_IOCTL_ALLOC_RAW_PORTAL \
204 _IOWR(DPAA_IOCTL_MAGIC, 0x0C, struct dpaa_ioctl_raw_portal)
205
206 #define DPAA_IOCTL_FREE_RAW_PORTAL \
207 _IOR(DPAA_IOCTL_MAGIC, 0x0D, struct dpaa_ioctl_raw_portal)
208
process_portal_allocate(struct dpaa_ioctl_raw_portal * portal)209 static int process_portal_allocate(struct dpaa_ioctl_raw_portal *portal)
210 {
211 int ret = check_fd();
212
213 if (ret)
214 return ret;
215
216 ret = ioctl(fd, DPAA_IOCTL_ALLOC_RAW_PORTAL, portal);
217 if (ret) {
218 perror("ioctl(DPAA_IOCTL_ALLOC_RAW_PORTAL)");
219 return ret;
220 }
221 return 0;
222 }
223
process_portal_free(struct dpaa_ioctl_raw_portal * portal)224 static int process_portal_free(struct dpaa_ioctl_raw_portal *portal)
225 {
226 int ret = check_fd();
227
228 if (ret)
229 return ret;
230
231 ret = ioctl(fd, DPAA_IOCTL_FREE_RAW_PORTAL, portal);
232 if (ret) {
233 perror("ioctl(DPAA_IOCTL_FREE_RAW_PORTAL)");
234 return ret;
235 }
236 return 0;
237 }
238
qman_allocate_raw_portal(struct dpaa_raw_portal * portal)239 int qman_allocate_raw_portal(struct dpaa_raw_portal *portal)
240 {
241 struct dpaa_ioctl_raw_portal input;
242 int ret;
243
244 input.type = dpaa_portal_qman;
245 input.index = portal->index;
246 input.enable_stash = portal->enable_stash;
247 input.cpu = portal->cpu;
248 input.cache = portal->cache;
249 input.window = portal->window;
250 input.sdest = portal->sdest;
251
252 ret = process_portal_allocate(&input);
253 if (ret)
254 return ret;
255 portal->index = input.index;
256 portal->cinh = input.cinh;
257 portal->cena = input.cena;
258 return 0;
259 }
260
qman_free_raw_portal(struct dpaa_raw_portal * portal)261 int qman_free_raw_portal(struct dpaa_raw_portal *portal)
262 {
263 struct dpaa_ioctl_raw_portal input;
264
265 input.type = dpaa_portal_qman;
266 input.index = portal->index;
267 input.cinh = portal->cinh;
268 input.cena = portal->cena;
269
270 return process_portal_free(&input);
271 }
272
bman_allocate_raw_portal(struct dpaa_raw_portal * portal)273 int bman_allocate_raw_portal(struct dpaa_raw_portal *portal)
274 {
275 struct dpaa_ioctl_raw_portal input;
276 int ret;
277
278 input.type = dpaa_portal_bman;
279 input.index = portal->index;
280 input.enable_stash = 0;
281
282 ret = process_portal_allocate(&input);
283 if (ret)
284 return ret;
285 portal->index = input.index;
286 portal->cinh = input.cinh;
287 portal->cena = input.cena;
288 return 0;
289 }
290
bman_free_raw_portal(struct dpaa_raw_portal * portal)291 int bman_free_raw_portal(struct dpaa_raw_portal *portal)
292 {
293 struct dpaa_ioctl_raw_portal input;
294
295 input.type = dpaa_portal_bman;
296 input.index = portal->index;
297 input.cinh = portal->cinh;
298 input.cena = portal->cena;
299
300 return process_portal_free(&input);
301 }
302
303 #define DPAA_IOCTL_ENABLE_LINK_STATUS_INTERRUPT \
304 _IOW(DPAA_IOCTL_MAGIC, 0x0E, struct usdpaa_ioctl_link_status)
305
306 #define DPAA_IOCTL_DISABLE_LINK_STATUS_INTERRUPT \
307 _IOW(DPAA_IOCTL_MAGIC, 0x0F, char[IF_NAME_MAX_LEN])
308
dpaa_intr_enable(char * if_name,int efd)309 int dpaa_intr_enable(char *if_name, int efd)
310 {
311 struct usdpaa_ioctl_link_status args;
312
313 int ret = check_fd();
314
315 if (ret)
316 return ret;
317
318 args.efd = (uint32_t)efd;
319 strcpy(args.if_name, if_name);
320
321 ret = ioctl(fd, DPAA_IOCTL_ENABLE_LINK_STATUS_INTERRUPT, &args);
322 if (ret)
323 return errno;
324
325 return 0;
326 }
327
dpaa_intr_disable(char * if_name)328 int dpaa_intr_disable(char *if_name)
329 {
330 int ret = check_fd();
331
332 if (ret)
333 return ret;
334
335 ret = ioctl(fd, DPAA_IOCTL_DISABLE_LINK_STATUS_INTERRUPT, if_name);
336 if (ret) {
337 if (errno == EINVAL)
338 DPAA_BUS_ERR("Failed to disable interrupt: Not Supported");
339 else
340 DPAA_BUS_ERR("Failed to disable interrupt");
341 return ret;
342 }
343
344 return 0;
345 }
346
347 #define DPAA_IOCTL_GET_IOCTL_VERSION \
348 _IOR(DPAA_IOCTL_MAGIC, 0x14, int)
349
dpaa_get_ioctl_version_number(void)350 int dpaa_get_ioctl_version_number(void)
351 {
352 int version_num, ret = check_fd();
353
354 if (ret)
355 return ret;
356
357 ret = ioctl(fd, DPAA_IOCTL_GET_IOCTL_VERSION, &version_num);
358 if (ret) {
359 if (errno == EINVAL) {
360 version_num = 1;
361 } else {
362 DPAA_BUS_ERR("Failed to get ioctl version number");
363 version_num = -1;
364 }
365 }
366
367 return version_num;
368 }
369
370 #define DPAA_IOCTL_GET_LINK_STATUS \
371 _IOWR(DPAA_IOCTL_MAGIC, 0x10, struct usdpaa_ioctl_link_status_args)
372
373 #define DPAA_IOCTL_GET_LINK_STATUS_OLD \
374 _IOWR(DPAA_IOCTL_MAGIC, 0x10, struct usdpaa_ioctl_link_status_args_old)
375
376
dpaa_get_link_status(char * if_name,struct rte_eth_link * link)377 int dpaa_get_link_status(char *if_name, struct rte_eth_link *link)
378 {
379 int ioctl_version, ret = check_fd();
380
381 if (ret)
382 return ret;
383
384 ioctl_version = dpaa_get_ioctl_version_number();
385
386 if (ioctl_version == 2) {
387 struct usdpaa_ioctl_link_status_args args;
388
389 strcpy(args.if_name, if_name);
390
391 ret = ioctl(fd, DPAA_IOCTL_GET_LINK_STATUS, &args);
392 if (ret) {
393 DPAA_BUS_ERR("Failed to get link status");
394 return ret;
395 }
396
397 link->link_status = args.link_status;
398 link->link_speed = args.link_speed;
399 link->link_duplex = args.link_duplex;
400 link->link_autoneg = args.link_autoneg;
401 } else {
402 struct usdpaa_ioctl_link_status_args_old args;
403
404 strcpy(args.if_name, if_name);
405
406 ret = ioctl(fd, DPAA_IOCTL_GET_LINK_STATUS_OLD, &args);
407 if (ret) {
408 if (errno == EINVAL)
409 DPAA_BUS_ERR("Get link status: Not Supported");
410 else
411 DPAA_BUS_ERR("Failed to get link status");
412 return ret;
413 }
414
415 link->link_status = args.link_status;
416 }
417
418 return 0;
419 }
420
421 #define DPAA_IOCTL_UPDATE_LINK_STATUS \
422 _IOW(DPAA_IOCTL_MAGIC, 0x11, struct usdpaa_ioctl_update_link_status_args)
423
dpaa_update_link_status(char * if_name,int link_status)424 int dpaa_update_link_status(char *if_name, int link_status)
425 {
426 struct usdpaa_ioctl_update_link_status_args args;
427 int ret;
428
429 ret = check_fd();
430 if (ret)
431 return ret;
432
433 strcpy(args.if_name, if_name);
434 args.link_status = link_status;
435
436 ret = ioctl(fd, DPAA_IOCTL_UPDATE_LINK_STATUS, &args);
437 if (ret) {
438 if (errno == EINVAL)
439 DPAA_BUS_ERR("Failed to set link status: Not Supported");
440 else
441 DPAA_BUS_ERR("Failed to set link status");
442 return ret;
443 }
444
445 return 0;
446 }
447
448 #define DPAA_IOCTL_UPDATE_LINK_SPEED \
449 _IOW(DPAA_IOCTL_MAGIC, 0x12, struct usdpaa_ioctl_update_link_speed)
450
dpaa_update_link_speed(char * if_name,int link_speed,int link_duplex)451 int dpaa_update_link_speed(char *if_name, int link_speed, int link_duplex)
452 {
453 struct usdpaa_ioctl_update_link_speed args;
454 int ret;
455
456 ret = check_fd();
457 if (ret)
458 return ret;
459
460 strcpy(args.if_name, if_name);
461 args.link_speed = link_speed;
462 args.link_duplex = link_duplex;
463
464 ret = ioctl(fd, DPAA_IOCTL_UPDATE_LINK_SPEED, &args);
465 if (ret) {
466 if (errno == EINVAL)
467 DPAA_BUS_ERR("Failed to set link speed: Not Supported");
468 else
469 DPAA_BUS_ERR("Failed to set link speed");
470 return ret;
471 }
472
473 return ret;
474 }
475
476 #define DPAA_IOCTL_RESTART_LINK_AUTONEG \
477 _IOW(DPAA_IOCTL_MAGIC, 0x13, char[IF_NAME_MAX_LEN])
478
dpaa_restart_link_autoneg(char * if_name)479 int dpaa_restart_link_autoneg(char *if_name)
480 {
481 int ret = check_fd();
482
483 if (ret)
484 return ret;
485
486 ret = ioctl(fd, DPAA_IOCTL_RESTART_LINK_AUTONEG, if_name);
487 if (ret) {
488 if (errno == EINVAL)
489 DPAA_BUS_ERR("Failed to restart autoneg: Not Supported");
490 else
491 DPAA_BUS_ERR("Failed to restart autoneg");
492 return ret;
493 }
494
495 return ret;
496 }
497