Switchtec Userspace PROJECT_NUMBER = 4.4
Loading...
Searching...
No Matches
fabric.c
1/*
2 * Microsemi Switchtec(tm) PCIe Management Library
3 * Copyright (c) 2017, Microsemi Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25#include <stddef.h>
26#include <errno.h>
27#include <string.h>
28
29#include "switchtec/fabric.h"
30#include "switchtec_priv.h"
31#include "switchtec/switchtec.h"
32#include "switchtec/errors.h"
33#include "switchtec/endian.h"
34
35static int topo_info_dump_start(struct switchtec_dev *dev)
36{
37 uint8_t subcmd = MRPC_TOPO_INFO_DUMP_START;
38 uint8_t status;
39
40 return switchtec_cmd(dev, MRPC_TOPO_INFO_DUMP, &subcmd, sizeof(subcmd),
41 &status, sizeof(status));
42}
43
44static int topo_info_dump_status_get(struct switchtec_dev *dev,
45 int *status, uint16_t *info_len)
46{
47 int ret;
48
49 uint8_t subcmd = MRPC_TOPO_INFO_DUMP_STATUS_GET;
50
51 struct {
52 uint8_t status;
53 uint8_t reserved;
54 uint16_t data_len_dw;
55 } result;
56
57 ret = switchtec_cmd(dev, MRPC_TOPO_INFO_DUMP, &subcmd, sizeof(subcmd),
58 &result, sizeof(result));
59
60 *status = result.status;
61 *info_len = result.data_len_dw * 4;
62
63 return ret;
64}
65
66#define SWITCHTEC_TOPO_INFO_DUMP_DATA_LENGTH_MAX 1000
67static int topo_info_dump_data_get(struct switchtec_dev *dev, uint16_t offset,
68 char *buf, uint16_t *len)
69{
70 int ret;
71 size_t buf_len;
72
73 struct {
74 uint8_t subcmd;
75 uint8_t reserved;
76 uint16_t offset;
77 } cmd = {
78 .subcmd = MRPC_TOPO_INFO_DUMP_DATA_GET,
79 };
80
81 struct {
82 uint8_t status;
83 uint8_t reserved;
84 uint16_t data_len_dw;
85 uint8_t data[SWITCHTEC_TOPO_INFO_DUMP_DATA_LENGTH_MAX];
86 } result;
87
88 if (switchtec_is_gen5(dev))
89 cmd.subcmd = MRPC_TOPO_INFO_DUMP_DATA_GET_GEN5;
90
91 buf_len = sizeof(result);
92
93 if (*len < SWITCHTEC_TOPO_INFO_DUMP_DATA_LENGTH_MAX)
94 buf_len = *len + sizeof(result)
95 - SWITCHTEC_TOPO_INFO_DUMP_DATA_LENGTH_MAX;
96
97 cmd.offset = offset;
98
99 ret = switchtec_cmd(dev, MRPC_TOPO_INFO_DUMP, &cmd,
100 sizeof(cmd), &result, buf_len);
101
102 *len = result.data_len_dw * 4;
103
104 memcpy(buf, &(result.data), *len);
105
106 return ret;
107}
108
109static int topo_info_dump_finish(struct switchtec_dev *dev)
110{
111 uint8_t subcmd = MRPC_TOPO_INFO_DUMP_FINISH;
112 uint8_t status;
113
114 return switchtec_cmd(dev, MRPC_TOPO_INFO_DUMP, &subcmd, sizeof(subcmd),
115 &status, sizeof(status));
116}
117
118enum switchtec_fab_topo_info_dump_status {
119 SWITCHTEC_FAB_TOPO_INFO_DUMP_NOT_START = 1,
120 SWITCHTEC_FAB_TOPO_INFO_DUMP_WAIT = 2,
121 SWITCHTEC_FAB_TOPO_INFO_DUMP_READY = 3,
122 SWITCHTEC_FAB_TOPO_INFO_DUMP_FAILED = 4,
123 SWITCHTEC_FAB_TOPO_INFO_DUMP_WRONG_SUB_CMD = 5,
124};
125
126static int topo_info_dump_gen4(struct switchtec_dev *dev,
127 struct switchtec_fab_topo_info *topo_info)
128{
129 int ret;
130 int status;
131 uint16_t total_info_len, offset, buf_len;
132 struct topo_info_reply_gen4 {
133 uint8_t sw_idx;
134 uint8_t rsvd[3];
135 uint32_t stack_bif[7];
136 uint8_t route_port[16];
137 uint64_t port_bitmap;
138
139 struct switchtec_fab_port_info list[SWITCHTEC_MAX_PORTS];
140 } reply = {};
141
142 char *buf = (char *)&reply;
143
144 ret = topo_info_dump_start(dev);
145 if (ret)
146 return ret;
147
148 do {
149 ret = topo_info_dump_status_get(dev, &status, &total_info_len);
150 if (ret)
151 return ret;
152 } while (status == SWITCHTEC_FAB_TOPO_INFO_DUMP_WAIT);
153
154 if (status != SWITCHTEC_FAB_TOPO_INFO_DUMP_READY)
155 return -1;
156
157 if (total_info_len > sizeof(reply))
158 return -1;
159
160 offset = 0;
161 buf_len = sizeof(reply);
162
163 while (offset < total_info_len) {
164 ret = topo_info_dump_data_get(dev, offset,
165 buf + offset, &buf_len);
166 if (ret)
167 return ret;
168
169 offset += buf_len;
170 buf_len = sizeof(reply) - offset;
171 }
172
173 ret = topo_info_dump_finish(dev);
174 if (ret)
175 return ret;
176
177 topo_info->sw_idx = reply.sw_idx;
178 topo_info->num_stack_bif = 7;
179 memcpy(topo_info->stack_bif, reply.stack_bif, 7 * sizeof(uint32_t));
180 memcpy(topo_info->route_port, reply.route_port, 16 * sizeof(uint8_t));
181 topo_info->port_bitmap = reply.port_bitmap;
182 memcpy(topo_info->port_info_list, reply.list,
183 total_info_len - (sizeof(reply) - sizeof(reply.list)));
184
185 return 0;
186}
187
188static int topo_info_dump_gen5(struct switchtec_dev *dev,
189 struct switchtec_fab_topo_info *topo_info)
190{
191 int ret;
192 int status;
193 uint16_t total_info_len, offset, buf_len;
194 struct topo_info_reply_gen5 {
195 uint8_t sw_idx;
196 uint8_t rsvd[3];
197 uint32_t stack_bif[8];
198 uint8_t route_port[16];
199 uint64_t port_bitmap;
200
201 struct switchtec_fab_port_info list[SWITCHTEC_MAX_PORTS];
202 } reply = {};
203
204 char *buf = (char *)&reply;
205
206 ret = topo_info_dump_start(dev);
207 if (ret)
208 return ret;
209
210 do {
211 ret = topo_info_dump_status_get(dev, &status, &total_info_len);
212 if (ret)
213 return ret;
214 } while (status == SWITCHTEC_FAB_TOPO_INFO_DUMP_WAIT);
215
216 if (status != SWITCHTEC_FAB_TOPO_INFO_DUMP_READY)
217 return -1;
218
219 if (total_info_len > sizeof(reply))
220 return -1;
221
222 offset = 0;
223 buf_len = sizeof(reply);
224
225 while (offset < total_info_len) {
226 ret = topo_info_dump_data_get(dev, offset,
227 buf + offset, &buf_len);
228 if (ret)
229 return ret;
230
231 offset += buf_len;
232 buf_len = sizeof(reply) - offset;
233 }
234
235 ret = topo_info_dump_finish(dev);
236 if (ret)
237 return ret;
238
239 topo_info->sw_idx = reply.sw_idx;
240 topo_info->num_stack_bif = 8;
241 memcpy(topo_info->stack_bif, reply.stack_bif, 8 * sizeof(uint32_t));
242 memcpy(topo_info->route_port, reply.route_port, 16 * sizeof(uint8_t));
243 topo_info->port_bitmap = reply.port_bitmap;
244 memcpy(topo_info->port_info_list, reply.list,
245 total_info_len - (sizeof(reply) - sizeof(reply.list)));
246
247 return 0;
248}
249
256int switchtec_topo_info_dump(struct switchtec_dev *dev,
257 struct switchtec_fab_topo_info *topo_info)
258{
259 if (!switchtec_is_pax_all(dev)) {
260 errno = ENOTSUP;
261 return -1;
262 }
263
264 if (switchtec_is_gen4(dev))
265 return topo_info_dump_gen4(dev, topo_info);
266 else
267 return topo_info_dump_gen5(dev, topo_info);
268}
269
270int switchtec_gfms_bind(struct switchtec_dev *dev,
271 struct switchtec_gfms_bind_req *req)
272{
273 int i;
274
275 struct {
276 uint8_t subcmd;
277 uint8_t host_sw_idx;
278 uint8_t host_phys_port_id;
279 uint8_t host_log_port_id;
280 struct {
281 uint16_t pdfid;
282 uint8_t next_valid;
283 uint8_t reserved;
284 } function[SWITCHTEC_FABRIC_MULTI_FUNC_NUM];
285 } cmd;
286
287 struct {
288 uint8_t status;
289 uint8_t reserved[3];
290 } result;
291
292 cmd.subcmd = MRPC_GFMS_BIND;
293 cmd.host_sw_idx = req->host_sw_idx;
294 cmd.host_phys_port_id = req->host_phys_port_id;
295 cmd.host_log_port_id = req->host_log_port_id;
296
297 for (i = 0; i < req->ep_number; i++) {
298 cmd.function[i].pdfid = req->ep_pdfid[i];
299 cmd.function[i].next_valid = 0;
300 if (i)
301 cmd.function[i - 1].next_valid = 1;
302 }
303
304 return switchtec_cmd(dev, MRPC_GFMS_BIND_UNBIND, &cmd, sizeof(cmd),
305 &result, sizeof(result));
306}
307
308int switchtec_gfms_unbind(struct switchtec_dev *dev,
309 struct switchtec_gfms_unbind_req *req)
310{
311 struct {
312 uint8_t subcmd;
313 uint8_t host_sw_idx;
314 uint8_t host_phys_port_id;
315 uint8_t host_log_port_id;
316 uint16_t pdfid;
317 uint8_t option;
318 uint8_t reserved;
319 } cmd;
320
321 struct {
322 uint8_t status;
323 } result;
324
325 cmd.subcmd = MRPC_GFMS_UNBIND;
326 cmd.host_sw_idx = req->host_sw_idx;
327 cmd.host_phys_port_id = req->host_phys_port_id;
328 cmd.host_log_port_id = req->host_log_port_id;
329 cmd.pdfid = req->pdfid;
330 cmd.option = req->option;
331
332 return switchtec_cmd(dev, MRPC_GFMS_BIND_UNBIND, &cmd, sizeof(cmd),
333 &result, sizeof(result));
334}
335
336int switchtec_port_control(struct switchtec_dev *dev, uint8_t control_type,
337 uint8_t phys_port_id, uint8_t hot_reset_flag)
338{
339 int ret;
340
341 struct {
342 uint8_t control_type;
343 uint8_t phys_port_id;
344 uint8_t hot_reset_flag;
345 uint8_t rsvd;
346 } cmd;
347
348 cmd.control_type = control_type;
349 cmd.phys_port_id = phys_port_id;
350 cmd.hot_reset_flag = hot_reset_flag;
351
352 ret = switchtec_cmd(dev, MRPC_PORT_CONTROL, &cmd, sizeof(cmd), NULL, 0);
353
354 return ret;
355}
356
364int switchtec_fab_port_config_get(struct switchtec_dev *dev,
365 uint8_t phys_port_id,
366 struct switchtec_fab_port_config *info)
367{
368 int ret;
369
370 struct {
371 uint8_t subcmd;
372 uint8_t phys_port_id;
373 uint8_t reserved[2];
374 } cmd;
375
376 cmd.subcmd = MRPC_PORT_CONFIG_GET;
377 cmd.phys_port_id = phys_port_id;
378
379 ret = switchtec_cmd(dev, MRPC_PORT_CONFIG, &cmd, sizeof(cmd),
380 info, sizeof(struct switchtec_fab_port_config));
381
382 return ret;
383}
384
392int switchtec_fab_port_config_set(struct switchtec_dev *dev,
393 uint8_t phys_port_id,
394 struct switchtec_fab_port_config *info)
395{
396 int ret;
397
398 struct {
399 uint8_t subcmd;
400 uint8_t phys_port_id;
401 uint8_t port_type;
402 uint8_t clock_source;
403 uint8_t clock_sris;
404 uint8_t hvd_inst;
405 uint8_t reserved[2];
406 } cmd;
407
408 cmd.subcmd = MRPC_PORT_CONFIG_SET;
409 cmd.phys_port_id = phys_port_id;
410 cmd.port_type = info->port_type;
411 cmd.clock_source = info->clock_source;
412 cmd.clock_sris = info->clock_sris;
413 cmd.hvd_inst = info->hvd_inst;
414
415 ret = switchtec_cmd(dev, MRPC_PORT_CONFIG, &cmd, sizeof(cmd),
416 info, sizeof(struct switchtec_fab_port_config));
417
418 return ret;
419}
420
421int switchtec_fab_gfms_db_dump_fabric_general(
422 struct switchtec_dev *dev,
423 struct switchtec_gfms_db_fabric_general *fabric_general)
424{
425 uint8_t subcmd = MRPC_GFMS_DB_DUMP_FABRIC;
426
427 return switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &subcmd, sizeof(subcmd),
428 fabric_general, sizeof(*fabric_general));
429}
430
431static size_t gfms_hvd_all_section_parse(
432 struct switchtec_dev *dev,
433 uint8_t *data,
434 struct switchtec_gfms_db_hvd_all *hvd_all)
435{
436 uint8_t *p;
437 int i;
438 size_t len;
439 size_t parsed_len;
440 size_t remaining_len;
441 struct switchtec_gfms_db_hvd_body *hvd_body;
442
443 p = data;
444
445 len = sizeof(hvd_all->hdr);
446 memcpy(&hvd_all->hdr, data, len);
447 p += len;
448 parsed_len = len;
449 remaining_len = hvd_all->hdr.resp_size_dw * 4 - len;
450
451 i = 0;
452 while (remaining_len) {
453 hvd_body = &hvd_all->bodies[i];
454
455 len = 8;
456 memcpy(hvd_body, p, len);
457 p += len;
458 remaining_len -= len;
459 parsed_len += len;
460
461 len = hvd_body->logical_port_count *
462 SWITCHTEC_FABRIC_MULTI_FUNC_NUM * 4;
463 memcpy(&hvd_body->bound[0], p, len);
464 p += len;
465 remaining_len -= len;
466 parsed_len += len;
467
468 i++;
469 hvd_all->hvd_count = i;
470 }
471
472 return parsed_len;
473}
474
475static size_t gfms_pax_general_section_parse(
476 struct switchtec_dev *dev,
477 uint8_t *data,
478 struct switchtec_gfms_db_pax_general *pax_general)
479{
480 size_t parsed_len;
481
482 parsed_len = sizeof(*pax_general);
483
484 memcpy(pax_general, data, parsed_len);
485
486 return parsed_len;
487}
488
489int switchtec_fab_gfms_db_dump_pax_general(
490 struct switchtec_dev *dev,
491 struct switchtec_gfms_db_pax_general *pax_general)
492{
493 uint8_t subcmd = MRPC_GFMS_DB_DUMP_PAX;
494
495 return switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &subcmd, sizeof(subcmd),
496 pax_general, sizeof(*pax_general));
497}
498
499static int gfms_dump_start(struct switchtec_dev *dev, uint8_t subcmd,
500 uint8_t param, uint32_t *total_len_dw)
501{
502 int ret;
503
504 struct {
505 uint8_t subcmd;
506 uint8_t param;
507 uint8_t reserved[2];
508 uint32_t type;
509 } cmd = {
510 .subcmd = subcmd,
511 .param = param,
512 .type = 1,
513 };
514
515 struct {
516 uint32_t dw_len;
517 uint32_t num_of_switch;
518 } rsp;
519
520 ret = switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &cmd, sizeof(cmd),
521 &rsp, sizeof(rsp));
522 *total_len_dw = rsp.dw_len;
523
524 return ret;
525}
526
527static int gfms_dump_get(struct switchtec_dev *dev, uint8_t subcmd,
528 uint32_t total_len_dw, uint8_t *data)
529{
530 int ret;
531
532 struct {
533 uint8_t subcmd;
534 uint8_t reserved[3];
535 uint32_t type;
536 uint32_t offset_dw;
537 } cmd = {
538 .subcmd = subcmd,
539 .type = 2,
540 .offset_dw = 0,
541 };
542
543 struct {
544 uint32_t offset_dw;
545 uint32_t size_dw;
546 uint32_t reserved;
547 uint8_t data[MRPC_MAX_DATA_LEN - 12];
548 } rsp = {
549 .offset_dw = 0,
550 .size_dw = 0,
551 };
552 do {
553 ret = switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &cmd, sizeof(cmd),
554 &rsp, MRPC_MAX_DATA_LEN);
555
556 if (ret)
557 break;
558
559 rsp.size_dw -= 3;
560
561 memcpy(data + (cmd.offset_dw * 4), rsp.data, rsp.size_dw * 4);
562
563 cmd.offset_dw += rsp.size_dw;
564
565 } while (total_len_dw > rsp.offset_dw + rsp.size_dw);
566
567 return ret;
568}
569
570static int gfms_dump_finish(struct switchtec_dev *dev, uint8_t subcmd)
571{
572 struct {
573 uint8_t subcmd;
574 uint8_t reserved[3];
575 uint32_t type;
576 } cmd = {
577 .subcmd = subcmd,
578 .type = 3,
579 };
580
581 return switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &cmd, sizeof(cmd),
582 NULL, 0);
583}
584
585int switchtec_fab_gfms_db_dump_hvd(struct switchtec_dev *dev,
586 uint8_t hvd_idx,
587 struct switchtec_gfms_db_hvd *hvd)
588{
589 uint32_t total_len_dw;
590 int ret;
591
592 ret = gfms_dump_start(dev, MRPC_GFMS_DB_DUMP_HVD,
593 hvd_idx, &total_len_dw);
594 if (ret)
595 return ret;
596
597 ret = gfms_dump_get(dev, MRPC_GFMS_DB_DUMP_HVD, total_len_dw,
598 (uint8_t *)hvd);
599 if (ret)
600 return ret;
601
602 ret = gfms_dump_finish(dev, MRPC_GFMS_DB_DUMP_HVD);
603 if (ret)
604 return ret;
605
606 return 0;
607}
608
609int switchtec_fab_gfms_db_dump_hvd_detail(
610 struct switchtec_dev *dev,
611 uint8_t hvd_idx,
612 struct switchtec_gfms_db_hvd_detail *hvd_detail)
613{
614 uint32_t total_len_dw;
615 int ret;
616 uint8_t *data;
618 void *p;
619 int len;
620 uint64_t bitmap;
621 int i;
622
623 ret = gfms_dump_start(dev, MRPC_GFMS_DB_DUMP_HVD_DETAIL,
624 hvd_idx, &total_len_dw);
625 if (ret)
626 return ret;
627
628 data = malloc(total_len_dw * 4);
629 if (!data)
630 return -ENOMEM;
631 ret = gfms_dump_get(dev, MRPC_GFMS_DB_DUMP_HVD_DETAIL, total_len_dw,
632 (uint8_t *)data);
633 if (ret) {
634 free(data);
635 return ret;
636 }
637
638 ret = gfms_dump_finish(dev, MRPC_GFMS_DB_DUMP_HVD_DETAIL);
639 if (ret) {
640 free(data);
641 return ret;
642 }
643
644 memcpy(&hvd_detail->hdr, data, sizeof(hvd_detail->hdr));
645
646 body = (struct switchtec_gfms_db_hvd_detail_body *)(data + sizeof(hvd_detail->hdr));
647
648 p = (void *)body;
649 hvd_detail->body.hvd_inst_id = body->hvd_inst_id;
650 hvd_detail->body.phy_pid = body->phy_pid;
651 hvd_detail->body.hfid = body->hfid;
652 hvd_detail->body.vep_count = body->vep_count;
653 hvd_detail->body.usp_status = body->usp_status;
654
655 p += offsetof(struct switchtec_gfms_db_hvd_detail_body, vep_region);
656 len = sizeof(body->vep_region[0]) * body->vep_count;
657 memcpy(hvd_detail->body.vep_region, body->vep_region, len);
658 p += len;
659
660 len = sizeof(hvd_detail->body.log_dsp_count);
661 memcpy(&hvd_detail->body.log_dsp_count, p, len);
662 p += len;
663
664 len = sizeof(hvd_detail->body.usp_bdf);
665 memcpy(&hvd_detail->body.usp_bdf, p, len);
666 p += len;
667
668 len = sizeof(hvd_detail->body.log_port_region[0]) *
669 le16toh(hvd_detail->body.log_dsp_count) *
670 SWITCHTEC_FABRIC_MULTI_FUNC_NUM;
671 memcpy(hvd_detail->body.log_port_region, p, len);
672 p += len;
673
674 len = sizeof(hvd_detail->body.log_port_p2p_enable_bitmap_low);
675 memcpy(&hvd_detail->body.log_port_p2p_enable_bitmap_low, p, len);
676 p += len;
677
678 len = sizeof(hvd_detail->body.log_port_p2p_enable_bitmap_high);
679 memcpy(&hvd_detail->body.log_port_p2p_enable_bitmap_high, p, len);
680 p += len;
681
682 bitmap = le32toh(hvd_detail->body.log_port_p2p_enable_bitmap_high);
683 bitmap <<= 32;
684 bitmap |= le32toh(hvd_detail->body.log_port_p2p_enable_bitmap_low);
685
686 hvd_detail->body.log_port_count = 0;
687 for (i = 0; i < (sizeof(bitmap) * 8); i++)
688 if (bitmap >> i && 0x1)
689 hvd_detail->body.log_port_count++;
690
691 len = sizeof(hvd_detail->body.log_port_p2p_bitmap[0]) *
692 hvd_detail->body.log_port_count;
693 memcpy(hvd_detail->body.log_port_p2p_bitmap, p, len);
694
695 free(data);
696 return 0;
697}
698
699int switchtec_fab_gfms_db_dump_fab_port(
700 struct switchtec_dev *dev,
701 uint8_t phy_pid,
702 struct switchtec_gfms_db_fab_port *fab_port)
703{
704 struct {
705 uint8_t subcmd;
706 uint8_t phy_pid;
707 } cmd = {
708 .subcmd = MRPC_GFMS_DB_DUMP_FAB_PORT,
709 .phy_pid = phy_pid,
710 };
711
712 return switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &cmd, sizeof(cmd),
713 fab_port, sizeof(*fab_port));
714}
715
716static int gfms_ep_port_start(struct switchtec_dev *dev,
717 uint8_t fab_ep_pid,
718 uint32_t *total_len_dw)
719{
720 int ret;
721
722 struct {
723 uint8_t subcmd;
724 uint8_t fab_ep_pid;
725 uint16_t reserved;
726 uint32_t type;
727 } cmd = {
728 .subcmd = MRPC_GFMS_DB_DUMP_EP_PORT,
729 .fab_ep_pid = fab_ep_pid,
730 .type = 1,
731 };
732
733 struct {
734 uint32_t dw_len;
735 uint32_t num_of_switch;
736 } rsp;
737
738 ret = switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &cmd, sizeof(cmd),
739 &rsp, sizeof(rsp));
740 *total_len_dw = rsp.dw_len;
741
742 return ret;
743}
744
745static int gfms_ep_port_get(struct switchtec_dev *dev,
746 uint8_t fab_ep_pid,
747 uint32_t total_len_dw,
748 uint8_t *data)
749{
750 int ret;
751
752 struct {
753 uint8_t subcmd;
754 uint8_t fab_ep_pid;
755 uint16_t reserved;
756 uint32_t type;
757 uint32_t offset_dw;
758 } cmd = {
759 .subcmd = MRPC_GFMS_DB_DUMP_EP_PORT,
760 .fab_ep_pid = fab_ep_pid,
761 .type = 2,
762 .offset_dw = 0,
763 };
764
765 struct {
766 uint32_t offset_dw;
767 uint32_t size_dw;
768 uint32_t reserved;
769 uint8_t data[MRPC_MAX_DATA_LEN - 12];
770 } rsp = {
771 .offset_dw = 0,
772 .size_dw = 0,
773 };
774
775 do {
776 ret = switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &cmd, sizeof(cmd),
777 &rsp, MRPC_MAX_DATA_LEN);
778
779 if (ret)
780 break;
781
782 if (rsp.size_dw > 0xf0)
783 rsp.size_dw = 0xf0;
784
785 rsp.size_dw -= 3;
786
787 memcpy(data + (cmd.offset_dw * 4), rsp.data, rsp.size_dw * 4);
788
789 cmd.offset_dw += rsp.size_dw;
790
791 } while (total_len_dw > rsp.offset_dw + rsp.size_dw);
792
793 return ret;
794}
795
796static int gfms_ep_port_finish(struct switchtec_dev *dev)
797{
798 struct {
799 uint8_t subcmd;
800 uint8_t reserved[3];
801 uint32_t type;
802 } cmd = {
803 .subcmd = MRPC_GFMS_DB_DUMP_EP_PORT,
804 .type = 3,
805 };
806
807 return switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &cmd, sizeof(cmd),
808 NULL, 0);
809}
810
811static size_t gfms_ep_port_attached_ep_parse(
812 struct switchtec_dev *dev,
813 uint8_t *data,
814 struct switchtec_gfms_db_ep_port_ep *ep_port_ep)
815{
816 size_t len;
817 size_t parsed_len;
818 uint8_t *p = data;
819
820 len = sizeof(ep_port_ep->ep_hdr);
821 memcpy(&ep_port_ep->ep_hdr, p, len);
822 p += len;
823 parsed_len = len;
824
825 len = ep_port_ep->ep_hdr.size_dw * 4 - sizeof(ep_port_ep->ep_hdr);
826 memcpy(ep_port_ep->functions, p, len);
827 parsed_len += len;
828
829 return parsed_len;
830}
831
832static size_t gfms_ep_port_attache_switch_parse(
833 struct switchtec_dev *dev,
834 uint8_t *data,
835 struct switchtec_gfms_db_ep_port_switch *ep_port_switch)
836{
837 size_t len;
838 size_t parsed_len;
839 uint8_t *p = data;
840
841 len = sizeof(ep_port_switch->sw_hdr);
842 memcpy(&ep_port_switch->sw_hdr, p, len);
843 p += len;
844 parsed_len = len;
845
846 len = sizeof(ep_port_switch->ds_switch.internal_functions[0]);
847 len = ep_port_switch->sw_hdr.function_number * len;
848 memcpy(ep_port_switch->ds_switch.internal_functions, p, len);
849 p += len;
850 parsed_len += len;
851
852 return parsed_len;
853}
854
855static size_t gfms_ep_port_sub_section_parse(
856 struct switchtec_dev *dev,
857 uint8_t *data,
858 struct switchtec_gfms_db_ep_port *ep_port)
859{
860 int i;
861 size_t parsed_len;
862 size_t remaining_len;
863 size_t len;
864 void *p = data;
865
866 len = sizeof(ep_port->port_hdr);
867 memcpy(&ep_port->port_hdr, p, len);
868 remaining_len = ep_port->port_hdr.size_dw * 4;
869 p += len;
870 parsed_len = len;
871 remaining_len -= len;
872
873 if (ep_port->port_hdr.type == SWITCHTEC_GFMS_DB_TYPE_SWITCH) {
874 len = gfms_ep_port_attache_switch_parse(dev, p,
875 &ep_port->ep_switch);
876 p += len;
877 parsed_len += len;
878 remaining_len -= len;
879
880 i = 0;
881 while (remaining_len) {
882 len = gfms_ep_port_attached_ep_parse(
883 dev, p,
884 &ep_port->ep_switch.switch_eps[i++]);
885 p += len;
886 parsed_len += len;
887 remaining_len -= len;
888 }
889 } else if (ep_port->port_hdr.type == SWITCHTEC_GFMS_DB_TYPE_EP) {
890 len = gfms_ep_port_attached_ep_parse(dev, p, &ep_port->ep_ep);
891 p += len;
892 parsed_len += len;
893 } else if (ep_port->port_hdr.type == SWITCHTEC_GFMS_DB_TYPE_NON) {
894 }
895
896 return parsed_len;
897}
898
899static size_t gfms_ep_port_section_parse(
900 struct switchtec_dev *dev,
901 uint8_t *data,
902 struct switchtec_gfms_db_ep_port_section *ep_port_section)
903{
904 size_t len;
905 size_t parsed_len;
906 void *p = data;
907
908 len = sizeof(ep_port_section->hdr);
909 memcpy(&ep_port_section->hdr, p, len);
910 p += len;
911 parsed_len = len;
912
913 len = ep_port_section->hdr.resp_size_dw * 4 - len;
914 len = gfms_ep_port_sub_section_parse(dev, p, &ep_port_section->ep_port);
915 parsed_len += len;
916
917 return parsed_len;
918}
919
920int switchtec_fab_gfms_db_dump_ep_port(
921 struct switchtec_dev *dev,
922 uint8_t phy_pid,
923 struct switchtec_gfms_db_ep_port_section *ep_port_section)
924{
925 uint32_t total_len_dw;
926 size_t parsed_len;
927 uint8_t *data;
928 int ret = 0;
929
930 ret = gfms_ep_port_start(dev, phy_pid, &total_len_dw);
931 if (ret)
932 goto exit;
933
934 data = malloc(total_len_dw * 4);
935 if (!data) {
936 ret = -ENOMEM;
937 goto exit;
938 }
939 ret = gfms_ep_port_get(dev, phy_pid, total_len_dw, data);
940 if (ret)
941 goto free_and_exit;
942
943 ret = gfms_ep_port_finish(dev);
944 if (ret)
945 goto free_and_exit;
946
947 parsed_len = gfms_ep_port_section_parse(dev, data, ep_port_section);
948 if (parsed_len != total_len_dw * 4)
949 ret = -1;
950
951free_and_exit:
952 free(data);
953exit:
954 return ret;
955}
956
957static size_t gfms_ep_port_all_section_parse(
958 struct switchtec_dev *dev,
959 uint8_t *data,
960 struct switchtec_gfms_db_ep_port_all_section *ep_port_all)
961{
962 uint8_t *p = data;
963 size_t parsed_len;
964 size_t remaining_len;
965 struct switchtec_gfms_db_ep_port *ep_port;
966 size_t len;
967 int i;
968
969 len = sizeof(ep_port_all->hdr);
970 memcpy(&ep_port_all->hdr, data, len);
971 parsed_len = len;
972 p += len;
973
974 remaining_len = ep_port_all->hdr.resp_size_dw * 4 -
975 sizeof(ep_port_all->hdr);
976
977 i = 0;
978 while (remaining_len) {
979 ep_port = &ep_port_all->ep_ports[i];
980
981 len = gfms_ep_port_sub_section_parse(dev, p, ep_port);
982 p += len;
983 parsed_len += len;
984 remaining_len -= len;
985
986 i++;
987 ep_port_all->ep_port_count = i;
988 }
989
990 return parsed_len;
991}
992
993static size_t gfms_pax_all_parse(struct switchtec_dev *dev,
994 uint8_t *data,
995 uint32_t data_len,
996 struct switchtec_gfms_db_pax_all *pax_all)
997{
998 uint8_t *p = data;
999 size_t len;
1000 size_t parsed_len;
1001
1002 parsed_len = 0;
1003
1004 len = gfms_pax_general_section_parse(dev, data, &pax_all->pax_general);
1005 p += len;
1006 parsed_len += len;
1007
1008 len = gfms_hvd_all_section_parse(dev, p, &pax_all->hvd_all);
1009 p += len;
1010 parsed_len += len;
1011
1012 len = gfms_ep_port_all_section_parse(dev, p, &pax_all->ep_port_all);
1013 parsed_len += len;
1014
1015 return parsed_len;
1016}
1017
1018int switchtec_fab_gfms_db_dump_pax_all(
1019 struct switchtec_dev *dev,
1020 struct switchtec_gfms_db_pax_all *pax_all)
1021{
1022 uint32_t total_len_dw;
1023 size_t parsed_len;
1024 uint8_t *data;
1025 int ret;
1026
1027 ret = gfms_dump_start(dev, MRPC_GFMS_DB_DUMP_PAX_ALL, 0, &total_len_dw);
1028 if (ret)
1029 return ret;
1030
1031 data = malloc(total_len_dw * 4);
1032 if (!data)
1033 return -ENOMEM;
1034 ret = gfms_dump_get(dev, MRPC_GFMS_DB_DUMP_PAX_ALL, total_len_dw, data);
1035 if (ret) {
1036 free(data);
1037 return ret;
1038 }
1039
1040 ret = gfms_dump_finish(dev, MRPC_GFMS_DB_DUMP_PAX_ALL);
1041 if (ret) {
1042 free(data);
1043 return ret;
1044 }
1045
1046 parsed_len = gfms_pax_all_parse(dev, data, total_len_dw * 4, pax_all);
1047
1048 if (parsed_len != total_len_dw * 4)
1049 ret = -1;
1050
1051 free(data);
1052 return ret;
1053}
1054
1055int switchtec_get_gfms_events(struct switchtec_dev *dev,
1056 struct switchtec_gfms_event *elist,
1057 size_t elist_len, int *overflow,
1058 size_t *remain_number)
1059{
1060 int ret;
1061 int event_cnt = 0;
1062 uint16_t req_num = elist_len;
1063 uint16_t remain_num;
1064 struct switchtec_gfms_event *e = elist;
1065 size_t d_len;
1066 uint8_t *p;
1067 int i;
1068
1069 struct {
1070 uint8_t subcmd;
1071 uint8_t reserved;
1072 uint16_t req_num;
1073 } req = {
1074 .subcmd = 1,
1075 .req_num = req_num,
1076 };
1077
1078 struct {
1079 uint16_t num;
1080 uint16_t remain_num_flag;
1081 uint8_t data[MRPC_MAX_DATA_LEN - 4];
1082 } resp;
1083
1084 struct entry {
1085 uint16_t entry_len;
1086 uint8_t event_code;
1087 uint8_t src_sw_id;
1088 uint8_t data[];
1089 } *hdr;
1090
1091 do {
1092 ret = switchtec_cmd(dev, MRPC_GFMS_EVENT, &req,
1093 sizeof(req), &resp, sizeof(resp));
1094 if (ret)
1095 return -1;
1096
1097 if ((resp.remain_num_flag & 0x8000) && overflow)
1098 *overflow = 1;
1099
1100 p = resp.data;
1101 for (i = 0; i < resp.num; i++) {
1102 hdr = (struct entry *)p;
1103 e->event_code = hdr->event_code;
1104 e->src_sw_id = hdr->src_sw_id;
1105 d_len = le32toh(hdr->entry_len) -
1106 offsetof(struct entry, data);
1107 memcpy(e->data.byte, hdr->data, d_len);
1108 p += hdr->entry_len;
1109 e++;
1110 };
1111 event_cnt += resp.num;
1112 remain_num = resp.remain_num_flag & 0x7fff;
1113 req_num -= resp.num;
1114 } while (req_num && remain_num);
1115
1116 if (remain_number)
1117 *remain_number = remain_num;
1118
1119 return event_cnt;
1120}
1121
1122int switchtec_clear_gfms_events(struct switchtec_dev *dev)
1123{
1124 int ret;
1125 uint32_t subcmd = 0;
1126
1127 ret = switchtec_cmd(dev, MRPC_GFMS_EVENT, &subcmd, sizeof(subcmd),
1128 NULL, 0);
1129 if (ret)
1130 return -1;
1131
1132 return 0;
1133}
1134
1135int switchtec_device_manage(struct switchtec_dev *dev,
1136 struct switchtec_device_manage_req *req,
1137 struct switchtec_device_manage_rsp *rsp)
1138{
1139 int ret;
1140
1141 req->hdr.expected_rsp_len = htole16(req->hdr.expected_rsp_len);
1142 req->hdr.pdfid = htole16(req->hdr.pdfid);
1143
1144 ret = switchtec_cmd(dev, MRPC_DEVICE_MANAGE_CMD,
1145 req, sizeof(struct switchtec_device_manage_req),
1146 rsp, sizeof(struct switchtec_device_manage_rsp));
1147
1148 rsp->hdr.rsp_len = le16toh(rsp->hdr.rsp_len);
1149
1150 return ret;
1151}
1152
1153int switchtec_ep_tunnel_config(struct switchtec_dev *dev, uint16_t subcmd,
1154 uint16_t pdfid, uint16_t expected_rsp_len,
1155 uint8_t *meta_data, uint16_t meta_data_len,
1156 uint8_t *rsp_data)
1157{
1158 int ret;
1159 size_t payload_len;
1160
1161 struct cfg_req {
1162 uint16_t subcmd;
1163 uint16_t pdfid;
1164 uint16_t expected_rsp_len;
1165 uint16_t meta_data_len;
1166 uint8_t meta_data[MRPC_MAX_DATA_LEN - 8];
1167 } req = {
1168 .subcmd = htole16(subcmd),
1169 .pdfid = htole16(pdfid),
1170 .expected_rsp_len = htole16(expected_rsp_len),
1171 };
1172
1173 struct cfg_rsp {
1174 uint32_t len;
1175 uint8_t data[MRPC_MAX_DATA_LEN - 4];
1176 } rsp;
1177
1178 if (meta_data_len > sizeof(req.meta_data))
1179 return -1;
1180
1181 req.meta_data_len = htole16(meta_data_len);
1182
1183 if (meta_data_len)
1184 memcpy(req.meta_data, meta_data, meta_data_len);
1185
1186 payload_len = offsetof(struct cfg_req, meta_data) + meta_data_len;
1187
1188 ret = switchtec_cmd(dev, MRPC_EP_TUNNEL_CFG, &req,
1189 payload_len, &rsp, sizeof(rsp));
1190
1191 if (ret)
1192 return -errno;
1193
1194 rsp.len = le32toh(rsp.len);
1195
1196 if (rsp_data && rsp.len)
1197 memcpy(rsp_data, rsp.data, rsp.len);
1198
1199 return 0;
1200}
1201
1202int switchtec_ep_tunnel_enable(struct switchtec_dev *dev, uint16_t pdfid)
1203{
1204 return switchtec_ep_tunnel_config(dev, MRPC_EP_TUNNEL_ENABLE,
1205 pdfid, 0, NULL, 0, NULL);
1206}
1207
1208int switchtec_ep_tunnel_disable(struct switchtec_dev *dev, uint16_t pdfid)
1209{
1210 return switchtec_ep_tunnel_config(dev, MRPC_EP_TUNNEL_DISABLE,
1211 pdfid, 0, NULL, 0, NULL);
1212}
1213
1214int switchtec_ep_tunnel_status(struct switchtec_dev *dev, uint16_t pdfid,
1215 uint32_t *status)
1216{
1217 int ret;
1218
1219 ret = switchtec_ep_tunnel_config(dev, MRPC_EP_TUNNEL_STATUS,
1220 pdfid, sizeof(*status), NULL,
1221 0, (uint8_t *)status);
1222 *status = le32toh(*status);
1223
1224 return ret;
1225}
1226
1227static int ep_csr_read(struct switchtec_dev *dev,
1228 uint16_t pdfid, void *dest,
1229 uint16_t src, size_t n)
1230{
1231 int ret;
1232
1233 if (n > SWITCHTEC_EP_CSR_MAX_READ_LEN)
1234 n = SWITCHTEC_EP_CSR_MAX_READ_LEN;
1235
1236 if (!n)
1237 return n;
1238
1239 struct ep_cfg_read {
1240 uint8_t subcmd;
1241 uint8_t reserved0;
1242 uint16_t pdfid;
1243 uint16_t addr;
1244 uint8_t bytes;
1245 uint8_t reserved1;
1246 } cmd = {
1247 .subcmd = 0,
1248 .pdfid = htole16(pdfid),
1249 .addr = htole16(src),
1250 .bytes= n,
1251 };
1252
1253 struct {
1254 uint32_t data;
1255 } rsp;
1256
1257 ret = switchtec_cmd(dev, MRPC_EP_RESOURCE_ACCESS, &cmd,
1258 sizeof(cmd), &rsp, 4);
1259 if (ret)
1260 return -1;
1261
1262 memcpy(dest, &rsp.data, n);
1263 return 0;
1264}
1265
1266int switchtec_ep_csr_read8(struct switchtec_dev *dev, uint16_t pdfid,
1267 uint16_t addr, uint8_t *val)
1268{
1269 return ep_csr_read(dev, pdfid, val, addr, 1);
1270}
1271
1272int switchtec_ep_csr_read16(struct switchtec_dev *dev, uint16_t pdfid,
1273 uint16_t addr, uint16_t *val)
1274{
1275 int ret;
1276
1277 ret = ep_csr_read(dev, pdfid, val, addr, 2);
1278 *val = le16toh(*val);
1279
1280 return ret;
1281}
1282
1283int switchtec_ep_csr_read32(struct switchtec_dev *dev, uint16_t pdfid,
1284 uint16_t addr, uint32_t *val)
1285{
1286 int ret;
1287
1288 ret = ep_csr_read(dev, pdfid, val, addr, 4);
1289 *val = le32toh(*val);
1290
1291 return ret;
1292}
1293
1294static int ep_csr_write(struct switchtec_dev *dev, uint16_t pdfid,
1295 uint16_t addr, const void *val, size_t n)
1296{
1297 if (n > SWITCHTEC_EP_CSR_MAX_WRITE_LEN)
1298 n = SWITCHTEC_EP_CSR_MAX_WRITE_LEN;
1299
1300 if (!n)
1301 return n;
1302
1303 struct ep_cfg_write {
1304 uint8_t subcmd;
1305 uint8_t reserved0;
1306 uint16_t pdfid;
1307 uint16_t addr;
1308 uint8_t bytes;
1309 uint8_t reserved1;
1310 uint32_t data;
1311 } cmd = {
1312 .subcmd = 1,
1313 .pdfid = htole16(pdfid),
1314 .addr = htole16(addr),
1315 .bytes= n,
1316 };
1317
1318 memcpy(&cmd.data, val, n);
1319
1320 return switchtec_cmd(dev, MRPC_EP_RESOURCE_ACCESS, &cmd,
1321 sizeof(cmd), NULL, 0);
1322}
1323
1324int switchtec_ep_csr_write8(struct switchtec_dev *dev, uint16_t pdfid,
1325 uint8_t val, uint16_t addr)
1326{
1327 return ep_csr_write(dev, pdfid, addr, &val, 1);
1328}
1329
1330int switchtec_ep_csr_write16(struct switchtec_dev *dev, uint16_t pdfid,
1331 uint16_t val, uint16_t addr)
1332{
1333 val = htole16(val);
1334 return ep_csr_write(dev, pdfid, addr, &val, 2);
1335}
1336
1337int switchtec_ep_csr_write32(struct switchtec_dev *dev, uint16_t pdfid,
1338 uint32_t val, uint16_t addr)
1339{
1340 val = htole32(val);
1341 return ep_csr_write(dev, pdfid, addr, &val, 4);
1342}
1343
1344static size_t ep_bar_read(struct switchtec_dev *dev, uint16_t pdfid,
1345 uint8_t bar, void *dest,
1346 uint64_t src, size_t n)
1347{
1348 if (n > SWITCHTEC_EP_BAR_MAX_READ_LEN)
1349 n = SWITCHTEC_EP_BAR_MAX_READ_LEN;
1350
1351 if (!n)
1352 return n;
1353
1354 src = htole64(src);
1355
1356 struct ep_bar_read {
1357 uint8_t subcmd;
1358 uint8_t reserved0;
1359 uint16_t pdfid;
1360 uint8_t bar;
1361 uint8_t reserved1;
1362 uint16_t bytes;
1363 uint32_t addr_low;
1364 uint32_t addr_high;
1365 } cmd = {
1366 .subcmd = 2,
1367 .pdfid = htole16(pdfid),
1368 .bar = bar,
1369 .addr_low = (uint32_t)src,
1370 .addr_high = (uint32_t)(src >> 32),
1371 .bytes= htole16((uint16_t)n),
1372 };
1373
1374 return switchtec_cmd(dev, MRPC_EP_RESOURCE_ACCESS, &cmd,
1375 sizeof(cmd), dest, n);
1376}
1377
1378int switchtec_ep_bar_read8(struct switchtec_dev *dev, uint16_t pdfid,
1379 uint8_t bar, uint64_t addr, uint8_t *val)
1380{
1381 return ep_bar_read(dev, pdfid, bar, val, addr, 1);
1382}
1383
1384int switchtec_ep_bar_read16(struct switchtec_dev *dev, uint16_t pdfid,
1385 uint8_t bar, uint64_t addr, uint16_t *val)
1386{
1387 int ret;
1388
1389 ret = ep_bar_read(dev, pdfid, bar, val, addr, 2);
1390 *val = le16toh(*val);
1391
1392 return ret;
1393}
1394
1395int switchtec_ep_bar_read32(struct switchtec_dev *dev, uint16_t pdfid,
1396 uint8_t bar, uint64_t addr, uint32_t *val)
1397{
1398 int ret;
1399
1400 ret = ep_bar_read(dev, pdfid, bar, val, addr, 4);
1401 *val = le32toh(*val);
1402
1403 return ret;
1404}
1405
1406int switchtec_ep_bar_read64(struct switchtec_dev *dev, uint16_t pdfid,
1407 uint8_t bar, uint64_t addr, uint64_t *val)
1408{
1409 int ret;
1410
1411 ret = ep_bar_read(dev, pdfid, bar, val, addr, 8);
1412 *val = le64toh(*val);
1413
1414 return ret;
1415}
1416
1417static int ep_bar_write(struct switchtec_dev *dev, uint16_t pdfid,
1418 uint8_t bar, uint64_t addr,
1419 const void *val, size_t n)
1420{
1421 if (n > SWITCHTEC_EP_BAR_MAX_WRITE_LEN)
1422 n = SWITCHTEC_EP_BAR_MAX_WRITE_LEN;
1423
1424 if (!n)
1425 return n;
1426
1427 addr = htole64(addr);
1428
1429 struct ep_bar_write {
1430 uint8_t subcmd;
1431 uint8_t reserved0;
1432 uint16_t pdfid;
1433 uint8_t bar;
1434 uint8_t reserved1;
1435 uint16_t bytes;
1436 uint32_t addr_low;
1437 uint32_t addr_high;
1438 uint32_t data[128];
1439 } cmd = {
1440 .subcmd = 3,
1441 .pdfid = htole16(pdfid),
1442 .bar = bar,
1443 .bytes= htole16((uint16_t)n),
1444 .addr_low = (uint32_t)addr,
1445 .addr_high = (uint32_t)(addr >> 32),
1446 };
1447
1448 memcpy(&cmd.data, val, n);
1449
1450 return switchtec_cmd(dev, MRPC_EP_RESOURCE_ACCESS,
1451 &cmd, sizeof(cmd), NULL, 0);
1452}
1453
1454int switchtec_ep_bar_write8(struct switchtec_dev *dev, uint16_t pdfid,
1455 uint8_t bar, uint8_t val, uint64_t addr)
1456{
1457 return ep_bar_write(dev, pdfid, bar, addr, &val, 1);
1458}
1459
1460int switchtec_ep_bar_write16(struct switchtec_dev *dev, uint16_t pdfid,
1461 uint8_t bar, uint16_t val, uint64_t addr)
1462{
1463 val = htole16(val);
1464 return ep_bar_write(dev, pdfid, bar, addr, &val, 2);
1465}
1466
1467int switchtec_ep_bar_write32(struct switchtec_dev *dev, uint16_t pdfid,
1468 uint8_t bar, uint32_t val, uint64_t addr)
1469{
1470 val = htole32(val);
1471 return ep_bar_write(dev, pdfid, bar, addr, &val, 4);
1472}
1473
1474int switchtec_ep_bar_write64(struct switchtec_dev *dev, uint16_t pdfid,
1475 uint8_t bar, uint64_t val, uint64_t addr)
1476{
1477 val = htole64(val);
1478 return ep_bar_write(dev, pdfid, bar, addr, &val, 8);
1479}
1480
1481static int admin_passthru_start(struct switchtec_dev *dev, uint16_t pdfid,
1482 size_t data_len, void *data,
1483 size_t *rsp_len)
1484{
1485 int ret;
1486 uint16_t copy_len;
1487 uint16_t offset = 0;
1488
1489 struct {
1490 uint8_t subcmd;
1491 uint8_t rsvd[3];
1492 uint16_t pdfid;
1493 uint16_t expected_rsp_len;
1494 uint8_t more_data;
1495 uint8_t rsvd1[3];
1496 uint16_t data_offset;
1497 uint16_t data_len;
1498 uint8_t data[MRPC_MAX_DATA_LEN - 16];
1499 } cmd = {
1500 .subcmd = MRPC_NVME_ADMIN_PASSTHRU_START,
1501 .pdfid = htole16(pdfid)
1502 };
1503
1504 struct {
1505 uint16_t rsp_len;
1506 uint16_t rsvd1;
1507 } reply = {};
1508
1509 if (data_len && data != NULL) {
1510 cmd.more_data = data_len > sizeof(cmd.data);
1511 while (cmd.more_data) {
1512 copy_len = sizeof(cmd.data);
1513 memcpy(cmd.data, data + offset, copy_len);
1514
1515 cmd.data_offset = htole16(offset);
1516 cmd.data_len = htole16(copy_len);
1517
1518 ret = switchtec_cmd(dev, MRPC_NVME_ADMIN_PASSTHRU,
1519 &cmd, sizeof(cmd), NULL, 0);
1520 if (ret)
1521 return ret;
1522
1523 offset += copy_len;
1524 data_len -= copy_len;
1525 cmd.more_data = data_len > sizeof(cmd.data);
1526 }
1527
1528 if (data_len) {
1529 memcpy(cmd.data, data + offset, data_len);
1530
1531 cmd.data_offset = htole16(offset);
1532 cmd.data_len = htole16(data_len);
1533 } else {
1534 cmd.data_len = 0;
1535 cmd.data_offset = 0;
1536 }
1537 }
1538
1539 cmd.expected_rsp_len = htole16(*rsp_len);
1540
1541 ret = switchtec_cmd(dev, MRPC_NVME_ADMIN_PASSTHRU,
1542 &cmd, sizeof(cmd), &reply, sizeof(reply));
1543 if (ret) {
1544 *rsp_len = 0;
1545 return ret;
1546 }
1547
1548 *rsp_len = le16toh(reply.rsp_len);
1549 return 0;
1550}
1551
1552static int admin_passthru_data(struct switchtec_dev *dev, uint16_t pdfid,
1553 size_t rsp_len, void *rsp)
1554{
1555 size_t offset = 0;
1556 int ret;
1557 struct {
1558 uint8_t subcmd;
1559 uint8_t rsvd[3];
1560 uint16_t pdfid;
1561 uint16_t offset;
1562 } cmd = {
1563 .subcmd = MRPC_NVME_ADMIN_PASSTHRU_DATA,
1564 .pdfid = htole16(pdfid),
1565 };
1566
1567 struct {
1568 uint16_t offset;
1569 uint16_t len;
1570 uint8_t data[MRPC_MAX_DATA_LEN - 4];
1571 } reply = {};
1572
1573 while (offset < rsp_len) {
1574 cmd.offset = htole16(offset);
1575
1576 ret = switchtec_cmd(dev, MRPC_NVME_ADMIN_PASSTHRU,
1577 &cmd, sizeof(cmd), &reply,
1578 sizeof(reply));
1579 if (ret)
1580 return ret;
1581
1582 memcpy((uint8_t*)rsp + offset, reply.data,
1583 htole16(reply.len));
1584 offset += htole16(reply.len);
1585 }
1586
1587 return 0;
1588}
1589
1590static int admin_passthru_end(struct switchtec_dev *dev, uint16_t pdfid)
1591{
1592 struct {
1593 uint8_t subcmd;
1594 uint8_t rsvd[3];
1595 uint16_t pdfid;
1596 uint16_t rsvd1;
1597 } cmd = {};
1598
1599 cmd.subcmd = MRPC_NVME_ADMIN_PASSTHRU_END;
1600 cmd.pdfid = htole16(pdfid);
1601
1602 return switchtec_cmd(dev, MRPC_NVME_ADMIN_PASSTHRU,
1603 &cmd, sizeof(cmd), NULL, 0);
1604}
1605
1616int switchtec_nvme_admin_passthru(struct switchtec_dev *dev, uint16_t pdfid,
1617 size_t data_len, void *data,
1618 size_t *rsp_len, void *rsp)
1619{
1620 int ret;
1621
1622 ret = admin_passthru_start(dev, pdfid, data_len, data, rsp_len);
1623 if (ret)
1624 return ret;
1625
1626 if (*rsp_len && rsp != NULL) {
1627 ret = admin_passthru_data(dev, pdfid, *rsp_len, rsp);
1628 if (ret) {
1629 *rsp_len = 0;
1630 return ret;
1631 }
1632 }
1633
1634 ret = admin_passthru_end(dev, pdfid);
1635
1636 return ret;
1637}
int switchtec_cmd(struct switchtec_dev *dev, uint32_t cmd, const void *payload, size_t payload_len, void *resp, size_t resp_len)
Execute an MRPC command.
Definition platform.c:178
The port config.
Definition fabric.h:164
uint8_t clock_sris
Port clock sris, enable/disable.
Definition fabric.h:167
uint8_t hvd_inst
HVM domain instance index for USP.
Definition fabric.h:168
uint8_t port_type
Port type.
Definition fabric.h:165
uint8_t clock_source
CSU channel index for port clock source(0-2).
Definition fabric.h:166
Represents the topology info.
Definition fabric.h:76
struct switchtec_fab_port_info port_info_list[SWITCHTEC_MAX_PORTS]
Port info list.
Definition fabric.h:91
uint8_t sw_idx
Switch index.
Definition fabric.h:77
int num_stack_bif
Number of port bifurcation fields.
Definition fabric.h:79
uint8_t route_port[16]
Route port.
Definition fabric.h:81
uint32_t stack_bif[8]
Port bifurcation.
Definition fabric.h:80
uint64_t port_bitmap
Enabled physical port bitmap.
Definition fabric.h:82
Represents the GFMS event.
Definition fabric.h:603
Main Switchtec header.
static int switchtec_is_gen4(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 4 device.
Definition switchtec.h:508
static int switchtec_is_gen5(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 5 device.
Definition switchtec.h:516
static int switchtec_is_pax_all(struct switchtec_dev *dev)
Return whether a Switchtec device is PAX(A).
Definition switchtec.h:641