Switchtec Userspace  PROJECT_NUMBER = 3.1
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 
35 static 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 
44 static 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
67 static 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 
109 static 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 
118 enum 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 
126 static 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 
188 static 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 
256 int 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 
270 int 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 
308 int 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 
336 int 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 
364 int 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 
392 int 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 
421 int 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 
431 static 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 
475 static 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 
489 int 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 
499 static 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 
527 static 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 
570 static 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 
585 int 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 
609 int 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 
697 int 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 
714 static 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 
743 static 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 
794 static 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 
809 static 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 
830 static 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 
853 static 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 
897 static 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 
918 int 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 
945 free_and_exit:
946  free(data);
947 exit:
948  return ret;
949 }
950 
951 static 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 
987 static 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 
1012 int 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 
1047 int 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 
1114 int 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 
1127 int 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 
1145 int 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 
1194 int 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 
1200 int 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 
1206 int 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 
1219 static 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 
1258 int 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 
1264 int 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 
1275 int 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 
1286 static 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 
1316 int 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 
1322 int 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 
1329 int 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 
1336 static 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 
1370 int 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 
1376 int 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 
1387 int 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 
1398 int 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 
1409 static 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 
1446 int 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 
1452 int 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 
1459 int 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 
1466 int 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 
1473 static 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 
1544 static 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 
1582 static 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 
1608 int 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 }
uint32_t stack_bif[8]
Port bifurcation.
Definition: fabric.h:80
uint8_t clock_sris
Port clock sris, enable/disable.
Definition: fabric.h:167
Represents each port in the in topology info.
Definition: fabric.h:47
uint8_t hvd_inst
HVM domain instance index for USP.
Definition: fabric.h:168
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:539
int num_stack_bif
Number of port bifurcation fields.
Definition: fabric.h:79
Represents the topology info.
Definition: fabric.h:76
uint64_t port_bitmap
Enabled physical port bitmap.
Definition: fabric.h:82
uint8_t route_port[16]
Route port.
Definition: fabric.h:81
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
The port config.
Definition: fabric.h:164
uint8_t clock_source
CSU channel index for port clock source(0-2)
Definition: fabric.h:166
uint8_t port_type
Port type.
Definition: fabric.h:165
uint8_t sw_idx
Switch index.
Definition: fabric.h:77
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
struct switchtec_fab_port_info port_info_list[SWITCHTEC_MAX_PORTS]
Port info list.
Definition: fabric.h:91
Represents the GFMS event.
Definition: fabric.h:603