Switchtec Userspace PROJECT_NUMBER = 4.0
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 ret = gfms_dump_get(dev, MRPC_GFMS_DB_DUMP_HVD_DETAIL, total_len_dw,
630 (uint8_t *)data);
631 if (ret) {
632 free(data);
633 return ret;
634 }
635
636 ret = gfms_dump_finish(dev, MRPC_GFMS_DB_DUMP_HVD_DETAIL);
637 if (ret) {
638 free(data);
639 return ret;
640 }
641
642 memcpy(&hvd_detail->hdr, data, sizeof(hvd_detail->hdr));
643
644 body = (struct switchtec_gfms_db_hvd_detail_body *)(data + sizeof(hvd_detail->hdr));
645
646 p = (void *)body;
647 hvd_detail->body.hvd_inst_id = body->hvd_inst_id;
648 hvd_detail->body.phy_pid = body->phy_pid;
649 hvd_detail->body.hfid = body->hfid;
650 hvd_detail->body.vep_count = body->vep_count;
651 hvd_detail->body.usp_status = body->usp_status;
652
653 p += offsetof(struct switchtec_gfms_db_hvd_detail_body, vep_region);
654 len = sizeof(body->vep_region[0]) * body->vep_count;
655 memcpy(hvd_detail->body.vep_region, body->vep_region, len);
656 p += len;
657
658 len = sizeof(hvd_detail->body.log_dsp_count);
659 memcpy(&hvd_detail->body.log_dsp_count, p, len);
660 p += len;
661
662 len = sizeof(hvd_detail->body.usp_bdf);
663 memcpy(&hvd_detail->body.usp_bdf, p, len);
664 p += len;
665
666 len = sizeof(hvd_detail->body.log_port_region[0]) *
667 le16toh(hvd_detail->body.log_dsp_count) *
668 SWITCHTEC_FABRIC_MULTI_FUNC_NUM;
669 memcpy(hvd_detail->body.log_port_region, p, len);
670 p += len;
671
672 len = sizeof(hvd_detail->body.log_port_p2p_enable_bitmap_low);
673 memcpy(&hvd_detail->body.log_port_p2p_enable_bitmap_low, p, len);
674 p += len;
675
676 len = sizeof(hvd_detail->body.log_port_p2p_enable_bitmap_high);
677 memcpy(&hvd_detail->body.log_port_p2p_enable_bitmap_high, p, len);
678 p += len;
679
680 bitmap = le32toh(hvd_detail->body.log_port_p2p_enable_bitmap_high);
681 bitmap <<= 32;
682 bitmap |= le32toh(hvd_detail->body.log_port_p2p_enable_bitmap_low);
683
684 hvd_detail->body.log_port_count = 0;
685 for (i = 0; i < (sizeof(bitmap) * 8); i++)
686 if (bitmap >> i && 0x1)
687 hvd_detail->body.log_port_count++;
688
689 len = sizeof(hvd_detail->body.log_port_p2p_bitmap[0]) *
690 hvd_detail->body.log_port_count;
691 memcpy(hvd_detail->body.log_port_p2p_bitmap, p, len);
692
693 free(data);
694 return 0;
695}
696
697int switchtec_fab_gfms_db_dump_fab_port(
698 struct switchtec_dev *dev,
699 uint8_t phy_pid,
700 struct switchtec_gfms_db_fab_port *fab_port)
701{
702 struct {
703 uint8_t subcmd;
704 uint8_t phy_pid;
705 } cmd = {
706 .subcmd = MRPC_GFMS_DB_DUMP_FAB_PORT,
707 .phy_pid = phy_pid,
708 };
709
710 return switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &cmd, sizeof(cmd),
711 fab_port, sizeof(*fab_port));
712}
713
714static int gfms_ep_port_start(struct switchtec_dev *dev,
715 uint8_t fab_ep_pid,
716 uint32_t *total_len_dw)
717{
718 int ret;
719
720 struct {
721 uint8_t subcmd;
722 uint8_t fab_ep_pid;
723 uint16_t reserved;
724 uint32_t type;
725 } cmd = {
726 .subcmd = MRPC_GFMS_DB_DUMP_EP_PORT,
727 .fab_ep_pid = fab_ep_pid,
728 .type = 1,
729 };
730
731 struct {
732 uint32_t dw_len;
733 uint32_t num_of_switch;
734 } rsp;
735
736 ret = switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &cmd, sizeof(cmd),
737 &rsp, sizeof(rsp));
738 *total_len_dw = rsp.dw_len;
739
740 return ret;
741}
742
743static int gfms_ep_port_get(struct switchtec_dev *dev,
744 uint8_t fab_ep_pid,
745 uint32_t total_len_dw,
746 uint8_t *data)
747{
748 int ret;
749
750 struct {
751 uint8_t subcmd;
752 uint8_t fab_ep_pid;
753 uint16_t reserved;
754 uint32_t type;
755 uint32_t offset_dw;
756 } cmd = {
757 .subcmd = MRPC_GFMS_DB_DUMP_EP_PORT,
758 .fab_ep_pid = fab_ep_pid,
759 .type = 2,
760 .offset_dw = 0,
761 };
762
763 struct {
764 uint32_t offset_dw;
765 uint32_t size_dw;
766 uint32_t reserved;
767 uint8_t data[MRPC_MAX_DATA_LEN - 12];
768 } rsp = {
769 .offset_dw = 0,
770 .size_dw = 0,
771 };
772
773 do {
774 ret = switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &cmd, sizeof(cmd),
775 &rsp, MRPC_MAX_DATA_LEN);
776
777 if (ret)
778 break;
779
780 if (rsp.size_dw > 0xf0)
781 rsp.size_dw = 0xf0;
782
783 rsp.size_dw -= 3;
784
785 memcpy(data + (cmd.offset_dw * 4), rsp.data, rsp.size_dw * 4);
786
787 cmd.offset_dw += rsp.size_dw;
788
789 } while(total_len_dw > rsp.offset_dw + rsp.size_dw);
790
791 return ret;
792}
793
794static int gfms_ep_port_finish(struct switchtec_dev *dev)
795{
796 struct {
797 uint8_t subcmd;
798 uint8_t reserved[3];
799 uint32_t type;
800 } cmd = {
801 .subcmd = MRPC_GFMS_DB_DUMP_EP_PORT,
802 .type = 3,
803 };
804
805 return switchtec_cmd(dev, MRPC_GFMS_DB_DUMP, &cmd, sizeof(cmd),
806 NULL, 0);
807}
808
809static size_t gfms_ep_port_attached_ep_parse(
810 struct switchtec_dev *dev,
811 uint8_t *data,
812 struct switchtec_gfms_db_ep_port_ep *ep_port_ep)
813{
814 size_t len;
815 size_t parsed_len;
816 uint8_t *p = data;
817
818 len = sizeof(ep_port_ep->ep_hdr);
819 memcpy(&ep_port_ep->ep_hdr, p, len);
820 p += len;
821 parsed_len = len;
822
823 len = ep_port_ep->ep_hdr.size_dw * 4 - sizeof(ep_port_ep->ep_hdr);
824 memcpy(ep_port_ep->functions, p, len);
825 parsed_len += len;
826
827 return parsed_len;
828}
829
830static size_t gfms_ep_port_attache_switch_parse(
831 struct switchtec_dev *dev,
832 uint8_t *data,
833 struct switchtec_gfms_db_ep_port_switch *ep_port_switch)
834{
835 size_t len;
836 size_t parsed_len;
837 uint8_t *p = data;
838
839 len = sizeof(ep_port_switch->sw_hdr);
840 memcpy(&ep_port_switch->sw_hdr, p, len);
841 p += len;
842 parsed_len = len;
843
844 len = sizeof(ep_port_switch->ds_switch.internal_functions[0]);
845 len = ep_port_switch->sw_hdr.function_number * len;
846 memcpy(ep_port_switch->ds_switch.internal_functions, p, len);
847 p += len;
848 parsed_len += len;
849
850 return parsed_len;
851}
852
853static size_t gfms_ep_port_sub_section_parse(
854 struct switchtec_dev *dev,
855 uint8_t *data,
856 struct switchtec_gfms_db_ep_port *ep_port)
857{
858 int i;
859 size_t parsed_len;
860 size_t remaining_len;
861 size_t len;
862 void *p = data;
863
864 len = sizeof(ep_port->port_hdr);
865 memcpy(&ep_port->port_hdr, p, len);
866 remaining_len = ep_port->port_hdr.size_dw * 4;
867 p += len;
868 parsed_len = len;
869 remaining_len -= len;
870
871 if (ep_port->port_hdr.type == SWITCHTEC_GFMS_DB_TYPE_SWITCH) {
872 len = gfms_ep_port_attache_switch_parse(dev, p,
873 &ep_port->ep_switch);
874 p += len;
875 parsed_len += len;
876 remaining_len -= len;
877
878 i = 0;
879 while (remaining_len) {
880 len = gfms_ep_port_attached_ep_parse(
881 dev, p,
882 &ep_port->ep_switch.switch_eps[i++]);
883 p += len;
884 parsed_len += len;
885 remaining_len -= len;
886 }
887 } else if (ep_port->port_hdr.type == SWITCHTEC_GFMS_DB_TYPE_EP) {
888 len = gfms_ep_port_attached_ep_parse(dev, p, &ep_port->ep_ep);
889 p += len;
890 parsed_len += len;
891 } else if (ep_port->port_hdr.type == SWITCHTEC_GFMS_DB_TYPE_NON) {
892 }
893
894 return parsed_len;
895}
896
897static size_t gfms_ep_port_section_parse(
898 struct switchtec_dev *dev,
899 uint8_t *data,
900 struct switchtec_gfms_db_ep_port_section *ep_port_section)
901{
902 size_t len;
903 size_t parsed_len;
904 void *p = data;
905
906 len = sizeof(ep_port_section->hdr);
907 memcpy(&ep_port_section->hdr, p, len);
908 p += len;
909 parsed_len = len;
910
911 len = ep_port_section->hdr.resp_size_dw * 4 - len;
912 len = gfms_ep_port_sub_section_parse(dev, p, &ep_port_section->ep_port);
913 parsed_len += len;
914
915 return parsed_len;
916}
917
918int switchtec_fab_gfms_db_dump_ep_port(
919 struct switchtec_dev *dev,
920 uint8_t phy_pid,
921 struct switchtec_gfms_db_ep_port_section *ep_port_section)
922{
923 uint32_t total_len_dw;
924 size_t parsed_len;
925 uint8_t *data;
926 int ret = 0;
927
928 ret = gfms_ep_port_start(dev, phy_pid, &total_len_dw);
929 if (ret)
930 goto exit;
931
932 data = malloc(total_len_dw * 4);
933 ret = gfms_ep_port_get(dev, phy_pid, total_len_dw, data);
934 if (ret)
935 goto free_and_exit;
936
937 ret = gfms_ep_port_finish(dev);
938 if (ret)
939 goto free_and_exit;
940
941 parsed_len = gfms_ep_port_section_parse(dev, data, ep_port_section);
942 if (parsed_len != total_len_dw * 4)
943 ret = -1;
944
945free_and_exit:
946 free(data);
947exit:
948 return ret;
949}
950
951static size_t gfms_ep_port_all_section_parse(
952 struct switchtec_dev *dev,
953 uint8_t *data,
954 struct switchtec_gfms_db_ep_port_all_section *ep_port_all)
955{
956 uint8_t *p = data;
957 size_t parsed_len;
958 size_t remaining_len;
959 struct switchtec_gfms_db_ep_port *ep_port;
960 size_t len;
961 int i;
962
963 len = sizeof(ep_port_all->hdr);
964 memcpy(&ep_port_all->hdr, data, len);
965 parsed_len = len;
966 p += len;
967
968 remaining_len = ep_port_all->hdr.resp_size_dw * 4 -
969 sizeof(ep_port_all->hdr);
970
971 i = 0;
972 while (remaining_len) {
973 ep_port = &ep_port_all->ep_ports[i];
974
975 len = gfms_ep_port_sub_section_parse(dev, p, ep_port);
976 p += len;
977 parsed_len += len;
978 remaining_len -= len;
979
980 i++;
981 ep_port_all->ep_port_count = i;
982 }
983
984 return parsed_len;
985}
986
987static size_t gfms_pax_all_parse(struct switchtec_dev *dev,
988 uint8_t *data,
989 uint32_t data_len,
990 struct switchtec_gfms_db_pax_all *pax_all)
991{
992 uint8_t *p = data;
993 size_t len;
994 size_t parsed_len;
995
996 parsed_len = 0;
997
998 len = gfms_pax_general_section_parse(dev, data, &pax_all->pax_general);
999 p += len;
1000 parsed_len += len;
1001
1002 len = gfms_hvd_all_section_parse(dev, p, &pax_all->hvd_all);
1003 p += len;
1004 parsed_len += len;
1005
1006 len = gfms_ep_port_all_section_parse(dev, p, &pax_all->ep_port_all);
1007 parsed_len += len;
1008
1009 return parsed_len;
1010}
1011
1012int switchtec_fab_gfms_db_dump_pax_all(
1013 struct switchtec_dev *dev,
1014 struct switchtec_gfms_db_pax_all *pax_all)
1015{
1016 uint32_t total_len_dw;
1017 size_t parsed_len;
1018 uint8_t *data;
1019 int ret;
1020
1021 ret = gfms_dump_start(dev, MRPC_GFMS_DB_DUMP_PAX_ALL, 0, &total_len_dw);
1022 if (ret)
1023 return ret;
1024
1025 data = malloc(total_len_dw * 4);
1026 ret = gfms_dump_get(dev, MRPC_GFMS_DB_DUMP_PAX_ALL, total_len_dw, data);
1027 if (ret) {
1028 free(data);
1029 return ret;
1030 }
1031
1032 ret = gfms_dump_finish(dev, MRPC_GFMS_DB_DUMP_PAX_ALL);
1033 if (ret) {
1034 free(data);
1035 return ret;
1036 }
1037
1038 parsed_len = gfms_pax_all_parse(dev, data, total_len_dw * 4, pax_all);
1039
1040 if (parsed_len != total_len_dw * 4)
1041 ret = -1;
1042
1043 free(data);
1044 return ret;
1045}
1046
1047int switchtec_get_gfms_events(struct switchtec_dev *dev,
1048 struct switchtec_gfms_event *elist,
1049 size_t elist_len, int *overflow,
1050 size_t *remain_number)
1051{
1052 int ret;
1053 int event_cnt = 0;
1054 uint16_t req_num = elist_len;
1055 uint16_t remain_num;
1056 struct switchtec_gfms_event *e = elist;
1057 size_t d_len;
1058 uint8_t *p;
1059 int i;
1060
1061 struct {
1062 uint8_t subcmd;
1063 uint8_t reserved;
1064 uint16_t req_num;
1065 } req = {
1066 .subcmd = 1,
1067 .req_num = req_num,
1068 };
1069
1070 struct {
1071 uint16_t num;
1072 uint16_t remain_num_flag;
1073 uint8_t data[MRPC_MAX_DATA_LEN - 4];
1074 } resp;
1075
1076 struct entry {
1077 uint16_t entry_len;
1078 uint8_t event_code;
1079 uint8_t src_sw_id;
1080 uint8_t data[];
1081 } *hdr;
1082
1083 do {
1084 ret = switchtec_cmd(dev, MRPC_GFMS_EVENT, &req,
1085 sizeof(req), &resp, sizeof(resp));
1086 if (ret)
1087 return -1;
1088
1089 if ((resp.remain_num_flag & 0x8000) && overflow)
1090 *overflow = 1;
1091
1092 p = resp.data;
1093 for (i = 0; i < resp.num; i++) {
1094 hdr = (struct entry *)p;
1095 e->event_code = hdr->event_code;
1096 e->src_sw_id = hdr->src_sw_id;
1097 d_len = le32toh(hdr->entry_len) -
1098 offsetof(struct entry, data);
1099 memcpy(e->data.byte, hdr->data, d_len);
1100 p += hdr->entry_len;
1101 e++;
1102 };
1103 event_cnt += resp.num;
1104 remain_num = resp.remain_num_flag & 0x7fff;
1105 req_num -= resp.num;
1106 } while (req_num && remain_num);
1107
1108 if (remain_number)
1109 *remain_number = remain_num;
1110
1111 return event_cnt;
1112}
1113
1114int switchtec_clear_gfms_events(struct switchtec_dev *dev)
1115{
1116 int ret;
1117 uint32_t subcmd = 0;
1118
1119 ret = switchtec_cmd(dev, MRPC_GFMS_EVENT, &subcmd, sizeof(subcmd),
1120 NULL, 0);
1121 if (ret)
1122 return -1;
1123
1124 return 0;
1125}
1126
1127int switchtec_device_manage(struct switchtec_dev *dev,
1128 struct switchtec_device_manage_req *req,
1129 struct switchtec_device_manage_rsp *rsp)
1130{
1131 int ret;
1132
1133 req->hdr.expected_rsp_len = htole16(req->hdr.expected_rsp_len);
1134 req->hdr.pdfid = htole16(req->hdr.pdfid);
1135
1136 ret = switchtec_cmd(dev, MRPC_DEVICE_MANAGE_CMD,
1137 req, sizeof(struct switchtec_device_manage_req),
1138 rsp, sizeof(struct switchtec_device_manage_rsp));
1139
1140 rsp->hdr.rsp_len = le16toh(rsp->hdr.rsp_len);
1141
1142 return ret;
1143}
1144
1145int switchtec_ep_tunnel_config(struct switchtec_dev *dev, uint16_t subcmd,
1146 uint16_t pdfid, uint16_t expected_rsp_len,
1147 uint8_t *meta_data, uint16_t meta_data_len,
1148 uint8_t *rsp_data)
1149{
1150 int ret;
1151 size_t payload_len;
1152
1153 struct cfg_req {
1154 uint16_t subcmd;
1155 uint16_t pdfid;
1156 uint16_t expected_rsp_len;
1157 uint16_t meta_data_len;
1158 uint8_t meta_data[MRPC_MAX_DATA_LEN - 8];
1159 } req = {
1160 .subcmd = htole16(subcmd),
1161 .pdfid = htole16(pdfid),
1162 .expected_rsp_len = htole16(expected_rsp_len),
1163 };
1164
1165 struct cfg_rsp {
1166 uint32_t len;
1167 uint8_t data[MRPC_MAX_DATA_LEN - 4];
1168 } rsp;
1169
1170 if (meta_data_len > sizeof(req.meta_data))
1171 return -1;
1172
1173 req.meta_data_len = htole16(meta_data_len);
1174
1175 if (meta_data_len)
1176 memcpy(req.meta_data, meta_data, meta_data_len);
1177
1178 payload_len = offsetof(struct cfg_req, meta_data) + meta_data_len;
1179
1180 ret = switchtec_cmd(dev, MRPC_EP_TUNNEL_CFG, &req,
1181 payload_len, &rsp, sizeof(rsp));
1182
1183 if (ret)
1184 return -errno;
1185
1186 rsp.len = le32toh(rsp.len);
1187
1188 if (rsp_data && rsp.len)
1189 memcpy(rsp_data, rsp.data, rsp.len);
1190
1191 return 0;
1192}
1193
1194int switchtec_ep_tunnel_enable(struct switchtec_dev *dev, uint16_t pdfid)
1195{
1196 return switchtec_ep_tunnel_config(dev, MRPC_EP_TUNNEL_ENABLE,
1197 pdfid, 0, NULL, 0, NULL);
1198}
1199
1200int switchtec_ep_tunnel_disable(struct switchtec_dev *dev, uint16_t pdfid)
1201{
1202 return switchtec_ep_tunnel_config(dev, MRPC_EP_TUNNEL_DISABLE,
1203 pdfid, 0, NULL, 0, NULL);
1204}
1205
1206int switchtec_ep_tunnel_status(struct switchtec_dev *dev, uint16_t pdfid,
1207 uint32_t *status)
1208{
1209 int ret;
1210
1211 ret = switchtec_ep_tunnel_config(dev, MRPC_EP_TUNNEL_STATUS,
1212 pdfid, sizeof(*status), NULL,
1213 0, (uint8_t *)status);
1214 *status = le32toh(*status);
1215
1216 return ret;
1217}
1218
1219static int ep_csr_read(struct switchtec_dev *dev,
1220 uint16_t pdfid, void *dest,
1221 uint16_t src, size_t n)
1222{
1223 int ret;
1224
1225 if (n > SWITCHTEC_EP_CSR_MAX_READ_LEN)
1226 n = SWITCHTEC_EP_CSR_MAX_READ_LEN;
1227
1228 if (!n)
1229 return n;
1230
1231 struct ep_cfg_read {
1232 uint8_t subcmd;
1233 uint8_t reserved0;
1234 uint16_t pdfid;
1235 uint16_t addr;
1236 uint8_t bytes;
1237 uint8_t reserved1;
1238 } cmd = {
1239 .subcmd = 0,
1240 .pdfid = htole16(pdfid),
1241 .addr = htole16(src),
1242 .bytes= n,
1243 };
1244
1245 struct {
1246 uint32_t data;
1247 } rsp;
1248
1249 ret = switchtec_cmd(dev, MRPC_EP_RESOURCE_ACCESS, &cmd,
1250 sizeof(cmd), &rsp, 4);
1251 if (ret)
1252 return -1;
1253
1254 memcpy(dest, &rsp.data, n);
1255 return 0;
1256}
1257
1258int switchtec_ep_csr_read8(struct switchtec_dev *dev, uint16_t pdfid,
1259 uint16_t addr, uint8_t *val)
1260{
1261 return ep_csr_read(dev, pdfid, val, addr, 1);
1262}
1263
1264int switchtec_ep_csr_read16(struct switchtec_dev *dev, uint16_t pdfid,
1265 uint16_t addr, uint16_t *val)
1266{
1267 int ret;
1268
1269 ret = ep_csr_read(dev, pdfid, val, addr, 2);
1270 *val = le16toh(*val);
1271
1272 return ret;
1273}
1274
1275int switchtec_ep_csr_read32(struct switchtec_dev *dev, uint16_t pdfid,
1276 uint16_t addr, uint32_t *val)
1277{
1278 int ret;
1279
1280 ret = ep_csr_read(dev, pdfid, val, addr, 4);
1281 *val = le32toh(*val);
1282
1283 return ret;
1284}
1285
1286static int ep_csr_write(struct switchtec_dev *dev, uint16_t pdfid,
1287 uint16_t addr, const void *val, size_t n)
1288{
1289 if (n > SWITCHTEC_EP_CSR_MAX_WRITE_LEN)
1290 n = SWITCHTEC_EP_CSR_MAX_WRITE_LEN;
1291
1292 if (!n)
1293 return n;
1294
1295 struct ep_cfg_write {
1296 uint8_t subcmd;
1297 uint8_t reserved0;
1298 uint16_t pdfid;
1299 uint16_t addr;
1300 uint8_t bytes;
1301 uint8_t reserved1;
1302 uint32_t data;
1303 } cmd = {
1304 .subcmd = 1,
1305 .pdfid = htole16(pdfid),
1306 .addr = htole16(addr),
1307 .bytes= n,
1308 };
1309
1310 memcpy(&cmd.data, val, n);
1311
1312 return switchtec_cmd(dev, MRPC_EP_RESOURCE_ACCESS, &cmd,
1313 sizeof(cmd), NULL, 0);
1314}
1315
1316int switchtec_ep_csr_write8(struct switchtec_dev *dev, uint16_t pdfid,
1317 uint8_t val, uint16_t addr)
1318{
1319 return ep_csr_write(dev, pdfid, addr, &val, 1);
1320}
1321
1322int switchtec_ep_csr_write16(struct switchtec_dev *dev, uint16_t pdfid,
1323 uint16_t val, uint16_t addr)
1324{
1325 val = htole16(val);
1326 return ep_csr_write(dev, pdfid, addr, &val, 2);
1327}
1328
1329int switchtec_ep_csr_write32(struct switchtec_dev *dev, uint16_t pdfid,
1330 uint32_t val, uint16_t addr)
1331{
1332 val = htole32(val);
1333 return ep_csr_write(dev, pdfid, addr, &val, 4);
1334}
1335
1336static size_t ep_bar_read(struct switchtec_dev *dev, uint16_t pdfid,
1337 uint8_t bar, void *dest,
1338 uint64_t src, size_t n)
1339{
1340 if (n > SWITCHTEC_EP_BAR_MAX_READ_LEN)
1341 n = SWITCHTEC_EP_BAR_MAX_READ_LEN;
1342
1343 if (!n)
1344 return n;
1345
1346 src = htole64(src);
1347
1348 struct ep_bar_read {
1349 uint8_t subcmd;
1350 uint8_t reserved0;
1351 uint16_t pdfid;
1352 uint8_t bar;
1353 uint8_t reserved1;
1354 uint16_t bytes;
1355 uint32_t addr_low;
1356 uint32_t addr_high;
1357 } cmd = {
1358 .subcmd = 2,
1359 .pdfid = htole16(pdfid),
1360 .bar = bar,
1361 .addr_low = (uint32_t)src,
1362 .addr_high = (uint32_t)(src >> 32),
1363 .bytes= htole16((uint16_t)n),
1364 };
1365
1366 return switchtec_cmd(dev, MRPC_EP_RESOURCE_ACCESS, &cmd,
1367 sizeof(cmd), dest, n);
1368}
1369
1370int switchtec_ep_bar_read8(struct switchtec_dev *dev, uint16_t pdfid,
1371 uint8_t bar, uint64_t addr, uint8_t *val)
1372{
1373 return ep_bar_read(dev, pdfid, bar, val, addr, 1);
1374}
1375
1376int switchtec_ep_bar_read16(struct switchtec_dev *dev, uint16_t pdfid,
1377 uint8_t bar, uint64_t addr, uint16_t *val)
1378{
1379 int ret;
1380
1381 ret = ep_bar_read(dev, pdfid, bar, val, addr, 2);
1382 *val = le16toh(*val);
1383
1384 return ret;
1385}
1386
1387int switchtec_ep_bar_read32(struct switchtec_dev *dev, uint16_t pdfid,
1388 uint8_t bar, uint64_t addr, uint32_t *val)
1389{
1390 int ret;
1391
1392 ret = ep_bar_read(dev, pdfid, bar, val, addr, 4);
1393 *val = le32toh(*val);
1394
1395 return ret;
1396}
1397
1398int switchtec_ep_bar_read64(struct switchtec_dev *dev, uint16_t pdfid,
1399 uint8_t bar, uint64_t addr, uint64_t *val)
1400{
1401 int ret;
1402
1403 ret = ep_bar_read(dev, pdfid, bar, val, addr, 8);
1404 *val = le64toh(*val);
1405
1406 return ret;
1407}
1408
1409static int ep_bar_write(struct switchtec_dev *dev, uint16_t pdfid,
1410 uint8_t bar, uint64_t addr,
1411 const void *val, size_t n)
1412{
1413 if (n > SWITCHTEC_EP_BAR_MAX_WRITE_LEN)
1414 n = SWITCHTEC_EP_BAR_MAX_WRITE_LEN;
1415
1416 if (!n)
1417 return n;
1418
1419 addr = htole64(addr);
1420
1421 struct ep_bar_write {
1422 uint8_t subcmd;
1423 uint8_t reserved0;
1424 uint16_t pdfid;
1425 uint8_t bar;
1426 uint8_t reserved1;
1427 uint16_t bytes;
1428 uint32_t addr_low;
1429 uint32_t addr_high;
1430 uint32_t data[128];
1431 } cmd = {
1432 .subcmd = 3,
1433 .pdfid = htole16(pdfid),
1434 .bar = bar,
1435 .bytes= htole16((uint16_t)n),
1436 .addr_low = (uint32_t)addr,
1437 .addr_high = (uint32_t)(addr >> 32),
1438 };
1439
1440 memcpy(&cmd.data, val, n);
1441
1442 return switchtec_cmd(dev, MRPC_EP_RESOURCE_ACCESS,
1443 &cmd, sizeof(cmd), NULL, 0);
1444}
1445
1446int switchtec_ep_bar_write8(struct switchtec_dev *dev, uint16_t pdfid,
1447 uint8_t bar, uint8_t val, uint64_t addr)
1448{
1449 return ep_bar_write(dev, pdfid, bar, addr, &val, 1);
1450}
1451
1452int switchtec_ep_bar_write16(struct switchtec_dev *dev, uint16_t pdfid,
1453 uint8_t bar, uint16_t val, uint64_t addr)
1454{
1455 val = htole16(val);
1456 return ep_bar_write(dev, pdfid, bar, addr, &val, 2);
1457}
1458
1459int switchtec_ep_bar_write32(struct switchtec_dev *dev, uint16_t pdfid,
1460 uint8_t bar, uint32_t val, uint64_t addr)
1461{
1462 val = htole32(val);
1463 return ep_bar_write(dev, pdfid, bar, addr, &val, 4);
1464}
1465
1466int switchtec_ep_bar_write64(struct switchtec_dev *dev, uint16_t pdfid,
1467 uint8_t bar, uint64_t val, uint64_t addr)
1468{
1469 val = htole64(val);
1470 return ep_bar_write(dev, pdfid, bar, addr, &val, 8);
1471}
1472
1473static int admin_passthru_start(struct switchtec_dev *dev, uint16_t pdfid,
1474 size_t data_len, void *data,
1475 size_t *rsp_len)
1476{
1477 int ret;
1478 uint16_t copy_len;
1479 uint16_t offset = 0;
1480
1481 struct {
1482 uint8_t subcmd;
1483 uint8_t rsvd[3];
1484 uint16_t pdfid;
1485 uint16_t expected_rsp_len;
1486 uint8_t more_data;
1487 uint8_t rsvd1[3];
1488 uint16_t data_offset;
1489 uint16_t data_len;
1490 uint8_t data[MRPC_MAX_DATA_LEN - 16];
1491 } cmd = {
1492 .subcmd = MRPC_NVME_ADMIN_PASSTHRU_START,
1493 .pdfid = htole16(pdfid)
1494 };
1495
1496 struct {
1497 uint16_t rsp_len;
1498 uint16_t rsvd1;
1499 } reply = {};
1500
1501 if (data_len && data != NULL) {
1502 cmd.more_data = data_len > sizeof(cmd.data);
1503 while (cmd.more_data) {
1504 copy_len = sizeof(cmd.data);
1505 memcpy(cmd.data, data + offset, copy_len);
1506
1507 cmd.data_offset = htole16(offset);
1508 cmd.data_len = htole16(copy_len);
1509
1510 ret = switchtec_cmd(dev, MRPC_NVME_ADMIN_PASSTHRU,
1511 &cmd, sizeof(cmd), NULL, 0);
1512 if (ret)
1513 return ret;
1514
1515 offset += copy_len;
1516 data_len -= copy_len;
1517 cmd.more_data = data_len > sizeof(cmd.data);
1518 }
1519
1520 if (data_len) {
1521 memcpy(cmd.data, data + offset, data_len);
1522
1523 cmd.data_offset = htole16(offset);
1524 cmd.data_len = htole16(data_len);
1525 } else {
1526 cmd.data_len = 0;
1527 cmd.data_offset = 0;
1528 }
1529 }
1530
1531 cmd.expected_rsp_len = htole16(*rsp_len);
1532
1533 ret = switchtec_cmd(dev, MRPC_NVME_ADMIN_PASSTHRU,
1534 &cmd, sizeof(cmd), &reply, sizeof(reply));
1535 if (ret) {
1536 *rsp_len = 0;
1537 return ret;
1538 }
1539
1540 *rsp_len = le16toh(reply.rsp_len);
1541 return 0;
1542}
1543
1544static int admin_passthru_data(struct switchtec_dev *dev, uint16_t pdfid,
1545 size_t rsp_len, void *rsp)
1546{
1547 size_t offset = 0;
1548 int ret;
1549 struct {
1550 uint8_t subcmd;
1551 uint8_t rsvd[3];
1552 uint16_t pdfid;
1553 uint16_t offset;
1554 } cmd = {
1555 .subcmd = MRPC_NVME_ADMIN_PASSTHRU_DATA,
1556 .pdfid = htole16(pdfid),
1557 };
1558
1559 struct {
1560 uint16_t offset;
1561 uint16_t len;
1562 uint8_t data[MRPC_MAX_DATA_LEN - 4];
1563 } reply = {};
1564
1565 while (offset < rsp_len) {
1566 cmd.offset = htole16(offset);
1567
1568 ret = switchtec_cmd(dev, MRPC_NVME_ADMIN_PASSTHRU,
1569 &cmd, sizeof(cmd), &reply,
1570 sizeof(reply));
1571 if (ret)
1572 return ret;
1573
1574 memcpy((uint8_t*)rsp + offset, reply.data,
1575 htole16(reply.len));
1576 offset += htole16(reply.len);
1577 }
1578
1579 return 0;
1580}
1581
1582static int admin_passthru_end(struct switchtec_dev *dev, uint16_t pdfid)
1583{
1584 struct {
1585 uint8_t subcmd;
1586 uint8_t rsvd[3];
1587 uint16_t pdfid;
1588 uint16_t rsvd1;
1589 } cmd = {};
1590
1591 cmd.subcmd = MRPC_NVME_ADMIN_PASSTHRU_END;
1592 cmd.pdfid = htole16(pdfid);
1593
1594 return switchtec_cmd(dev, MRPC_NVME_ADMIN_PASSTHRU,
1595 &cmd, sizeof(cmd), NULL, 0);
1596}
1597
1608int switchtec_nvme_admin_passthru(struct switchtec_dev *dev, uint16_t pdfid,
1609 size_t data_len, void *data,
1610 size_t *rsp_len, void *rsp)
1611{
1612 int ret;
1613
1614 ret = admin_passthru_start(dev, pdfid, data_len, data, rsp_len);
1615 if (ret)
1616 return ret;
1617
1618 if (*rsp_len && rsp != NULL) {
1619 ret = admin_passthru_data(dev, pdfid, *rsp_len, rsp);
1620 if (ret) {
1621 *rsp_len = 0;
1622 return ret;
1623 }
1624 }
1625
1626 ret = admin_passthru_end(dev, pdfid);
1627
1628 return ret;
1629}
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:164
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 each port in the in topology info.
Definition fabric.h:47
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:431
static int switchtec_is_gen5(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 5 device.
Definition switchtec.h:439
static int switchtec_is_pax_all(struct switchtec_dev *dev)
Return whether a Switchtec device is PAX(A).
Definition switchtec.h:548