ACK: [PATCH 1/4] opal: pci_info: Add OPAL PCI Info validation
Colin Ian King
colin.king at canonical.com
Fri Nov 11 09:44:36 UTC 2016
On 11/11/16 04:01, Deb McLemore wrote:
> Check that the PCI devices are properly setup in the device tree.
>
> Signed-off-by: Deb McLemore <debmc at linux.vnet.ibm.com>
> ---
> configure.ac | 18 ++-
> src/Makefile.am | 8 ++
> src/opal/pci_info.c | 379 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 400 insertions(+), 5 deletions(-)
> create mode 100644 src/opal/pci_info.c
>
> diff --git a/configure.ac b/configure.ac
> index 042d45b..2ef4f4f 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -65,14 +65,22 @@
> AC_CHECK_HEADERS([gio/gio.h])
> AC_CHECK_HEADERS([asm/opal-prd.h])
> AC_CHECK_HEADERS([mtd/mtd-abi.h])
> - AM_CONDITIONAL([HAVE_ASM_OPAL_PRD_H], [test "x$ac_cv_header_asm_opal_prd_h" = "xyes"])
> - AM_CONDITIONAL([HAVE_MTD_ABI_H], [test "x$ac_cv_header_mtd_abi_h" = "xyes"])
> + AC_CHECK_HEADERS([pci/pci.h])
> + AM_CONDITIONAL([HAVE_ASM_OPAL_PRD_H],
> + [test "x$ac_cv_header_asm_opal_prd_h" = "xyes"])
> + AM_CONDITIONAL([HAVE_MTD_ABI_H],
> + [test "x$ac_cv_header_mtd_abi_h" = "xyes"])
> + AM_CONDITIONAL([HAVE_PCI_PCI_H],
> + [test "x$ac_cv_header_pci_pci_h" = "xyes"])
> #AC_CHECK_LIB(pcre, pcre_compile)
> AC_SEARCH_LIBS([fdt_check_header], [fdt], [
> - AC_DEFINE([HAVE_LIBFDT], [1], [Define if we have libfdt])
> - ])
> + AC_DEFINE([HAVE_LIBFDT], [1], [Define if we have libfdt])])
> AM_CONDITIONAL([HAVE_LIBFDT],
> - [test "x$ac_cv_search_fdt_check_header" != "xno"])
> + [test "x$ac_cv_search_fdt_check_header" != "xno"])
> + AC_SEARCH_LIBS([pci_alloc], [pci], [
> + AC_DEFINE([HAVE_LIBPCI], [1], [Define if we have libpci])])
> + AM_CONDITIONAL([HAVE_LIBPCI],
> + [test "x$ac_cv_search_pci_alloc" != "xno"])
> AC_FUNC_MALLOC
> AC_FUNC_FORK
> AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK
> diff --git a/src/Makefile.am b/src/Makefile.am
> index eeef7a8..b2604e3 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -26,6 +26,13 @@ dt_tests = \
> devicetree/dt_sysinfo/dt_sysinfo.c
> endif
>
> +if HAVE_LIBFDT
> +if HAVE_LIBPCI
> +pci_tests = \
> + opal/pci_info.c
> +endif
> +endif
> +
> #
> # fwts main + tests
> #
> @@ -150,6 +157,7 @@ fwts_SOURCES = main.c \
> uefi/uefirtauthvar/uefirtauthvar.c \
> uefi/esrtdump/esrtdump.c \
> uefi/esrt/esrt.c \
> + $(pci_tests) \
> $(dt_tests)
>
> fwts_LDFLAGS = -lm `pkg-config --libs glib-2.0 gio-2.0`
> diff --git a/src/opal/pci_info.c b/src/opal/pci_info.c
> new file mode 100644
> index 0000000..fa92c44
> --- /dev/null
> +++ b/src/opal/pci_info.c
> @@ -0,0 +1,379 @@
> +/*
> + * Copyright (C) 2010-2016 Canonical
> + * Some of this work - Copyright (C) 2016 IBM
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +
> +#define _GNU_SOURCE /* added for asprintf */
> +#include <fcntl.h>
> +#include <sys/ioctl.h>
> +#include <stdio.h>
> +
> +#include "fwts.h"
> +
> +#include <pci/pci.h>
> +
> +#include <libfdt.h>
> +
> +struct pci_access *pcia = NULL;
> +struct pci_dev *dev;
> +
> +static int pci_get_dev_info(fwts_framework *fw,
> + char *property,
> + char *pci_dt_path,
> + char *sys_slot,
> + const char *pci_slot_buf,
> + char *pci_domain)
> +{
> +
> + unsigned int pin;
> + char namebuf[PATH_MAX], *device_name;
> + char vendorbuf[PATH_MAX], *vendor_name;
> + char classbuf[PATH_MAX], *class_name;
> + char *tmp_pci_domain;
> + bool found = false;
> +
> + for (dev=pcia->devices; dev; dev=dev->next)
> + {
> + pci_fill_info(dev,
> + PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
> + pin = pci_read_byte(dev, PCI_INTERRUPT_PIN);
> + if (asprintf(&tmp_pci_domain,
> + "%04x:%02x:%02x.%d",
> + dev->domain,
> + dev->bus,
> + dev->dev,
> + dev->func) < 0 ) {
> + fwts_log_nl(fw);
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "OPAL PCI Info",
> + "Internal"
> + " processing problem"
> + " at tmp_pci_domain,"
> + " please check the system"
> + " for setup issues.");
> + free(tmp_pci_domain);
> + return FWTS_ERROR;
> + } else {
> + if (strstr(pci_domain, tmp_pci_domain)) {
> + found = true;
> + device_name = pci_lookup_name(pcia,
> + namebuf,
> + sizeof(namebuf),
> + PCI_LOOKUP_DEVICE,
> + dev->vendor_id,
> + dev->device_id);
> + vendor_name = pci_lookup_name(pcia,
> + vendorbuf,
> + sizeof(vendorbuf),
> + PCI_LOOKUP_VENDOR,
> + dev->vendor_id,
> + dev->device_id);
> + class_name = pci_lookup_name(pcia,
> + classbuf,
> + sizeof(classbuf),
> + PCI_LOOKUP_CLASS,
> + dev->device_class);
> + fwts_advice(fw,
> + "Property \"%s\" of \"%s\" from device"
> + " tree node %s%s is \"%s\","
> + " device_name=\"%s\", device_id=%04x,"
> + " vendor_name=\"%s\", vendor_id=%04x,"
> + " device_class_name=\"%s\","
> + " device_class=%04x,"
> + " irq=%d (pin %d), base0=%lx. Please"
> + " verify the data matches what you"
> + " desire.",
> + property, sys_slot, DT_FS_PATH,
> + pci_dt_path, pci_slot_buf,
> + device_name, dev->device_id,
> + vendor_name, dev->vendor_id,
> + class_name, dev->device_class,
> + dev->irq, pin,
> + (long) dev->base_addr[0]);
> + fwts_infoonly(fw);
> + }
> + free(tmp_pci_domain);
> + }
> + }
> + if (!found) {
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "OPAL PCI Info",
> + "A match was not found"
> + " for \"%s\" from the libpci-dev tools."
> + " Check the \"lspci\" output to review"
> + " if there is a setup issue."
> + " If the \"lscpi\" output looks good"
> + " then report a bug in the libpci-dev tools.",
> + pci_domain);
> + fwts_advice(fw,
> + "Property \"%s\" of \"%s\" from device"
> + " tree node %s%s is \"%s\". Please"
> + " verify the data matches what you desire.",
> + property, sys_slot, DT_FS_PATH,
> + pci_dt_path, pci_slot_buf);
> + fwts_infoonly(fw);
> + return FWTS_ERROR;
> + }
> + return FWTS_OK;
> +}
> +
> +static int pci_get_slot_info(fwts_framework *fw,
> + char *property,
> + char *pci_dt_path,
> + char *sys_slot,
> + char *pci_domain)
> +{
> + int node, pci_slot_len;
> + const char *pci_slot_buf;
> +
> + node = fdt_path_offset(fw->fdt,
> + pci_dt_path);
> + if (node >= 0) {
> + pci_slot_buf = fdt_getprop(fw->fdt, node,
> + property, &pci_slot_len);
> + if (pci_slot_buf) {
> + fwts_log_nl(fw);
> + if (pci_get_dev_info(fw,
> + property,
> + pci_dt_path,
> + sys_slot,
> + pci_slot_buf,
> + pci_domain)) {
> + return FWTS_ERROR;
> + }
> + } else {
> + fwts_log_nl(fw);
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "OPAL PCI Info",
> + "Internal processing problem"
> + " at pci_slot_buf for \"%s\""
> + " for \"%s%s\", please"
> + " check the system for setup"
> + " issues.",
> + property,
> + DT_FS_PATH,
> + pci_dt_path);
> + fwts_log_nl(fw);
> + return FWTS_ERROR;
> + }
> + } else {
> + fwts_log_nl(fw);
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "OPAL PCI Info",
> + "The OPAL device tree node is not able"
> + " to be detected so skipping the pci_info"
> + " test. There may be tools missing such as"
> + " libfdt-dev or dtc, check that the packages"
> + " are installed and re-build if needed."
> + " If this condition persists try running the"
> + " dt_base test to further diagnose. If dt_base"
> + " test is not available this is probably a"
> + " setup problem. Validation of the PCI"
> + " devices in the device tree \"%s\" cannot"
> + " be run.",
> + DT_FS_PATH);
> + fwts_log_nl(fw);
> + return FWTS_ERROR;
> + }
> + return FWTS_OK;
> +}
> +
> +static int get_linux_pci_devices(fwts_framework *fw)
> +{
> + int count, i, failures = 0;
> + ssize_t bytes = 0;
> + struct dirent **namelist;
> + bool found = false;
> +
> + count = scandir(DT_LINUX_PCI_DEVICES, &namelist, NULL, alphasort);
> + if (count < 0) {
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "OPAL PCI Info",
> + "Scan for PCI devices in '%s' is unable to find any "
> + "candidates. Check the installation "
> + "for the PCI device config for missing nodes"
> + " in the device tree if you expect PCI devices.",
> + DT_LINUX_PCI_DEVICES);
> + return FWTS_ERROR;
> + }
> +
> + fwts_log_nl(fw);
> + fwts_log_info(fw, "STARTING checks of PCI devices");
> +
> + for (i = 0; i < count; i++) {
> + struct dirent *dirent;
> + char *pci_slot;
> + char *of_node_link;
> + char of_node_path[PATH_MAX+1];
> + char *sys_slot = NULL;
> + int rc = 0;
> +
> + memset(of_node_path, 0, sizeof(of_node_path));
> +
> + dirent = namelist[i];
> +
> + if (dirent->d_name[0] == '.' ||
> + asprintf(&pci_slot,
> + "%s",
> + dirent->d_name) < 0) {
> + /* asprintf must be last condition so when it */
> + /* evaluates pci_slot gets allocated */
> + free(namelist[i]);
> + continue;
> + }
> +
> + if (strstr(pci_slot, "00:00.0")) {
> + found = true;
> + if (asprintf(&of_node_link,
> + "%s/%s/of_node",
> + DT_LINUX_PCI_DEVICES,
> + pci_slot) < 0 ) {
> + fwts_log_nl(fw);
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "OPAL PCI Info",
> + "Internal"
> + " processing problem at"
> + " pci_slot \"%s\", please"
> + " check the system for"
> + " setup issues.",
> + pci_slot);
> + failures ++;
> + free(pci_slot);
> + free(namelist[i]);
> + continue;
> + }
> +
> + bytes = readlink(of_node_link,
> + of_node_path,
> + sizeof(of_node_path) -1);
> + if (bytes < 0) {
> + fwts_log_nl(fw);
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "OPAL PCI Info",
> + "Internal"
> + " processing problem at "
> + "readlink of_node_link \"%s\","
> + " please check the system"
> + " for setup issues.",
> + of_node_link);
> + failures ++;
> + free(of_node_link);
> + free(pci_slot);
> + free(namelist[i]);
> + bytes = 0;
> + continue;
> + }
> + of_node_path[bytes] = '\0';
> + sys_slot = strstr(of_node_path, "/pciex");
> + if (sys_slot) {
> + rc = pci_get_slot_info(fw,
> + DT_PROPERTY_OPAL_PCI_SLOT,
> + sys_slot,
> + of_node_link,
> + pci_slot);
> + if (rc == FWTS_ERROR) {
> + failures ++;
> + }
> + } else {
> + fwts_log_nl(fw);
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "OPAL PCI Info",
> + "Internal"
> + " processing problem at strstr"
> + " of_node_path of \"%s\", "
> + "please check the system"
> + " for setup issues.",
> + of_node_path);
> + failures ++;
> + free(of_node_link);
> + free(pci_slot);
> + free(namelist[i]);
> + continue;
> +
> + }
> + free(of_node_link);
> + }
> + free(pci_slot);
> + free(namelist[i]);
> + }
> + free(namelist);
> +
> + fwts_log_nl(fw);
> + fwts_log_info(fw, "ENDING checks of PCI devices");
> + fwts_log_nl(fw);
> +
> + if (!found) {
> + failures ++;
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "OPAL PCI Info",
> + "No root PCI devices (xxxx:00:00.0) were found"
> + " in \"%s\". Check the system for setup"
> + " issues.",
> + DT_LINUX_PCI_DEVICES);
> + }
> +
> + if (failures) {
> + return FWTS_ERROR;
> + } else {
> + return FWTS_OK;
> + }
> +}
> +
> +static int pci_info_test1(fwts_framework *fw)
> +{
> +
> + pcia = pci_alloc();
> + pci_init(pcia);
> + pci_scan_bus(pcia);
> +
> + if (!get_linux_pci_devices(fw)) {
> + pci_cleanup(pcia);
> + return FWTS_OK;
> + } else {
> + pci_cleanup(pcia);
> + return FWTS_ERROR;
> + }
> +}
> +
> +static int pci_info_init(fwts_framework *fw)
> +{
> + if (fw->firmware_type != FWTS_FIRMWARE_OPAL) {
> + fwts_skipped(fw,
> + "The firmware type detected was not set"
> + " to OPAL so skipping the OPAL PCI Info"
> + " checks.");
> + return FWTS_SKIP;
> + } else {
> + return FWTS_OK;
> + }
> +}
> +
> +static fwts_framework_minor_test pci_info_tests[] = {
> + { pci_info_test1, "OPAL PCI Info" },
> + { NULL, NULL }
> +};
> +
> +static fwts_framework_ops pci_info_ops = {
> + .description = "OPAL PCI Info",
> + .init = pci_info_init,
> + .minor_tests = pci_info_tests
> +};
> +
> +FWTS_REGISTER_FEATURES("pci_info", &pci_info_ops, FWTS_TEST_ANYTIME,
> + FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV,
> + FWTS_FW_FEATURE_DEVICETREE);
>
Thanks Deb!
Acked-by: Colin Ian King <colin.king at canonical.com>
More information about the fwts-devel
mailing list