From patchwork Wed Feb 8 09:29:22 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Hung X-Patchwork-Id: 140082 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id 6DEA1B6EE7 for ; Wed, 8 Feb 2012 20:29:34 +1100 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1Rv3qE-00038M-Ii for incoming@patchwork.ozlabs.org; Wed, 08 Feb 2012 09:29:30 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1Rv3qB-00038F-NN for fwts-devel@lists.ubuntu.com; Wed, 08 Feb 2012 09:29:27 +0000 Received: from [210.242.151.101] (helo=canonical.com) by youngberry.canonical.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1Rv3qA-0000aR-Gy; Wed, 08 Feb 2012 09:29:27 +0000 From: Alex Hung To: fwts-devel@lists.ubuntu.com Subject: [PATCH] pcie: add pcie aspm registers check on root port and device. Date: Wed, 8 Feb 2012 17:29:22 +0800 Message-Id: <1328693362-31128-1-git-send-email-alex.hung@canonical.com> X-Mailer: git-send-email 1.7.5.4 X-BeenThere: fwts-devel@lists.ubuntu.com X-Mailman-Version: 2.1.13 Precedence: list List-Id: Firmware Test Suite Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: fwts-devel-bounces@lists.ubuntu.com Errors-To: fwts-devel-bounces@lists.ubuntu.com Signed-off-by: Alex Hung --- src/pci/aspm/aspm.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 216 insertions(+), 3 deletions(-) diff --git a/src/pci/aspm/aspm.c b/src/pci/aspm/aspm.c index db82718..9ed7fc0 100644 --- a/src/pci/aspm/aspm.c +++ b/src/pci/aspm/aspm.c @@ -26,10 +26,45 @@ #include #include #include -#include - #include "fwts.h" +struct pci_device { + uint8_t segment; + uint8_t bus; + uint8_t dev; + uint8_t func; + uint8_t config[256]; + struct pci_device *next; +}; + + +struct pcie_capability { + uint8_t pcie_cap_id; + uint8_t next_cap_point; + uint16_t pcie_cap_reg; + uint32_t device_cap; + uint16_t device_contrl; + uint16_t device_status; + uint32_t link_cap; + uint16_t link_contrl; + uint16_t link_status; + uint32_t slot_cap; + uint16_t slot_contrl; + uint16_t slot_status; + uint16_t root_contrl; + uint16_t root_cap; + uint32_t root_status; + uint32_t device_cap2; + uint16_t device_contrl2; + uint16_t device_status2; + uint32_t link_cap2; + uint16_t link_contrl2; + uint16_t link_status2; + uint32_t slot_cap2; + uint16_t slot_contrl2; + uint16_t slot_status2; +}; + static int facp_get_aspm_control(fwts_framework *fw, int *aspm) { fwts_acpi_table_info *table; @@ -51,6 +86,174 @@ static int facp_get_aspm_control(fwts_framework *fw, int *aspm) return FWTS_OK; } +int pcie_compare_rp_dev_aspm_registers(fwts_framework *fw, + struct pci_device *rp, + struct pci_device *dev) +{ + struct pcie_capability *rp_cap, *device_cap; + uint8_t rp_aspm_support, rp_aspm_cntrl; + uint8_t device_aspm_support, device_aspm_cntrl; + uint8_t next_cap; + int ret = FWTS_OK; + + next_cap = rp->config[0x34]; + rp_cap = (struct pcie_capability *) &rp->config[next_cap]; + while (rp_cap->pcie_cap_id != 0x10) { + if (rp_cap->next_cap_point == 0x00) + break; + next_cap = rp_cap->next_cap_point; + rp_cap = (struct pcie_capability *) &rp->config[next_cap]; + } + + next_cap = dev->config[0x34]; + device_cap = (struct pcie_capability *) &dev->config[next_cap]; + while (device_cap->pcie_cap_id != 0x10) { + if (device_cap->next_cap_point == 0x00) + break; + next_cap = device_cap->next_cap_point; + device_cap = (struct pcie_capability *) &dev->config[next_cap]; + } + + rp_aspm_support = (rp_cap->link_cap & 0x0c00) >> 10; + rp_aspm_cntrl = (rp_cap->link_contrl & 0x03); + device_aspm_support = (device_cap->link_cap & 0x0c00) >> 10; + device_aspm_cntrl = (device_cap->link_contrl & 0x03); + + if ((rp_aspm_support & 0x01) != (rp_aspm_cntrl & 0x01)) { + fwts_warning(fw, "RP %02Xh:%02Xh.%02Xh L0s not enabled.", + rp->bus, rp->dev, rp->func); + } + + if ((rp_aspm_support & 0x02) != (rp_aspm_cntrl & 0x02)) { + fwts_warning(fw, "RP %02Xh:%02Xh.%02Xh L1 not enabled.", + rp->bus, rp->dev, rp->func); + } + + + if ((device_aspm_support & 0x01) != (device_aspm_cntrl & 0x01)) { + fwts_warning(fw, "Device %02Xh:%02Xh.%02Xh L0s not enabled.", + dev->bus, dev->dev, dev->func); + } + + if ((device_aspm_support & 0x02) != (device_aspm_cntrl & 0x02)) { + fwts_warning(fw, "Device %02Xh:%02Xh.%02Xh L1 not enabled.", + dev->bus, dev->dev, dev->func); + } + + if (rp_aspm_cntrl != device_aspm_cntrl) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "PCIEASPM_UNMATCHED", + "PCIE aspm setting was not matched."); + fwts_log_error(fw, "RP %02Xh:%02Xh.%02Xh has aspm = %02Xh." + , rp->bus, rp->dev, rp->func, rp_aspm_cntrl); + fwts_log_error(fw, "Device %02Xh:%02Xh.%02Xh has aspm = %02Xh.", + dev->bus, dev->dev, dev->func, device_aspm_cntrl); + } else { + fwts_passed(fw, "PCIE aspm setting matched was matched."); + } + + return ret; +} + +int pcie_check_aspm_registers(fwts_framework *fw, + const fwts_log_level level) +{ + fwts_list *lspci_output; + fwts_list_link *item; + struct pci_device *root = NULL, *cur = NULL, *device = NULL; + char command[PATH_MAX]; + int ret = FWTS_OK; + + snprintf(command, sizeof(command), "%s", fw->lspci); + + if (fwts_pipe_exec(command, &lspci_output) == FWTS_EXEC_ERROR) { + fwts_log_warning(fw, "Could not execute %s", command); + return FWTS_EXEC_ERROR; + } + + /* Get the list of pci devices and their configuration */ + fwts_list_foreach(item, lspci_output) { + char *line = fwts_text_list_text(item); + char *pEnd; + + device = (struct pci_device *) malloc(sizeof(*device)); + if (device == NULL) + return FWTS_ERROR; + + device->bus = strtol(line, &pEnd, 16); + device->dev = strtol(pEnd + 1, &pEnd, 16); + device->func = strtol(pEnd + 1, &pEnd, 16); + + if (device->bus == 0 && device->dev == 0 && device->func == 0) + root = device; + else + cur->next = device; + + cur = device; + } + + cur = root; + while (cur != NULL) { + int reg_loc = 0, reg_val = 0; + int i; + + snprintf(command, sizeof(command), "%s -s %02X:%02X.%02X -xxx", + fw->lspci, cur->bus, cur->dev, cur->func); + if (fwts_pipe_exec(command, &lspci_output) == FWTS_EXEC_ERROR) { + fwts_log_warning(fw, "Could not execute %s", command); + return FWTS_EXEC_ERROR; + } + + fwts_list_foreach(item, lspci_output) { + char *line = fwts_text_list_text(item); + char *pEnd; + + if (line[3] == ' ') { + reg_val = strtol(line, &pEnd, 16); + for (i = 0; i < 16; i++) { + reg_val = strtol(pEnd + 1, &pEnd, 16); + cur->config[reg_loc] = reg_val; + reg_loc++; + } + } + } + cur = cur->next; + } + + /* Check aspm registers from the list of pci devices */ + cur = root; + while (cur != NULL) { + struct pci_device *target; + + if (cur->config[0x0E] & 0x01) { + + target = root; + while (target != NULL) { + if (target->bus == cur->config[0x19]) + break; + target = target->next; + } + if (target == NULL) { + cur = cur->next; + continue; + } + + pcie_compare_rp_dev_aspm_registers(fw, cur, target); + } + cur = cur->next; + } + + cur = root; + while (cur != NULL) { + device = cur->next; + free(cur); + cur = device; + } + + fwts_text_list_free(lspci_output); + + return ret; +} + static int aspm_check_configuration(fwts_framework *fw) { int ret; @@ -65,8 +268,18 @@ static int aspm_check_configuration(fwts_framework *fw) return ret; } +static int aspm_pcie_register_configuration(fwts_framework *fw) +{ + int ret; + + ret = pcie_check_aspm_registers(fw, LOG_LEVEL_HIGH); + + return ret; +} + static fwts_framework_minor_test aspm_tests[] = { - { aspm_check_configuration, "PCIe ASPM configuration test." }, + { aspm_check_configuration, "PCIe ASPM ACPI test." }, + { aspm_pcie_register_configuration, "PCIe ASPM registers test." }, { NULL, NULL } };