Switchtec Userspace  PROJECT_NUMBER = PROJECT_NUMBER=PROJECT_NUMBER = 2.2
pmon.c
Go to the documentation of this file.
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 
30 #define SWITCHTEC_LIB_CORE
31 
32 #include "switchtec/pmon.h"
33 #include "switchtec_priv.h"
34 #include "switchtec/switchtec.h"
35 #include "switchtec/endian.h"
36 
37 #include <stddef.h>
38 #include <errno.h>
39 
60 #define ENTRY(x, h) {.mask=x, .name=#x, .help=h}
61 
63  ENTRY(ALL, "all events"),
64  ENTRY(ALL_TLPS, "all TLPs"),
65  ENTRY(ALL_ERRORS, "all errors"),
66  ENTRY(UNSUP_REQ_ERR, "Unsupported Request error"),
67  ENTRY(ECRC_ERR, "ECRC error"),
68  ENTRY(MALFORM_TLP_ERR, "Malformed TLP error"),
69  ENTRY(RCVR_OFLOW_ERR, "Receiver Overflow error"),
70  ENTRY(CMPLTR_ABORT_ERR, "Completer Abort error"),
71  ENTRY(POISONED_TLP_ERR, "Poisoned TLP error"),
72  ENTRY(SURPRISE_DOWN_ERR, "Surprise Down error"),
73  ENTRY(DATA_LINK_PROTO_ERR, "Data Link Protocol error"),
74  ENTRY(HDR_LOG_OFLOW_ERR, "Header Log Overflow error"),
75  ENTRY(UNCOR_INT_ERR, "Uncorrectable Internal Error"),
76  ENTRY(REPLAY_TMR_TIMEOUT, "Replay Timer Timeout"),
77  ENTRY(REPLAY_NUM_ROLLOVER, "Replay Number Rollover"),
78  ENTRY(BAD_DLLP, "Bad DLLP"),
79  ENTRY(BAD_TLP, "Bad TLP"),
80  ENTRY(RCVR_ERR, "Receiver Error"),
81  ENTRY(RCV_FATAL_MSG, "Fatal Error Message received"),
82  ENTRY(RCV_NON_FATAL_MSG, "Non-fatal Error Message received"),
83  ENTRY(RCV_CORR_MSG, "Correctable Error Message received"),
84  ENTRY(NAK_RCVD, "NAK received"),
85  ENTRY(RULE_TABLE_HIT, "Rule Search Table rule hit"),
86  ENTRY(POSTED_TLP, "Posted TLP"),
87  ENTRY(COMP_TLP, "Completion TLP"),
88  ENTRY(NON_POSTED_TLP, "Non-Posted TLP"),
89  {0}};
90 
96 {
97  const struct switchtec_evcntr_type_list *t;
98  int i = 0;
99 
100  for (t = switchtec_evcntr_type_list; t->name; t++, i++);
101 
102  return i;
103 }
104 
116 const char *switchtec_evcntr_type_str(int *type_mask)
117 {
118  const struct switchtec_evcntr_type_list *t;
119 
120  for (t = switchtec_evcntr_type_list; t->name; t++) {
121  if ((t->mask & *type_mask) != t->mask)
122  continue;
123 
124  *type_mask &= ~t->mask;
125  return t->name;
126  }
127 
128  return NULL;
129 }
130 
139 int switchtec_evcntr_setup(struct switchtec_dev *dev, unsigned stack_id,
140  unsigned cntr_id,
141  struct switchtec_evcntr_setup *setup)
142 {
143  struct pmon_event_counter_setup cmd = {
144  .sub_cmd_id = MRPC_PMON_SETUP_EV_COUNTER,
145  .stack_id = stack_id,
146  .counter_id = cntr_id,
147  .num_counters = 1,
148 
149  .counters = {
150  [0] = {
151  .mask = htole32((setup->type_mask << 8) |
152  (setup->port_mask & 0xFF)),
153  .ieg = setup->egress,
154  .thresh = htole32(setup->threshold),
155  },
156  },
157  };
158 
159  if (cntr_id >= SWITCHTEC_MAX_EVENT_COUNTERS) {
160  errno = EINVAL;
161  return -errno;
162  }
163 
164  return switchtec_cmd(dev, MRPC_PMON, &cmd, sizeof(cmd),
165  NULL, 0);
166 }
167 
168 static int evcntr_get(struct switchtec_dev *dev, int sub_cmd,
169  unsigned stack_id, unsigned cntr_id, unsigned nr_cntrs,
170  void *res, size_t res_size, int clear)
171 {
172  int ret;
173 
174  struct pmon_event_counter_get cmd = {
175  .sub_cmd_id = sub_cmd,
176  .stack_id = stack_id,
177  .counter_id = cntr_id,
178  .num_counters = nr_cntrs,
179  .read_clear = clear,
180  };
181 
182  if (res_size > MRPC_MAX_DATA_LEN ||
183  cntr_id >= SWITCHTEC_MAX_EVENT_COUNTERS ||
184  nr_cntrs > SWITCHTEC_MAX_EVENT_COUNTERS ||
185  cntr_id + nr_cntrs > SWITCHTEC_MAX_EVENT_COUNTERS)
186  {
187  errno = EINVAL;
188  return -errno;
189  }
190 
191  ret = switchtec_cmd(dev, MRPC_PMON, &cmd, sizeof(cmd),
192  res, res_size);
193 
194  if (ret) {
195  errno = ret;
196  return -EINVAL;
197  }
198 
199  return 0;
200 }
201 
214 int switchtec_evcntr_get_setup(struct switchtec_dev *dev, unsigned stack_id,
215  unsigned cntr_id, unsigned nr_cntrs,
216  struct switchtec_evcntr_setup *res)
217 {
218  int ret;
219  int i;
220  struct pmon_event_counter_get_setup_result data[nr_cntrs];
221 
222  if (res == NULL) {
223  errno = EINVAL;
224  return -errno;
225  }
226 
227  ret = evcntr_get(dev, MRPC_PMON_GET_EV_COUNTER_SETUP,
228  stack_id, cntr_id, nr_cntrs, data,
229  sizeof(*data) * nr_cntrs, 0);
230  if (ret)
231  return ret;
232 
233  for (i = 0; i < nr_cntrs; i++) {
234  res[i].port_mask = le32toh(data[i].mask) & 0xFF;
235  res[i].type_mask = le32toh(data[i].mask) >> 8;
236  res[i].egress = data[i].ieg;
237  res[i].threshold = le32toh(data[i].thresh);
238  }
239 
240  return nr_cntrs;
241 }
242 
257 int switchtec_evcntr_get(struct switchtec_dev *dev, unsigned stack_id,
258  unsigned cntr_id, unsigned nr_cntrs, unsigned *res,
259  int clear)
260 {
261  int ret;
262  int i;
263  struct pmon_event_counter_result data[nr_cntrs];
264 
265  if (res == NULL) {
266  errno = EINVAL;
267  return -errno;
268  }
269 
270  ret = evcntr_get(dev, MRPC_PMON_GET_EV_COUNTER,
271  stack_id, cntr_id, nr_cntrs, data,
272  sizeof(*data) * nr_cntrs, clear);
273  if (ret)
274  return ret;
275 
276  for (i = 0; i < nr_cntrs; i++)
277  res[i] = le32toh(data[i].value);
278 
279  return nr_cntrs;
280 }
281 
301 int switchtec_evcntr_get_both(struct switchtec_dev *dev, unsigned stack_id,
302  unsigned cntr_id, unsigned nr_cntrs,
303  struct switchtec_evcntr_setup *setup,
304  unsigned *counts, int clear)
305 {
306  int ret = 0;
307 
308  ret = switchtec_evcntr_get_setup(dev, stack_id, cntr_id, nr_cntrs,
309  setup);
310  if (ret < 0)
311  return ret;
312 
313  return switchtec_evcntr_get(dev, stack_id, cntr_id, nr_cntrs,
314  counts, clear);
315 }
316 
325 int switchtec_evcntr_wait(struct switchtec_dev *dev, int timeout_ms)
326 {
327  return switchtec_event_wait_for(dev, SWITCHTEC_PFF_EVT_THRESH,
328  SWITCHTEC_EVT_IDX_ALL,
329  NULL, timeout_ms);
330 }
331 
340  struct switchtec_bwcntr_res *old_cntr)
341 {
342  new_cntr->time_us -= old_cntr->time_us;
343  new_cntr->egress.posted -= old_cntr->egress.posted;
344  new_cntr->egress.nonposted -= old_cntr->egress.nonposted;
345  new_cntr->egress.comp -= old_cntr->egress.comp;
346  new_cntr->ingress.posted -= old_cntr->ingress.posted;
347  new_cntr->ingress.nonposted -= old_cntr->ingress.nonposted;
348  new_cntr->ingress.comp -= old_cntr->ingress.comp;
349 }
350 
359 int switchtec_bwcntr_set_many(struct switchtec_dev *dev, int nr_ports,
360  int * phys_port_ids,
361  enum switchtec_bw_type bw_type)
362 {
363  int i;
364  size_t cmd_size;
365  struct pmon_bw_set cmd = {
366  .sub_cmd_id = MRPC_PMON_SET_BW_COUNTER,
367  .count = nr_ports,
368  };
369 
370  for (i = 0; i < cmd.count; i++) {
371  cmd.ports[i].id = phys_port_ids[i];
372  cmd.ports[i].bw_type = bw_type;
373  }
374 
375  cmd_size = offsetof(struct pmon_bw_set, ports) +
376  sizeof(cmd.ports[0]) * cmd.count;
377 
378  return switchtec_cmd(dev, MRPC_PMON, &cmd, cmd_size, NULL, 0);
379 }
380 
387 int switchtec_bwcntr_set_all(struct switchtec_dev *dev,
388  enum switchtec_bw_type bw_type)
389 {
390  int ret, i;
391  struct switchtec_status *status;
392  int ids[SWITCHTEC_MAX_PORTS];
393 
394  ret = switchtec_status(dev, &status);
395  if (ret < 0)
396  return ret;
397 
398  for (i = 0; i < ret; i++) {
399  ids[i] = status[i].port.phys_id;
400  }
401 
402  ret = switchtec_bwcntr_set_many(dev, ret, ids, bw_type);
403  free(status);
404  return ret;
405 }
406 
419 int switchtec_bwcntr_many(struct switchtec_dev *dev, int nr_ports,
420  int *phys_port_ids, int clear,
421  struct switchtec_bwcntr_res *res)
422 {
423  int i;
424  int ret;
425  int remain = nr_ports;
426  size_t cmd_size;
427  struct pmon_bw_get cmd = {
428  .sub_cmd_id = MRPC_PMON_GET_BW_COUNTER,
429  };
430  int cmd_max_count = ((MRPC_MAX_DATA_LEN - sizeof(struct pmon_bw_get))
431  / sizeof(*res));
432 
433  while (remain) {
434  cmd.count = remain;
435  if (cmd.count > cmd_max_count)
436  cmd.count = cmd_max_count;
437 
438  for (i = 0; i < cmd.count; i++) {
439  cmd.ports[i].id = phys_port_ids[i];
440  cmd.ports[i].clear = clear;
441  }
442 
443  cmd_size = offsetof(struct pmon_bw_get, ports) +
444  sizeof(cmd.ports[0]) * cmd.count;
445 
446  ret = switchtec_cmd(dev, MRPC_PMON, &cmd, cmd_size, res,
447  sizeof(*res) * cmd.count);
448  if (ret)
449  return -1;
450 
451  remain -= cmd.count;
452  phys_port_ids += cmd.count;
453 
454  if (res)
455  res += cmd.count;
456  }
457 
458  return nr_ports;
459 }
460 
473 int switchtec_bwcntr_all(struct switchtec_dev *dev, int clear,
474  struct switchtec_port_id **ports,
475  struct switchtec_bwcntr_res **res)
476 {
477  int ret, i;
478  struct switchtec_status *status;
479  int ids[SWITCHTEC_MAX_PORTS];
480 
481  ret = switchtec_status(dev, &status);
482  if (ret < 0)
483  return ret;
484 
485  if (ports)
486  *ports = calloc(ret, sizeof(**ports));
487  if (res)
488  *res = calloc(ret, sizeof(**res));
489 
490  for (i = 0; i < ret; i++) {
491  ids[i] = status[i].port.phys_id;
492  if (ports)
493  (*ports)[i] = status[i].port;
494  }
495 
496  ret = switchtec_bwcntr_many(dev, ret, ids, clear, *res);
497  if (ret < 0) {
498  if (ports)
499  free(*ports);
500  if (res)
501  free(*res);
502  }
503 
504  free(status);
505  return ret;
506 }
507 
513 uint64_t switchtec_bwcntr_tot(struct switchtec_bwcntr_dir *d)
514 {
515  return d->posted + d->nonposted + d->comp;
516 }
517 
527 int switchtec_lat_setup_many(struct switchtec_dev *dev, int nr_ports,
528  int *egress_port_ids, int *ingress_port_ids)
529 {
530  int i;
531  size_t cmd_size;
532  struct pmon_lat_setup cmd = {
533  .sub_cmd_id = MRPC_PMON_SETUP_LAT_COUNTER,
534  .count = nr_ports,
535  };
536 
537  for (i = 0; i < nr_ports; i++) {
538  cmd.ports[i].egress = egress_port_ids[i];
539  cmd.ports[i].ingress = ingress_port_ids[i];
540  }
541 
542  cmd_size = offsetof(struct pmon_lat_setup, ports) +
543  sizeof(cmd.ports[0]) * nr_ports;
544 
545  return switchtec_cmd(dev, MRPC_PMON, &cmd, cmd_size, NULL, 0);
546 }
547 
557 int switchtec_lat_setup(struct switchtec_dev *dev, int egress_port_id,
558  int ingress_port_id, int clear)
559 {
560  int ret;
561 
562  ret = switchtec_lat_setup_many(dev, 1, &egress_port_id,
563  &ingress_port_id);
564  if (ret)
565  return ret;
566 
567  if (!clear)
568  return ret;
569 
570  return switchtec_lat_get(dev, 1, egress_port_id, NULL, NULL);
571 }
572 
585 int switchtec_lat_get_many(struct switchtec_dev *dev, int nr_ports,
586  int clear, int *egress_port_ids,
587  int *cur_ns, int *max_ns)
588 {
589  int ret, i;
590  size_t cmd_size;
591  struct pmon_lat_data resp[nr_ports];
592  struct pmon_lat_get cmd = {
593  .sub_cmd_id = MRPC_PMON_GET_LAT_COUNTER,
594  .count = nr_ports,
595  .clear = clear,
596  };
597 
598  for (i = 0; i < nr_ports; i++)
599  cmd.port_ids[i] = egress_port_ids[i];
600 
601  cmd_size = offsetof(struct pmon_lat_get, port_ids) +
602  sizeof(cmd.port_ids[0]) * nr_ports;
603 
604  ret = switchtec_cmd(dev, MRPC_PMON, &cmd, cmd_size, resp,
605  sizeof(*resp) * nr_ports);
606 
607  if (ret)
608  return -1;
609 
610  if (cur_ns)
611  for (i = 0; i < nr_ports; i++)
612  cur_ns[i] = resp[i].cur_ns;
613 
614  if (max_ns)
615  for (i = 0; i < nr_ports; i++)
616  max_ns[i] = resp[i].max_ns;
617 
618  return nr_ports;
619 }
620 
633 int switchtec_lat_get(struct switchtec_dev *dev, int clear,
634  int egress_port_ids, int *cur_ns,
635  int *max_ns)
636 {
637  return switchtec_lat_get_many(dev, 1, clear, &egress_port_ids,
638  cur_ns, max_ns);
639 }
640 
Completion TLP.
Definition: switchtec.h:743
ECRC Error.
Definition: switchtec.h:723
Bad TLP.
Definition: switchtec.h:735
Unsupported Request Error.
Definition: switchtec.h:722
Replay Timer Timeout.
Definition: switchtec.h:732
Rule Search Table Rule Hit.
Definition: switchtec.h:741
const char * switchtec_evcntr_type_str(int *type_mask)
Get a string for the event indicated by lowest bit set in the type_mask.
Definition: pmon.c:116
uint64_t switchtec_bwcntr_tot(struct switchtec_bwcntr_dir *d)
Get the total.
Definition: pmon.c:513
uint64_t comp
Completion TLP bytes.
Definition: switchtec.h:820
Uncorrectable Internal Error.
Definition: switchtec.h:731
uint64_t time_us
Time (in microseconds)
Definition: switchtec.h:817
Port identification.
Definition: switchtec.h:137
struct switchtec_port_id port
Port ID.
Definition: switchtec.h:154
int switchtec_bwcntr_set_many(struct switchtec_dev *dev, int nr_ports, int *phys_port_ids, enum switchtec_bw_type bw_type)
Set bandwidth type for a number of ports.
Definition: pmon.c:359
void switchtec_bwcntr_sub(struct switchtec_bwcntr_res *new_cntr, struct switchtec_bwcntr_res *old_cntr)
Subtract all the values between two bwcntr result structures.
Definition: pmon.c:339
Receive Correctable Error Message.
Definition: switchtec.h:739
int switchtec_evcntr_setup(struct switchtec_dev *dev, unsigned stack_id, unsigned cntr_id, struct switchtec_evcntr_setup *setup)
Setup an event counter performance monitor.
Definition: pmon.c:139
enum switchtec_evcntr_type_mask type_mask
Event counter types to count.
Definition: switchtec.h:784
int switchtec_status(struct switchtec_dev *dev, struct switchtec_status **status)
Get the status of all the ports on a switchtec device.
Definition: switchtec.c:389
int switchtec_evcntr_get_both(struct switchtec_dev *dev, unsigned stack_id, unsigned cntr_id, unsigned nr_cntrs, struct switchtec_evcntr_setup *setup, unsigned *counts, int clear)
Retrieve the current counts and setup information for one or more event counters. ...
Definition: pmon.c:301
Bad DLLP.
Definition: switchtec.h:734
struct switchtec_bwcntr_res::switchtec_bwcntr_dir egress
Bandwidth out of the port.
Mask indicating all possible errors.
Definition: switchtec.h:749
int switchtec_evcntr_get_setup(struct switchtec_dev *dev, unsigned stack_id, unsigned cntr_id, unsigned nr_cntrs, struct switchtec_evcntr_setup *res)
Retrieve the setup information for one or more event counters.
Definition: pmon.c:214
int switchtec_lat_get_many(struct switchtec_dev *dev, int nr_ports, int clear, int *egress_port_ids, int *cur_ns, int *max_ns)
Get a number of latency counter results.
Definition: pmon.c:585
Malformed TLP Error.
Definition: switchtec.h:724
Completer Abort Error.
Definition: switchtec.h:726
int switchtec_lat_setup_many(struct switchtec_dev *dev, int nr_ports, int *egress_port_ids, int *ingress_port_ids)
Setup a number of latency counters.
Definition: pmon.c:527
Posted TLP.
Definition: switchtec.h:742
Structure used to setup an event counter.
Definition: switchtec.h:780
switchtec_bw_type
The types of bandwidth.
Definition: switchtec.h:178
Non-Posted TLP.
Definition: switchtec.h:744
unsigned char phys_id
Physical port number.
Definition: switchtec.h:143
Replay Number Rollover.
Definition: switchtec.h:733
int switchtec_evcntr_wait(struct switchtec_dev *dev, int timeout_ms)
Block until any event counter has reached its threshold.
Definition: pmon.c:325
int switchtec_evcntr_type_count(void)
Get the number of event counter types.
Definition: pmon.c:95
int switchtec_bwcntr_many(struct switchtec_dev *dev, int nr_ports, int *phys_port_ids, int clear, struct switchtec_bwcntr_res *res)
Retrieve the bandwidth counter results for a number of ports.
Definition: pmon.c:419
unsigned threshold
Threshold to count to before generating an interrupt.
Definition: switchtec.h:791
uint64_t nonposted
Non-Posted TLP bytes.
Definition: switchtec.h:821
Main Switchtec header.
NAK Received.
Definition: switchtec.h:740
Port status structure.
Definition: switchtec.h:153
Mask indicating all event types.
Definition: switchtec.h:764
Header Log Overflow Error.
Definition: switchtec.h:730
Mask indicating all TLP types.
Definition: switchtec.h:759
Surprise Down Error.
Definition: switchtec.h:728
int switchtec_bwcntr_all(struct switchtec_dev *dev, int clear, struct switchtec_port_id **ports, struct switchtec_bwcntr_res **res)
Retrieve the bandwidth counter results for all the ports in the system.
Definition: pmon.c:473
int switchtec_lat_get(struct switchtec_dev *dev, int clear, int egress_port_ids, int *cur_ns, int *max_ns)
Get a single latency counter result.
Definition: pmon.c:633
Poisoned TLP Error.
Definition: switchtec.h:727
Receive FATAL Error Message.
Definition: switchtec.h:737
struct switchtec_bwcntr_res::switchtec_bwcntr_dir ingress
Bandwidth into the port.
int switchtec_bwcntr_set_all(struct switchtec_dev *dev, enum switchtec_bw_type bw_type)
Set bandwidth type for all the ports in the system.
Definition: pmon.c:387
Null-terminated list of all event counter types with a name and help text.
Definition: switchtec.h:771
int switchtec_event_wait_for(struct switchtec_dev *dev, enum switchtec_event_id e, int index, struct switchtec_event_summary *res, int timeout_ms)
Block until a specific event occurs.
Definition: events.c:369
int switchtec_evcntr_get(struct switchtec_dev *dev, unsigned stack_id, unsigned cntr_id, unsigned nr_cntrs, unsigned *res, int clear)
Retrieve the current counts for one or more event counters.
Definition: pmon.c:257
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:132
Receiver Error.
Definition: switchtec.h:736
Receiver Overflow Error.
Definition: switchtec.h:725
Data Link Protocol Error.
Definition: switchtec.h:729
int switchtec_lat_setup(struct switchtec_dev *dev, int egress_port_id, int ingress_port_id, int clear)
Setup a latency counter.
Definition: pmon.c:557
Bandwidth counter result struct.
Definition: switchtec.h:816
uint64_t posted
Posted TLP bytes.
Definition: switchtec.h:819
Receive Non-FATAL Error Message.
Definition: switchtec.h:738