From patchwork Wed Jul 31 09:59:32 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Kirsher, Jeffrey T" X-Patchwork-Id: 2836207 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Original-To: patchwork-linux-pci@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 63E5C9F4D4 for ; Wed, 31 Jul 2013 10:00:20 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2D22C20326 for ; Wed, 31 Jul 2013 10:00:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E6B9020319 for ; Wed, 31 Jul 2013 10:00:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759430Ab3GaKAO (ORCPT ); Wed, 31 Jul 2013 06:00:14 -0400 Received: from mga14.intel.com ([143.182.124.37]:59620 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1759242Ab3GaJ7r (ORCPT ); Wed, 31 Jul 2013 05:59:47 -0400 Received: from azsmga001.ch.intel.com ([10.2.17.19]) by azsmga102.ch.intel.com with ESMTP; 31 Jul 2013 02:59:46 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.89,786,1367996400"; d="scan'208";a="339470125" Received: from unknown (HELO jtkirshe-mobl.amr.corp.intel.com) ([10.255.13.204]) by azsmga001.ch.intel.com with ESMTP; 31 Jul 2013 02:59:45 -0700 From: Jeff Kirsher To: davem@davemloft.net, bhelgaas@google.com Cc: Jacob Keller , netdev@vger.kernel.org, gospo@redhat.com, sassmann@redhat.com, linux-pci@vger.kernel.org, Jeff Kirsher Subject: [net-next v2 10/15] PCI: Add function to obtain minimum link width and speed Date: Wed, 31 Jul 2013 02:59:32 -0700 Message-Id: <1375264777-13595-11-git-send-email-jeffrey.t.kirsher@intel.com> X-Mailer: git-send-email 1.7.11.7 In-Reply-To: <1375264777-13595-1-git-send-email-jeffrey.t.kirsher@intel.com> References: <1375264777-13595-1-git-send-email-jeffrey.t.kirsher@intel.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Spam-Status: No, score=-8.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jacob Keller A PCI Express device can potentially report a link width and speed which it will not properly fulfill due to being plugged into a slower link higher in the chain. This function walks up the PCI bus chain and calculates the minimum link width and speed of this entire chain. This can be useful to enable a device to determine if it has enough bandwidth for optimum functionality. Signed-off-by: Jacob Keller Tested-by: Phil Schmitt Acked-by: Bjorn Helgaas Signed-off-by: Jeff Kirsher --- drivers/pci/pci.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 2 ++ 2 files changed, 45 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e37fea6..c71e78c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3579,6 +3579,49 @@ int pcie_set_mps(struct pci_dev *dev, int mps) } /** + * pcie_get_minimum_link - determine minimum link settings of a PCI device + * @dev: PCI device to query + * @speed: storage for minimum speed + * @width: storage for minimum width + * + * This function will walk up the PCI device chain and determine the minimum + * link width and speed of the device. + */ +int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed, + enum pcie_link_width *width) +{ + int ret; + + *speed = PCI_SPEED_UNKNOWN; + *width = PCIE_LNK_WIDTH_UNKNOWN; + + while (dev) { + u16 lnksta; + enum pci_bus_speed next_speed; + enum pcie_link_width next_width; + + ret = pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); + if (ret) + return ret; + + next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS]; + next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >> + PCI_EXP_LNKSTA_NLW_SHIFT; + + if (next_speed < *speed) + *speed = next_speed; + + if (next_width < *width) + *width = next_width; + + dev = dev->bus->self; + } + + return 0; +} +EXPORT_SYMBOL(pcie_get_minimum_link); + +/** * pci_select_bars - Make BAR mask from the type of resource * @dev: the PCI device for which BAR mask is made * @flags: resource type mask to be selected diff --git a/include/linux/pci.h b/include/linux/pci.h index a0bf22d..2edbee6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -934,6 +934,8 @@ int pcie_get_readrq(struct pci_dev *dev); int pcie_set_readrq(struct pci_dev *dev, int rq); int pcie_get_mps(struct pci_dev *dev); int pcie_set_mps(struct pci_dev *dev, int mps); +int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed, + enum pcie_link_width *width); int __pci_reset_function(struct pci_dev *dev); int __pci_reset_function_locked(struct pci_dev *dev); int pci_reset_function(struct pci_dev *dev);