From patchwork Wed Aug 28 17:23:13 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Liu X-Patchwork-Id: 270611 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id C8A892C0085 for ; Thu, 29 Aug 2013 03:25:49 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753464Ab3H1RZs (ORCPT ); Wed, 28 Aug 2013 13:25:48 -0400 Received: from mail-pd0-f176.google.com ([209.85.192.176]:57447 "EHLO mail-pd0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753392Ab3H1RZs (ORCPT ); Wed, 28 Aug 2013 13:25:48 -0400 Received: by mail-pd0-f176.google.com with SMTP id q10so6561822pdj.35 for ; Wed, 28 Aug 2013 10:25:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=lcb3d0LOVp9enXUtPcDYf2iATLSc9J5tk9wliwmtUVk=; b=g6HagkmAX97R/zZ6wTNEcP89NDtCaKnYQbXsAye+YyWKAcvgLr9oS555o0MSzA6jmo oFJnmzvKv12puOGJlS1FDiHN2Y/+bv/pGtQKH+aH1UQWeaanHs2VFLnxddqUbd2f/eVY vnRqiHxtnZ80E53qtBnF+vZ/E4QQtyLHzFidMDPQE2PZK1M4nfxbTMN8vfkoMDqgGknL swi7B4FJFk+qMHouLmRekPjL/Wh4ib0Qggxi8NgOwqZbW2chen3X+nYAYiPmvTSXifXY V/dbof1lpcWtcLHIxmtMjCu+YsSob7c6qVgNvWNmQwMdcAuL9rXoZZPjmE+BwdfyzYNf lC2w== X-Received: by 10.68.226.234 with SMTP id rv10mr29077023pbc.1.1377710747433; Wed, 28 Aug 2013 10:25:47 -0700 (PDT) Received: from localhost.localdomain ([114.250.89.233]) by mx.google.com with ESMTPSA id py4sm32458667pbb.33.1969.12.31.16.00.00 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 28 Aug 2013 10:25:46 -0700 (PDT) From: Jiang Liu To: Bjorn Helgaas , Yuval Mintz , "jacob . e . keller @ intel . com" Cc: liuj97@gmail.com, Jiang Liu , "linux-pci @ vger . kernel . org" Subject: [PATCH v2] PCI: correctly check availability of PCIe Link Cap/Status/Control registers Date: Thu, 29 Aug 2013 01:23:13 +0800 Message-Id: <1377710593-9758-1-git-send-email-liuj97@gmail.com> X-Mailer: git-send-email 1.8.1.2 In-Reply-To: References: Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: Jiang Liu According to PCIe Base Specification 3.0, devices are guarenteed to return zero for unimplemented V2 PCI Express Capability registers. But there's no such guarantee for unimplemented V1 PCI Express Capability registers, so we need to explicitly check availability of V1 PCI Express Capability registers and return zero for unimplemented registers. Changeset 1b6b8ce2ac372e "PCI: only save/restore existent registers in the PCIe capability" introduces pcie_cap_has_lnkctl(), which assumes that PCIe root port, endpoint and legacy endpoint with 1.0 PCIe Capability implement Link Cap/Status/Control registers. On the other hand, section 7.8 of PCIe Base Spec V1.1 and V3.0 states that "The Link Capabilities, Link Status, and Link Control registers are required for all Root Ports, Switch Ports, Bridges, and Endpoints that are not Root Complex Integrated Endpoints." That means Link Capability/Status/Control registers are also available for PCIe Upstream Port, Downstream Port, PCIe-to-PCI bridge and PCI-to-PCIe bridge. So change pcie_cap_has_lnkctl() to follow PCIe specifications. Also refine pcie_cap_has_sltctl() and pcie_cap_has_rtctl() for readability. Signed-off-by: Jiang Liu Reported-by: Yuval Mintz --- drivers/pci/access.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 1cc2366..b9af3d1 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -470,6 +470,13 @@ void pci_cfg_access_unlock(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_cfg_access_unlock); +/* + * According to PCIe base spec 3.0, devices are guarenteed to return zero for + * unimplemented V2 PCI Express Capability registers. But there's no such + * guarantee for unimplemented V1 PCI Express Capability registers, so + * explicitly check availability of V1 PCI Express Capability registers + * and return zero for unimplemented registers. + */ static inline int pcie_cap_version(const struct pci_dev *dev) { return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS; @@ -484,29 +491,39 @@ static inline bool pcie_cap_has_lnkctl(const struct pci_dev *dev) { int type = pci_pcie_type(dev); - return pcie_cap_version(dev) > 1 || - type == PCI_EXP_TYPE_ROOT_PORT || - type == PCI_EXP_TYPE_ENDPOINT || - type == PCI_EXP_TYPE_LEG_END; + if (pcie_cap_version(dev) == 1) + return type == PCI_EXP_TYPE_ENDPOINT || + type == PCI_EXP_TYPE_LEG_END || + type == PCI_EXP_TYPE_ROOT_PORT || + type == PCI_EXP_TYPE_UPSTREAM || + type == PCI_EXP_TYPE_DOWNSTREAM || + type == PCI_EXP_TYPE_PCI_BRIDGE || + type == PCI_EXP_TYPE_PCIE_BRIDGE; + + return true; } static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev) { int type = pci_pcie_type(dev); - return pcie_cap_version(dev) > 1 || - type == PCI_EXP_TYPE_ROOT_PORT || - (type == PCI_EXP_TYPE_DOWNSTREAM && - pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT); + if (pcie_cap_version(dev) == 1) + return type == PCI_EXP_TYPE_ROOT_PORT || + (type == PCI_EXP_TYPE_DOWNSTREAM && + pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT); + + return true; } static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev) { int type = pci_pcie_type(dev); - return pcie_cap_version(dev) > 1 || - type == PCI_EXP_TYPE_ROOT_PORT || - type == PCI_EXP_TYPE_RC_EC; + if (pcie_cap_version(dev) == 1) + return type == PCI_EXP_TYPE_ROOT_PORT || + type == PCI_EXP_TYPE_RC_EC; + + return true; } static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)