Switchtec Userspace  PROJECT_NUMBER = PROJECT_NUMBER=PROJECT_NUMBER = 2.2
events.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_priv.h"
33 
34 #include "switchtec/switchtec.h"
35 #include "switchtec/utils.h"
36 
37 #include <sys/time.h>
38 
39 #include <errno.h>
40 #include <string.h>
41 #include <strings.h>
42 
57 #define EV(t, n, s, d)[SWITCHTEC_ ## t ## _EVT_ ## n] = {\
58  .type = t, \
59  .summary_bit = (1 << (s)), \
60  .short_name = #n, \
61  .desc = d, \
62 }
63 
64 #define GLOBAL SWITCHTEC_EVT_GLOBAL
65 #define PART SWITCHTEC_EVT_PART
66 #define PFF SWITCHTEC_EVT_PFF
67 
68 static const struct {
69  enum switchtec_event_id id;
70  enum switchtec_event_type type;
71  uint64_t summary_bit;
72  const char *short_name;
73  const char *desc;
74 } events[] = {
75  EV(GLOBAL, STACK_ERROR, 0, "Stack Error"),
76  EV(GLOBAL, PPU_ERROR, 1, "PPU Error"),
77  EV(GLOBAL, ISP_ERROR, 2, "ISP Error"),
78  EV(GLOBAL, SYS_RESET, 3, "System Reset"),
79  EV(GLOBAL, FW_EXC, 4, "Firmware Exception"),
80  EV(GLOBAL, FW_NMI, 5, "Firmware Non-Maskable Interrupt"),
81  EV(GLOBAL, FW_NON_FATAL, 6, "Firmware Non-Fatal Error"),
82  EV(GLOBAL, FW_FATAL, 7, "Firmware Fatal Error"),
83  EV(GLOBAL, TWI_MRPC_COMP, 8, "TWI MRPC Completion"),
84  EV(GLOBAL, TWI_MRPC_COMP_ASYNC, 9, "TWI MRPC Async Completion"),
85  EV(GLOBAL, CLI_MRPC_COMP, 10, "CLI MRPC Completion"),
86  EV(GLOBAL, CLI_MRPC_COMP_ASYNC, 11, "CLI MRPC Async Completion"),
87  EV(GLOBAL, GPIO_INT, 12, "GPIO Interrupt"),
88  EV(GLOBAL, GFMS, 13, "Global Fabric Management Server Event"),
89  EV(PART, PART_RESET, 0, "Partition Reset"),
90  EV(PART, MRPC_COMP, 1, "MRPC Completion"),
91  EV(PART, MRPC_COMP_ASYNC, 2, "MRPC Async Completion"),
92  EV(PART, DYN_PART_BIND_COMP, 3,
93  "Dynamic Partition Binding Completion"),
94  EV(PFF, AER_IN_P2P, 0, "Advanced Error Reporting in P2P Port"),
95  EV(PFF, AER_IN_VEP, 1, "Advanced Error Reporting in vEP"),
96  EV(PFF, DPC, 2, "Downstream Port Containment Event"),
97  EV(PFF, CTS, 3, "Completion Timeout Synthesis Event"),
98  EV(PFF, UEC, 4, "Upstream Error Containment Event"),
99  EV(PFF, HOTPLUG, 5, "Hotplug Event"),
100  EV(PFF, IER, 6, "Internal Error Reporting Event"),
101  EV(PFF, THRESH, 7, "Event Counter Threshold Reached"),
102  EV(PFF, POWER_MGMT, 8, "Power Management Event"),
103  EV(PFF, TLP_THROTTLING, 9, "TLP Throttling Event"),
104  EV(PFF, FORCE_SPEED, 10, "Force Speed Error"),
105  EV(PFF, CREDIT_TIMEOUT, 11, "Credit Timeout"),
106  EV(PFF, LINK_STATE, 12, "Link State Change Event"),
107 };
108 
109 #define EVBIT(t, n, b)[b] = SWITCHTEC_ ## t ## _EVT_ ## n
110 static const enum switchtec_event_id global_event_bits[64] = {
111  [0 ... 63] = -1,
112  EVBIT(GLOBAL, STACK_ERROR, 0),
113  EVBIT(GLOBAL, PPU_ERROR, 1),
114  EVBIT(GLOBAL, ISP_ERROR, 2),
115  EVBIT(GLOBAL, SYS_RESET, 3),
116  EVBIT(GLOBAL, FW_EXC, 4),
117  EVBIT(GLOBAL, FW_NMI, 5),
118  EVBIT(GLOBAL, FW_NON_FATAL, 6),
119  EVBIT(GLOBAL, FW_FATAL, 7),
120  EVBIT(GLOBAL, TWI_MRPC_COMP, 8),
121  EVBIT(GLOBAL, TWI_MRPC_COMP_ASYNC, 9),
122  EVBIT(GLOBAL, CLI_MRPC_COMP, 10),
123  EVBIT(GLOBAL, CLI_MRPC_COMP_ASYNC, 11),
124  EVBIT(GLOBAL, GPIO_INT, 12),
125 };
126 
127 static const enum switchtec_event_id part_event_bits[64] = {
128  [0 ... 63] = -1,
129  EVBIT(PART, PART_RESET, 0),
130  EVBIT(PART, MRPC_COMP, 1),
131  EVBIT(PART, MRPC_COMP_ASYNC, 2),
132  EVBIT(PART, DYN_PART_BIND_COMP, 3),
133 };
134 
135 static const enum switchtec_event_id pff_event_bits[64] = {
136  [0 ... 63] = -1,
137  EVBIT(PFF, AER_IN_P2P, 0),
138  EVBIT(PFF, AER_IN_VEP, 1),
139  EVBIT(PFF, DPC, 2),
140  EVBIT(PFF, CTS, 3),
141  EVBIT(PFF, UEC, 4),
142  EVBIT(PFF, HOTPLUG, 5),
143  EVBIT(PFF, IER, 6),
144  EVBIT(PFF, THRESH, 7),
145  EVBIT(PFF, POWER_MGMT, 8),
146  EVBIT(PFF, TLP_THROTTLING, 9),
147  EVBIT(PFF, FORCE_SPEED, 10),
148  EVBIT(PFF, CREDIT_TIMEOUT, 11),
149  EVBIT(PFF, LINK_STATE, 12),
150 };
151 
152 static void set_all_parts(struct switchtec_event_summary *sum, uint64_t bit)
153 {
154  int i;
155 
156  for (i = 0; i < ARRAY_SIZE(sum->part); i++)
157  sum->part[i] |= bit;
158 }
159 
160 static void set_all_pffs(struct switchtec_event_summary *sum, uint64_t bit)
161 {
162  int i;
163 
164  for (i = 0; i < ARRAY_SIZE(sum->pff); i++)
165  sum->pff[i] |= bit;
166 }
167 
176  enum switchtec_event_id e,
177  int index)
178 {
179  uint64_t bit = events[e].summary_bit;
180 
181  switch (events[e].type) {
182  case GLOBAL:
183  sum->global |= bit;
184  break;
185  case PART:
186  if (index == SWITCHTEC_EVT_IDX_LOCAL) {
187  sum->local_part |= bit;
188  } else if (index == SWITCHTEC_EVT_IDX_ALL) {
189  set_all_parts(sum, bit);
190  } else if (index < 0 || index >= ARRAY_SIZE(sum->part)) {
191  errno = EINVAL;
192  return -EINVAL;
193  } else {
194  sum->part[index] |= bit;
195  }
196  break;
197  case PFF:
198  if (index == SWITCHTEC_EVT_IDX_ALL) {
199  set_all_pffs(sum, bit);
200  } else if (index < 0 || index >= ARRAY_SIZE(sum->pff)) {
201  errno = EINVAL;
202  return -EINVAL;
203  } else {
204  sum->pff[index] |= bit;
205  }
206  break;
207  }
208 
209  return 0;
210 }
211 
220  enum switchtec_event_id e,
221  int index)
222 {
223  uint64_t bit = events[e].summary_bit;
224 
225  switch (events[e].type) {
226  case GLOBAL:
227  return sum->global & bit;
228  case PART:
229  return sum->part[index] & bit;
230  case PFF:
231  return sum->pff[index] & bit;
232  }
233 
234  return 0;
235 }
236 
249  enum switchtec_event_id *e,
250  int *idx)
251 {
252  int bit;
253 
254  if (!idx || !e)
255  return -EINVAL;
256 
257  *idx = 0;
258 
259  bit = ffs(sum->global) - 1;
260  if (bit >= 0) {
261  *e = global_event_bits[bit];
262  sum->global &= ~(1 << bit);
263  return 1;
264  }
265 
266  for (*idx = 0; *idx < ARRAY_SIZE(sum->part); (*idx)++) {
267  bit = ffs(sum->part[*idx]) - 1;
268  if (bit < 0)
269  continue;
270 
271  *e = part_event_bits[bit];
272  sum->part[*idx] &= ~(1 << bit);
273  return 1;
274  }
275 
276  for (*idx = 0; *idx < ARRAY_SIZE(sum->pff); (*idx)++) {
277  bit = ffs(sum->pff[*idx]) - 1;
278  if (bit < 0)
279  continue;
280 
281  *e = pff_event_bits[bit];
282  sum->pff[*idx] &= ~(1 << bit);
283  return 1;
284  }
285 
286  return 0;
287 }
288 
297 int switchtec_event_check(struct switchtec_dev *dev,
298  struct switchtec_event_summary *chk,
299  struct switchtec_event_summary *res)
300 {
301  struct switchtec_event_summary res_tmp;
302  int i;
303  int ret;
304 
305  if (!chk)
306  return -EINVAL;
307 
308  if (!res)
309  res = &res_tmp;
310 
311  ret = switchtec_event_summary(dev, res);
312  if (ret)
313  return ret;
314 
315  if (chk->global & res->global)
316  return 1;
317 
318  if (chk->part_bitmap & res->part_bitmap)
319  return 1;
320 
321  if (chk->local_part & res->local_part)
322  return 1;
323 
324  for (i = 0; i < SWITCHTEC_MAX_PARTS; i++)
325  if (chk->part[i] & res->part[i])
326  return 1;
327 
328  for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++)
329  if (chk->pff[i] & res->pff[i])
330  return 1;
331 
332  return 0;
333 }
334 
344  const char **name,
345  const char **desc)
346 {
347  if (e <= SWITCHTEC_EVT_INVALID || e >= SWITCHTEC_MAX_EVENTS)
348  return -1;
349 
350  if (name)
351  *name = events[e].short_name;
352 
353  if (desc)
354  *desc = events[e].desc;
355 
356  return events[e].type;
357 }
358 
369 int switchtec_event_wait_for(struct switchtec_dev *dev,
370  enum switchtec_event_id e, int index,
371  struct switchtec_event_summary *res,
372  int timeout_ms)
373 {
374  struct timeval tv;
375  long long start, now;
376  struct switchtec_event_summary wait_for = {0};
377  int ret;
378 
379  if (dev->ops->event_wait_for)
380  return dev->ops->event_wait_for(dev, e, index, res, timeout_ms);
381 
382  ret = switchtec_event_summary_set(&wait_for, e, index);
383  if (ret)
384  return ret;
385 
386  ret = switchtec_event_ctl(dev, e, index,
387  SWITCHTEC_EVT_FLAG_CLEAR |
388  SWITCHTEC_EVT_FLAG_EN_POLL,
389  NULL);
390  if (ret < 0)
391  return ret;
392 
393  ret = gettimeofday(&tv, NULL);
394  if (ret)
395  return ret;
396 
397  now = start = ((tv.tv_sec) * 1000 + tv.tv_usec / 1000);
398 
399  while (1) {
400  ret = switchtec_event_wait(dev, timeout_ms > 0 ?
401  now - start + timeout_ms : -1);
402  if (ret < 0)
403  return ret;
404 
405  if (ret == 0)
406  goto next;
407 
408  ret = switchtec_event_check(dev, &wait_for, res);
409  if (ret < 0)
410  return ret;
411 
412  if (ret)
413  return 1;
414 
415 next:
416  ret = gettimeofday(&tv, NULL);
417  if (ret)
418  return ret;
419 
420  now = ((tv.tv_sec) * 1000 + tv.tv_usec / 1000);
421 
422  if (timeout_ms > 0 && now - start >= timeout_ms) {
423  ret = switchtec_event_summary(dev, res);
424  return ret;
425  }
426  }
427 }
428 
int switchtec_event_check(struct switchtec_dev *dev, struct switchtec_event_summary *chk, struct switchtec_event_summary *res)
Check if one or more events have occurred.
Definition: events.c:297
int switchtec_event_summary_test(struct switchtec_event_summary *sum, enum switchtec_event_id e, int index)
Test if a bit corresponding to an event is set in a summary structure.
Definition: events.c:219
int switchtec_event_summary_iter(struct switchtec_event_summary *sum, enum switchtec_event_id *e, int *idx)
Iterate through all set bits in an event summary structure.
Definition: events.c:248
switchtec_event_id
Enumeration of all possible events.
Definition: switchtec.h:265
enum switchtec_event_type switchtec_event_info(enum switchtec_event_id e, const char **name, const char **desc)
Get the name and description strings as well as the type (global, partition or pff) for a specific ev...
Definition: events.c:343
int switchtec_event_summary_set(struct switchtec_event_summary *sum, enum switchtec_event_id e, int index)
Set a bit corresponding to an event in a summary structure.
Definition: events.c:175
Event summary bitmaps.
Definition: switchtec.h:250
uint64_t part_bitmap
Bitmap of partitions with active events.
Definition: switchtec.h:252
Main Switchtec header.
int switchtec_event_wait(struct switchtec_dev *dev, int timeout_ms)
Wait for any event to occur (typically just an interrupt)
Definition: platform.c:297
uint64_t global
Bitmap of global events.
Definition: switchtec.h:251
unsigned pff[SWITCHTEC_MAX_PFF_CSR]
Bitmap of events in each port function.
Definition: switchtec.h:259
unsigned part[SWITCHTEC_MAX_PARTS]
Bitmap of events in each partition.
Definition: switchtec.h:256
switchtec_event_type
There are three event types indicated by this enumeration: global, partition and port function...
Definition: switchtec.h:620
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_event_ctl(struct switchtec_dev *dev, enum switchtec_event_id e, int index, int flags, uint32_t data[5])
Enable, disable and clear events or retrieve event data.
Definition: platform.c:281
int switchtec_event_summary(struct switchtec_dev *dev, struct switchtec_event_summary *sum)
Retrieve a summary of all the events that have occurred in the switch.
Definition: platform.c:265
unsigned local_part
Bitmap of events in the local partition.
Definition: switchtec.h:253