From patchwork Fri Jan 6 07:02:44 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Hung X-Patchwork-Id: 134613 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 021AC1007D6 for ; Fri, 6 Jan 2012 18:02:53 +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 1Rj3pD-00070K-Qb for incoming@patchwork.ozlabs.org; Fri, 06 Jan 2012 07:02:51 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1Rj3pC-00070F-7S for fwts-devel@lists.ubuntu.com; Fri, 06 Jan 2012 07:02:50 +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 1Rj3pB-00075t-0W; Fri, 06 Jan 2012 07:02:50 +0000 From: Alex Hung To: fwts-devel@lists.ubuntu.com Subject: [PATCH] pcie: aspm: add aspm configuration check on PCIe root ports and PCIe devices. Date: Fri, 6 Jan 2012 15:02:44 +0800 Message-Id: <1325833364-15933-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/lib/include/fwts_aspm.h | 36 ++++++++++ src/lib/src/fwts_aspm.c | 152 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 186 insertions(+), 2 deletions(-) diff --git a/src/lib/include/fwts_aspm.h b/src/lib/include/fwts_aspm.h index 91437fa..389ebee 100644 --- a/src/lib/include/fwts_aspm.h +++ b/src/lib/include/fwts_aspm.h @@ -22,6 +22,42 @@ #include "fwts_acpi.h" +typedef struct pci_device { + uint8_t segment; + uint8_t bus; + uint8_t dev; + uint8_t func; + uint8_t configuration[256]; + struct pci_device *next; +} pci_device; + + +typedef 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; +} pcie_capability; int fwts_aspm_check_configuration(fwts_framework *fw); diff --git a/src/lib/src/fwts_aspm.c b/src/lib/src/fwts_aspm.c index a6ee1b7..f0d7f8e 100644 --- a/src/lib/src/fwts_aspm.c +++ b/src/lib/src/fwts_aspm.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "fwts.h" @@ -51,6 +50,154 @@ int fwts_facp_get_aspm_control(fwts_framework *fw, int *aspm) return FWTS_OK; } +int fwts_pcie_check_aspm_registers(fwts_framework *fw, const fwts_log_level level) +{ + fwts_list *lspci_output; + fwts_list_link *item; + pci_device *root = NULL, *cur = NULL, *device = NULL; + char command[PATH_MAX]; + + // Get list of PCIe devices + 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; + } + + fwts_list_foreach(item, lspci_output) { + device = (pci_device*) malloc (sizeof(pci_device)); + char *line = fwts_text_list_text(item); + char *pEnd; + + 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; + } + + // Get configuration space for each PCIe 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->configuration[reg_loc] = (uint8_t) reg_val; + reg_loc++; + } + } + } + cur = cur->next; + } + + // Check aspm settings + cur = root; + while (cur != NULL) { + pci_device *target; + pcie_capability *rp_cap, *device_cap; + + if (cur->configuration[0x0E] & 0x01) { + uint8_t rp_aspm_support, rp_aspm_cntrl, device_aspm_support, device_aspm_cntrl; + + target = root; + while (target != NULL) { + if (target->bus == cur->configuration[0x19]) + break; + target = target->next; + } + + if (target == NULL) { + cur = cur->next; + continue; + } + + rp_cap = (pcie_capability*) &cur->configuration[cur->configuration[0x34]]; + while (rp_cap->pcie_cap_id != 0x10) { + if (rp_cap->next_cap_point == 0x00) + break; + rp_cap = (pcie_capability*) &cur->configuration[rp_cap->next_cap_point]; + } + + device_cap = (pcie_capability*) &target->configuration[target->configuration[0x34]]; + while (device_cap->pcie_cap_id != 0x10) { + if (device_cap->next_cap_point == 0x00) + break; + device_cap = (pcie_capability*) &target->configuration[device_cap->next_cap_point]; + } + + // Compare aspm settings for the root port (rp_cap) vs. the device (device_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_log_info(fw, "PCIe root port (B%02Xh, D%02Xh, F%02Xh) supports L0s, but not enabled.", + cur->bus, cur->dev, cur->func); + } + + if ((rp_aspm_support & 0x02) != (rp_aspm_cntrl & 0x02)){ + fwts_log_info(fw, "PCIe root port (B%02Xh, D%02Xh, F%02Xh) supports L1, but not enabled.", + cur->bus, cur->dev, cur->func); + } + + + if ((device_aspm_support & 0x01) != (device_aspm_cntrl & 0x01)){ + fwts_log_info(fw, "PCIe device (B%02Xh, D%02Xh, F%02Xh) supports L0s, but not enabled.", + target->bus, target->dev, target->func); + } + + if ((device_aspm_support & 0x02) != (device_aspm_cntrl & 0x02)){ + fwts_log_info(fw, "PCIe device (B%02Xh, D%02Xh, F%02Xh) supports L1, but not enabled.", + target->bus, target->dev, target->func); + } + + if (rp_aspm_cntrl != device_aspm_cntrl){ + fwts_failed(fw, level, "ASPMInconsistent", + "PCIe root port has different aspm setting from PCIe device."); + fwts_log_info(fw, "PCIe root port (B%02Xh, D%02Xh, F%02Xh) has aspm = %02Xh.", + cur->bus, cur->dev, cur->func, rp_aspm_cntrl); + fwts_log_info(fw, "PCIe device (B%02Xh, D%02Xh, F%02Xh) has aspm = %02Xh.", + target->bus, target->dev, target->func, device_aspm_cntrl); + } + } + cur = cur->next; + } + + // Free memory + cur = root; + while (cur != NULL){ + device = cur->next; + free(cur); + cur = device; + } + + fwts_text_list_free(lspci_output); + + return FWTS_OK; +} + int fwts_aspm_check_configuration(fwts_framework *fw) { int ret; @@ -62,7 +209,8 @@ int fwts_aspm_check_configuration(fwts_framework *fw) return FWTS_ERROR; } + ret = fwts_pcie_check_aspm_registers(fw, LOG_LEVEL_HIGH); + return ret; } -