2 * collectd - src/pcie_errors.c
4 * Copyright(c) 2018 Intel Corporation. All rights reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * Kamil Wiatrowski <kamilx.wiatrowski@intel.com>
31 #include "utils_llist.h"
33 #include <linux/pci_regs.h>
35 #define PCIE_ERRORS_PLUGIN "pcie_errors"
36 #define PCIE_DEFAULT_PROCDIR "/proc/bus/pci"
37 #define PCIE_DEFAULT_SYSFSDIR "/sys/bus/pci"
38 #define PCIE_NAME_LEN 512
39 #define PCIE_BUFF_SIZE 1024
41 #define PCIE_ERROR "pcie_error"
42 #define PCIE_SEV_CE "correctable"
43 #define PCIE_SEV_FATAL "fatal"
44 #define PCIE_SEV_NOFATAL "non_fatal"
46 #define PCIE_DEV(x) (((x) >> 3) & 0x1f)
47 #define PCIE_FN(x) ((x)&0x07)
49 #define PCIE_ECAP_OFFSET 0x100 /* ECAP always begin at offset 0x100 */
51 typedef struct pcie_config_s {
55 char access_dir[PATH_MAX];
59 typedef struct pcie_device_s {
67 uint16_t device_status;
68 uint32_t correctable_errors;
69 uint32_t uncorrectable_errors;
72 typedef struct pcie_fops_s {
73 int (*list_devices)(llist_t *dev_list);
74 int (*open)(pcie_device_t *dev);
75 void (*close)(pcie_device_t *dev);
76 int (*read)(pcie_device_t *dev, void *buff, int size, int pos);
79 typedef struct pcie_error_s {
84 static llist_t *pcie_dev_list;
85 static pcie_config_t pcie_config = {.access_dir = "", .use_sysfs = 1};
86 static pcie_fops_t pcie_fops;
88 /* Device Error Status */
89 static pcie_error_t pcie_base_errors[] = {
90 {PCI_EXP_DEVSTA_CED, "Correctable Error"},
91 {PCI_EXP_DEVSTA_NFED, "Non-Fatal Error"},
92 {PCI_EXP_DEVSTA_FED, "Fatal Error"},
93 {PCI_EXP_DEVSTA_URD, "Unsupported Request"}};
94 static const int pcie_base_errors_num = STATIC_ARRAY_SIZE(pcie_base_errors);
96 /* Uncorrectable Error Status */
97 static pcie_error_t pcie_aer_ues[] = {
98 #ifdef PCI_ERR_UNC_DLP
99 {PCI_ERR_UNC_DLP, "Data Link Protocol"},
101 #ifdef PCI_ERR_UNC_SURPDN
102 {PCI_ERR_UNC_SURPDN, "Surprise Down"},
104 #ifdef PCI_ERR_UNC_POISON_TLP
105 {PCI_ERR_UNC_POISON_TLP, "Poisoned TLP"},
107 #ifdef PCI_ERR_UNC_FCP
108 {PCI_ERR_UNC_FCP, "Flow Control Protocol"},
110 #ifdef PCI_ERR_UNC_COMP_TIME
111 {PCI_ERR_UNC_COMP_TIME, "Completion Timeout"},
113 #ifdef PCI_ERR_UNC_COMP_ABORT
114 {PCI_ERR_UNC_COMP_ABORT, "Completer Abort"},
116 #ifdef PCI_ERR_UNC_UNX_COMP
117 {PCI_ERR_UNC_UNX_COMP, "Unexpected Completion"},
119 #ifdef PCI_ERR_UNC_RX_OVER
120 {PCI_ERR_UNC_RX_OVER, "Receiver Overflow"},
122 #ifdef PCI_ERR_UNC_MALF_TLP
123 {PCI_ERR_UNC_MALF_TLP, "Malformed TLP"},
125 #ifdef PCI_ERR_UNC_ECRC
126 {PCI_ERR_UNC_ECRC, "ECRC Error Status"},
128 #ifdef PCI_ERR_UNC_UNSUP
129 {PCI_ERR_UNC_UNSUP, "Unsupported Request"},
131 #ifdef PCI_ERR_UNC_ACSV
132 {PCI_ERR_UNC_ACSV, "ACS Violation"},
134 #ifdef PCI_ERR_UNC_INTN
135 {PCI_ERR_UNC_INTN, "Internal"},
137 #ifdef PCI_ERR_UNC_MCBTLP
138 {PCI_ERR_UNC_MCBTLP, "MC blocked TLP"},
140 #ifdef PCI_ERR_UNC_ATOMEG
141 {PCI_ERR_UNC_ATOMEG, "Atomic egress blocked"},
143 #ifdef PCI_ERR_UNC_TLPPRE
144 {PCI_ERR_UNC_TLPPRE, "TLP prefix blocked"},
147 static const int pcie_aer_ues_num = STATIC_ARRAY_SIZE(pcie_aer_ues);
149 /* Correctable Error Status */
150 static pcie_error_t pcie_aer_ces[] = {
151 #ifdef PCI_ERR_COR_RCVR
152 {PCI_ERR_COR_RCVR, "Receiver Error Status"},
154 #ifdef PCI_ERR_COR_BAD_TLP
155 {PCI_ERR_COR_BAD_TLP, "Bad TLP Status"},
157 #ifdef PCI_ERR_COR_BAD_DLLP
158 {PCI_ERR_COR_BAD_DLLP, "Bad DLLP Status"},
160 #ifdef PCI_ERR_COR_REP_ROLL
161 {PCI_ERR_COR_REP_ROLL, "REPLAY_NUM Rollover"},
163 #ifdef PCI_ERR_COR_REP_TIMER
164 {PCI_ERR_COR_REP_TIMER, "Replay Timer Timeout"},
166 #ifdef PCI_ERR_COR_ADV_NFAT
167 {PCI_ERR_COR_ADV_NFAT, "Advisory Non-Fatal"},
169 #ifdef PCI_ERR_COR_INTERNAL
170 {PCI_ERR_COR_INTERNAL, "Corrected Internal"},
172 #ifdef PCI_ERR_COR_LOG_OVER
173 {PCI_ERR_COR_LOG_OVER, "Header Log Overflow"},
176 static const int pcie_aer_ces_num = STATIC_ARRAY_SIZE(pcie_aer_ces);
178 static int pcie_add_device(llist_t *list, int domain, uint8_t bus,
179 uint8_t device, uint8_t fn) {
181 pcie_device_t *dev = calloc(1, sizeof(*dev));
183 ERROR(PCIE_ERRORS_PLUGIN ": Failed to allocate device");
187 dev->domain = domain;
189 dev->device = device;
193 entry = llentry_create(NULL, dev);
195 ERROR(PCIE_ERRORS_PLUGIN ": Failed to create llentry");
199 llist_append(list, entry);
201 DEBUG(PCIE_ERRORS_PLUGIN ": pci device added to list: %04x:%02x:%02x.%d",
202 domain, bus, device, fn);
206 static void pcie_clear_list(llist_t *list) {
210 for (llentry_t *e = llist_head(list); e != NULL; e = e->next)
216 static int pcie_list_devices_proc(llist_t *dev_list) {
218 char file_name[PCIE_NAME_LEN];
219 char buf[PCIE_BUFF_SIZE];
223 if (dev_list == NULL)
226 snprintf(file_name, sizeof(file_name), "%s/devices", pcie_config.access_dir);
227 fd = fopen(file_name, "r");
229 char errbuf[PCIE_BUFF_SIZE];
230 ERROR(PCIE_ERRORS_PLUGIN ": Cannot open file %s to get devices list: %s",
231 file_name, sstrerror(errno, errbuf, sizeof(errbuf)));
235 while (fgets(buf, sizeof(buf), fd)) {
237 uint8_t bus, dev, fn;
239 if (sscanf(buf, "%x", &slot) != 1) {
240 ERROR(PCIE_ERRORS_PLUGIN ": Failed to read line %u from %s", i + 1,
246 dev = PCIE_DEV(slot);
248 ret = pcie_add_device(dev_list, 0, bus, dev, fn);
259 static int pcie_list_devices_sysfs(llist_t *dev_list) {
262 char dir_name[PCIE_NAME_LEN];
265 if (dev_list == NULL)
268 snprintf(dir_name, sizeof(dir_name), "%s/devices", pcie_config.access_dir);
269 dir = opendir(dir_name);
271 char errbuf[PCIE_BUFF_SIZE];
272 ERROR(PCIE_ERRORS_PLUGIN ": Cannot open dir %s to get devices list: %s",
273 dir_name, sstrerror(errno, errbuf, sizeof(errbuf)));
277 while ((item = readdir(dir))) {
278 unsigned int dom, bus, dev;
281 /* Omit special non-device entries */
282 if (item->d_name[0] == '.')
285 if (sscanf(item->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &fn) != 4) {
286 ERROR(PCIE_ERRORS_PLUGIN ": Failed to parse entry %s", item->d_name);
290 ret = pcie_add_device(dev_list, dom, bus, dev, fn);
299 static void pcie_close(pcie_device_t *dev) {
300 if (close(dev->fd) == -1) {
301 char errbuf[PCIE_BUFF_SIZE];
302 ERROR(PCIE_ERRORS_PLUGIN ": Failed to close %04x:%02x:%02x.%d, fd=%d: %s",
303 dev->domain, dev->bus, dev->device, dev->function, dev->fd,
304 sstrerror(errno, errbuf, sizeof(errbuf)));
310 static int pcie_open(pcie_device_t *dev, const char *name) {
311 dev->fd = open(name, O_RDONLY);
313 char errbuf[PCIE_BUFF_SIZE];
314 ERROR(PCIE_ERRORS_PLUGIN ": Failed to open file %s: %s", name,
315 sstrerror(errno, errbuf, sizeof(errbuf)));
322 static int pcie_open_proc(pcie_device_t *dev) {
323 char file_name[PCIE_NAME_LEN];
325 snprintf(file_name, sizeof(file_name), "%s/%02x/%02x.%d",
326 pcie_config.access_dir, dev->bus, dev->device, dev->function);
328 return pcie_open(dev, file_name);
331 static int pcie_open_sysfs(pcie_device_t *dev) {
332 char file_name[PCIE_NAME_LEN];
334 snprintf(file_name, sizeof(file_name), "%s/devices/%04x:%02x:%02x.%d/config",
335 pcie_config.access_dir, dev->domain, dev->bus, dev->device,
338 return pcie_open(dev, file_name);
341 static int pcie_read(pcie_device_t *dev, void *buff, int size, int pos) {
342 int len = pread(dev->fd, buff, size, pos);
347 char errbuf[PCIE_BUFF_SIZE];
348 ERROR(PCIE_ERRORS_PLUGIN ": Failed to read %04x:%02x:%02x.%d at pos %d: %s",
349 dev->domain, dev->bus, dev->device, dev->function, pos,
350 sstrerror(errno, errbuf, sizeof(errbuf)));
352 ERROR(PCIE_ERRORS_PLUGIN
353 ": %04x:%02x:%02x.%d Read only %d bytes, should be %d",
354 dev->domain, dev->bus, dev->device, dev->function, len, size);
359 static uint8_t pcie_read8(pcie_device_t *dev, int pos) {
361 if (pcie_fops.read(dev, &value, 1, pos))
366 static uint16_t pcie_read16(pcie_device_t *dev, int pos) {
368 if (pcie_fops.read(dev, &value, 2, pos))
373 static uint32_t pcie_read32(pcie_device_t *dev, int pos) {
375 if (pcie_fops.read(dev, &value, 4, pos))
380 static void pcie_dispatch_notification(pcie_device_t *dev, notification_t *n,
382 const char *type_instance) {
383 sstrncpy(n->host, hostname_g, sizeof(n->host));
384 snprintf(n->plugin_instance, sizeof(n->plugin_instance), "%04x:%02x:%02x.%d",
385 dev->domain, dev->bus, dev->device, dev->function);
386 sstrncpy(n->type, type, sizeof(n->type));
387 sstrncpy(n->type_instance, type_instance, sizeof(n->type_instance));
389 plugin_dispatch_notification(n);
392 /* Report errors found in AER Correctable Error Status register */
393 static void pcie_dispatch_correctable_errors(pcie_device_t *dev,
394 uint32_t errors, uint32_t masked) {
395 for (int i = 0; i < pcie_aer_ces_num; i++) {
396 pcie_error_t *err = pcie_aer_ces + i;
397 notification_t n = {.severity = NOTIF_WARNING,
399 .plugin = PCIE_ERRORS_PLUGIN,
402 /* If not specifically set by config option omit masked errors */
403 if (!pcie_config.notif_masked && (err->mask & masked))
406 if (err->mask & errors) {
407 /* Error already reported, notify only if persistent is set */
408 if (!pcie_config.persistent && (err->mask & dev->correctable_errors))
411 DEBUG(PCIE_ERRORS_PLUGIN ": %04x:%02x:%02x.%d: %s set", dev->domain,
412 dev->bus, dev->device, dev->function, err->desc);
413 snprintf(n.message, sizeof(n.message), "Correctable Error set: %s",
415 pcie_dispatch_notification(dev, &n, PCIE_ERROR, PCIE_SEV_CE);
417 } else if (err->mask & dev->correctable_errors) {
418 DEBUG(PCIE_ERRORS_PLUGIN ": %04x:%02x:%02x.%d: %s cleared", dev->domain,
419 dev->bus, dev->device, dev->function, err->desc);
421 n.severity = NOTIF_OKAY;
422 snprintf(n.message, sizeof(n.message), "Correctable Error cleared: %s",
424 pcie_dispatch_notification(dev, &n, PCIE_ERROR, PCIE_SEV_CE);
429 /* Report errors found in AER Uncorrectable Error Status register */
430 static void pcie_dispatch_uncorrectable_errors(pcie_device_t *dev,
431 uint32_t errors, uint32_t masked,
433 for (int i = 0; i < pcie_aer_ues_num; i++) {
434 pcie_error_t *err = pcie_aer_ues + i;
435 const char *type_instance =
436 (severity & err->mask) ? PCIE_SEV_FATAL : PCIE_SEV_NOFATAL;
438 .time = cdtime(), .plugin = PCIE_ERRORS_PLUGIN, .meta = NULL};
440 /* If not specifically set by config option omit masked errors */
441 if (!pcie_config.notif_masked && (err->mask & masked))
444 if (err->mask & errors) {
445 /* Error already reported, notify only if persistent is set */
446 if (!pcie_config.persistent && (err->mask & dev->uncorrectable_errors))
449 DEBUG(PCIE_ERRORS_PLUGIN ": %04x:%02x:%02x.%d: %s(%s) set", dev->domain,
450 dev->bus, dev->device, dev->function, err->desc, type_instance);
452 n.severity = (severity & err->mask) ? NOTIF_FAILURE : NOTIF_WARNING;
453 snprintf(n.message, sizeof(n.message), "Uncorrectable(%s) Error set: %s",
454 type_instance, err->desc);
455 pcie_dispatch_notification(dev, &n, PCIE_ERROR, type_instance);
457 } else if (err->mask & dev->uncorrectable_errors) {
458 DEBUG(PCIE_ERRORS_PLUGIN ": %04x:%02x:%02x.%d: %s(%s) cleared",
459 dev->domain, dev->bus, dev->device, dev->function, err->desc,
462 n.severity = NOTIF_OKAY;
463 snprintf(n.message, sizeof(n.message),
464 "Uncorrectable(%s) Error cleared: %s", type_instance, err->desc);
465 pcie_dispatch_notification(dev, &n, PCIE_ERROR, type_instance);
470 /* Find offset of PCI Express Capability Structure
471 * in PCI configuration space.
472 * Returns offset, -1 if not found.
474 static int pcie_find_cap_exp(pcie_device_t *dev) {
475 int pos = pcie_read8(dev, PCI_CAPABILITY_LIST) & ~3;
478 uint8_t id = pcie_read8(dev, pos + PCI_CAP_LIST_ID);
482 if (id == PCI_CAP_ID_EXP)
485 pos = pcie_read8(dev, pos + PCI_CAP_LIST_NEXT) & ~3;
488 DEBUG(PCIE_ERRORS_PLUGIN ": Cannot find CAP EXP for %04x:%02x:%02x.%d",
489 dev->domain, dev->bus, dev->device, dev->function);
494 /* Find offset of Advanced Error Reporting Capability.
495 * Returns AER offset, -1 if not found.
497 static int pcie_find_ecap_aer(pcie_device_t *dev) {
498 int pos = PCIE_ECAP_OFFSET;
499 uint32_t header = pcie_read32(dev, pos);
500 int id = PCI_EXT_CAP_ID(header);
501 int next = PCI_EXT_CAP_NEXT(header);
506 if (id == PCI_EXT_CAP_ID_ERR)
510 if (next <= PCIE_ECAP_OFFSET)
513 header = pcie_read32(dev, next);
514 id = PCI_EXT_CAP_ID(header);
516 if (id == PCI_EXT_CAP_ID_ERR)
519 next = PCI_EXT_CAP_NEXT(header);
525 static void pcie_check_dev_status(pcie_device_t *dev, int pos) {
526 /* Read Device Status register with mask for errors only */
527 uint16_t new_status = pcie_read16(dev, pos + PCI_EXP_DEVSTA) & 0xf;
529 /* Check if anything new should be reported */
530 if (!(pcie_config.persistent && new_status) &&
531 (new_status == dev->device_status))
534 /* Report errors found in Device Status register */
535 for (int i = 0; i < pcie_base_errors_num; i++) {
536 pcie_error_t *err = pcie_base_errors + i;
537 const char *type_instance = (err->mask == PCI_EXP_DEVSTA_FED)
539 : (err->mask == PCI_EXP_DEVSTA_CED)
543 (err->mask == PCI_EXP_DEVSTA_FED) ? NOTIF_FAILURE : NOTIF_WARNING;
544 notification_t n = {.severity = severity,
546 .plugin = PCIE_ERRORS_PLUGIN,
549 if (err->mask & new_status) {
550 /* Error already reported, notify only if persistent is set */
551 if (!pcie_config.persistent && (err->mask & dev->device_status))
554 DEBUG(PCIE_ERRORS_PLUGIN ": %04x:%02x:%02x.%d: %s set", dev->domain,
555 dev->bus, dev->device, dev->function, err->desc);
556 snprintf(n.message, sizeof(n.message), "Device Status Error set: %s",
558 pcie_dispatch_notification(dev, &n, PCIE_ERROR, type_instance);
560 } else if (err->mask & dev->device_status) {
561 DEBUG(PCIE_ERRORS_PLUGIN ": %04x:%02x:%02x.%d: %s cleared", dev->domain,
562 dev->bus, dev->device, dev->function, err->desc);
563 n.severity = NOTIF_OKAY;
564 snprintf(n.message, sizeof(n.message), "Device Status Error cleared: %s",
566 pcie_dispatch_notification(dev, &n, PCIE_ERROR, type_instance);
570 dev->device_status = new_status;
573 static void pcie_check_aer(pcie_device_t *dev, int pos) {
574 /* Check for AER uncorrectable errors */
575 uint32_t errors = pcie_read32(dev, pos + PCI_ERR_UNCOR_STATUS);
577 if ((pcie_config.persistent && errors) ||
578 (errors != dev->uncorrectable_errors)) {
579 uint32_t masked = pcie_read32(dev, pos + PCI_ERR_UNCOR_MASK);
580 uint32_t severity = pcie_read32(dev, pos + PCI_ERR_UNCOR_SEVER);
581 pcie_dispatch_uncorrectable_errors(dev, errors, masked, severity);
583 dev->uncorrectable_errors = errors;
585 /* Check for AER correctable errors */
586 errors = pcie_read32(dev, pos + PCI_ERR_COR_STATUS);
587 if ((pcie_config.persistent && errors) ||
588 (errors != dev->correctable_errors)) {
589 uint32_t masked = pcie_read32(dev, pos + PCI_ERR_COR_MASK);
590 pcie_dispatch_correctable_errors(dev, errors, masked);
592 dev->correctable_errors = errors;
595 static int pcie_process_devices(llist_t *devs) {
600 for (llentry_t *e = llist_head(devs); e != NULL; e = e->next) {
601 pcie_device_t *dev = e->value;
603 if (pcie_fops.open(dev) == 0) {
604 pcie_check_dev_status(dev, dev->cap_exp);
605 if (dev->ecap_aer != -1)
606 pcie_check_aer(dev, dev->ecap_aer);
608 pcie_fops.close(dev);
610 notification_t n = {.severity = NOTIF_FAILURE,
612 .message = "Failed to read device status",
613 .plugin = PCIE_ERRORS_PLUGIN,
615 pcie_dispatch_notification(dev, &n, "", "");
623 /* This function is to be called during init to filter out no pcie devices */
624 static void pcie_preprocess_devices(llist_t *devs) {
630 for (llentry_t *e = llist_head(devs); e != NULL; e = e_next) {
631 pcie_device_t *dev = e->value;
634 if (pcie_fops.open(dev) == 0) {
635 uint16_t status = pcie_read16(dev, PCI_STATUS);
636 if (status & PCI_STATUS_CAP_LIST)
637 dev->cap_exp = pcie_find_cap_exp(dev);
639 /* Every PCIe device must have Capability Structure */
640 if (dev->cap_exp == -1) {
641 DEBUG(PCIE_ERRORS_PLUGIN ": Not PCI Express device: %04x:%02x:%02x.%d",
642 dev->domain, dev->bus, dev->device, dev->function);
645 dev->ecap_aer = pcie_find_ecap_aer(dev);
646 if (dev->ecap_aer == -1)
647 INFO(PCIE_ERRORS_PLUGIN
648 ": Device is not AER capable: %04x:%02x:%02x.%d",
649 dev->domain, dev->bus, dev->device, dev->function);
652 pcie_fops.close(dev);
654 ERROR(PCIE_ERRORS_PLUGIN ": %04x:%02x:%02x.%d: failed to open",
655 dev->domain, dev->bus, dev->device, dev->function);
662 llist_remove(devs, e);
668 static int pcie_plugin_read(__attribute__((unused)) user_data_t *ud) {
670 if (pcie_process_devices(pcie_dev_list) < 0) {
671 ERROR(PCIE_ERRORS_PLUGIN ": Failed to read devices state");
677 static void pcie_access_config(void) {
678 /* Set functions for register access to
679 * use proc or sysfs depending on config. */
680 if (pcie_config.use_sysfs) {
681 pcie_fops.list_devices = pcie_list_devices_sysfs;
682 pcie_fops.open = pcie_open_sysfs;
683 if (pcie_config.access_dir[0] == '\0')
684 sstrncpy(pcie_config.access_dir, PCIE_DEFAULT_SYSFSDIR,
685 sizeof(pcie_config.access_dir));
688 pcie_fops.list_devices = pcie_list_devices_proc;
689 pcie_fops.open = pcie_open_proc;
690 if (pcie_config.access_dir[0] == '\0')
691 sstrncpy(pcie_config.access_dir, PCIE_DEFAULT_PROCDIR,
692 sizeof(pcie_config.access_dir));
694 /* Common functions */
695 pcie_fops.close = pcie_close;
696 pcie_fops.read = pcie_read;
699 static int pcie_plugin_config(oconfig_item_t *ci) {
701 for (int i = 0; i < ci->children_num; i++) {
702 oconfig_item_t *child = ci->children + i;
705 if (strcasecmp("Source", child->key) == 0) {
706 if ((child->values_num != 1) ||
707 (child->values[0].type != OCONFIG_TYPE_STRING)) {
709 } else if (strcasecmp("proc", child->values[0].value.string) == 0) {
710 pcie_config.use_sysfs = 0;
711 } else if (strcasecmp("sysfs", child->values[0].value.string) != 0) {
712 ERROR(PCIE_ERRORS_PLUGIN ": Allowed sources are 'proc' or 'sysfs'.");
715 } else if (strcasecmp("AccessDir", child->key) == 0) {
716 status = cf_util_get_string_buffer(child, pcie_config.access_dir,
717 sizeof(pcie_config.access_dir));
718 } else if (strcasecmp("ReportMasked", child->key) == 0) {
719 status = cf_util_get_boolean(child, &pcie_config.notif_masked);
720 } else if (strcasecmp("PersistentNotifications", child->key) == 0) {
721 status = cf_util_get_boolean(child, &pcie_config.persistent);
723 ERROR(PCIE_ERRORS_PLUGIN ": Invalid configuration option \"%s\".",
725 pcie_config.config_error = 1;
730 ERROR(PCIE_ERRORS_PLUGIN ": Invalid configuration parameter \"%s\".",
732 pcie_config.config_error = 1;
740 static int pcie_shutdown(void) {
741 pcie_clear_list(pcie_dev_list);
742 pcie_dev_list = NULL;
747 static int pcie_init(void) {
748 if (pcie_config.config_error) {
749 ERROR(PCIE_ERRORS_PLUGIN
750 ": Error in configuration, failed to init plugin.");
754 pcie_access_config();
755 pcie_dev_list = llist_create();
756 if (pcie_fops.list_devices(pcie_dev_list) != 0) {
757 ERROR(PCIE_ERRORS_PLUGIN ": Failed to find devices.");
761 pcie_preprocess_devices(pcie_dev_list);
762 if (llist_size(pcie_dev_list) == 0) {
763 /* No any PCI Express devices were found on the system */
764 ERROR(PCIE_ERRORS_PLUGIN ": No PCIe devices found in %s",
765 pcie_config.access_dir);
773 void module_register(void) {
774 plugin_register_init(PCIE_ERRORS_PLUGIN, pcie_init);
775 plugin_register_complex_config(PCIE_ERRORS_PLUGIN, pcie_plugin_config);
776 plugin_register_complex_read(NULL, PCIE_ERRORS_PLUGIN, pcie_plugin_read, 0,
778 plugin_register_shutdown(PCIE_ERRORS_PLUGIN, pcie_shutdown);