From patchwork Wed May 11 22:21:46 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jesse Barnes X-Patchwork-Id: 778562 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.3) with ESMTP id p4BMLxsI013420 for ; Wed, 11 May 2011 22:22:04 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756764Ab1EKWWD (ORCPT ); Wed, 11 May 2011 18:22:03 -0400 Received: from oproxy1-pub.bluehost.com ([66.147.249.253]:52666 "HELO oproxy1-pub.bluehost.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1756759Ab1EKWWB (ORCPT ); Wed, 11 May 2011 18:22:01 -0400 Received: (qmail 8639 invoked by uid 0); 11 May 2011 22:22:00 -0000 Received: from unknown (HELO box514.bluehost.com) (74.220.219.114) by cpoproxy1.bluehost.com with SMTP; 11 May 2011 22:22:00 -0000 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=virtuousgeek.org; h=Received:From:To:Cc:Subject:Date:Message-Id:X-Mailer:In-Reply-To:References:X-Identified-User; b=Y3GViKJUMuTmRXcaaPPsG1F31Z1FNKYdCLW4lpp30xLBzVunAOf3i52ps7Ff0IgzLcmoDCpDlol1UybwSJoLDi1cKn7v8kqOJcStZfjG2XI18/olN9/Z54alJuYVXnYa; Received: from c-67-161-37-189.hsd1.ca.comcast.net ([67.161.37.189] helo=jbarnes-desktop.intel.com) by box514.bluehost.com with esmtpsa (TLSv1:AES256-SHA:256) (Exim 4.69) (envelope-from ) id 1QKHn5-0007ps-N9; Wed, 11 May 2011 16:21:59 -0600 From: Jesse Barnes To: linux-pci@vger.kernel.org Cc: Matthew Wilcox , Bjorn Helgaas , Jesse Barnes Subject: [PATCH 3/3] PCI: add latency tolerance reporting enable/disable support Date: Wed, 11 May 2011 15:21:46 -0700 Message-Id: <1305152506-19578-4-git-send-email-jbarnes@virtuousgeek.org> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1305152506-19578-1-git-send-email-jbarnes@virtuousgeek.org> References: <1305152506-19578-1-git-send-email-jbarnes@virtuousgeek.org> X-Identified-User: {10642:box514.bluehost.com:virtuous:virtuousgeek.org} {sentby:smtp auth 67.161.37.189 authed with jbarnes@virtuousgeek.org} Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Wed, 11 May 2011 22:22:04 +0000 (UTC) Latency tolerance reporting allows devices to send messages to the root complex indicating their latency tolerance for snooped & unsnooped memory transactions. Add support for enabling & disabling this feature, along with a routine to set the max latencies a device should send upstream. Signed-off-by: Jesse Barnes Reviewed-by: Myron Stowe --- drivers/pci/pci.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 5 ++ include/linux/pci_regs.h | 9 +++ 3 files changed, 163 insertions(+), 0 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 01e4cab..53302cb 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1979,6 +1979,155 @@ void pci_disable_obff(struct pci_dev *dev) } EXPORT_SYMBOL(pci_disable_obff); +/** + * pci_ltr_supported - check whether a device supports LTR + * @dev: PCI device + * + * RETURNS: + * True if @dev supports latency tolerance reporting, false otherwise. + */ +bool pci_ltr_supported(struct pci_dev *dev) +{ + int pos; + u32 cap; + + if (!pci_is_pcie(dev)) + return false; + + pos = pci_pcie_cap(dev); + if (!pos) + return false; + + pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP2, &cap); + + return cap & PCI_EXP_DEVCAP2_LTR; +} +EXPORT_SYMBOL(pci_ltr_supported); + +/** + * pci_enable_ltr - enable latency tolerance reporting + * @dev: PCI device + * + * Enable LTR on @dev if possible, which means enabling it first on + * upstream ports. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int pci_enable_ltr(struct pci_dev *dev) +{ + int pos; + u16 ctrl; + int ret; + + if (!pci_ltr_supported(dev)) + return -ENOTSUPP; + + pos = pci_pcie_cap(dev); + if (!pos) + return -ENOTSUPP; + + /* Only primary function can enable/disable LTR */ + if (PCI_FUNC(dev->devfn) != 0) + return -EINVAL; + + /* Enable upstream ports first */ + if (dev->bus) { + ret = pci_enable_ltr(dev->bus->self); + if (ret) + return ret; + } + + pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl); + ctrl |= PCI_EXP_LTR_EN; + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl); + + return 0; +} +EXPORT_SYMBOL(pci_enable_ltr); + +/** + * pci_disable_ltr - disable latency tolerance reporting + * @dev: PCI device + */ +void pci_disable_ltr(struct pci_dev *dev) +{ + int pos; + u16 ctrl; + + if (!pci_ltr_supported(dev)) + return; + + pos = pci_pcie_cap(dev); + if (!pos) + return; + + /* Only primary function can enable/disable LTR */ + if (PCI_FUNC(dev->devfn) != 0) + return; + + pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl); + ctrl &= ~PCI_EXP_LTR_EN; + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl); +} +EXPORT_SYMBOL(pci_disable_ltr); + +static int __pci_ltr_scale(int *val) +{ + int scale = 0; + + while (*val > 1023) { + *val = (*val + 31) / 32; + scale++; + } + return scale; +} + +/** + * pci_set_ltr - set LTR latency values + * @dev: PCI device + * @snoop_lat_ns: snoop latency in nanoseconds + * @nosnoop_lat_ns: nosnoop latency in nanoseconds + * + * Figure out the scale and set the LTR values accordingly. + */ +int pci_set_ltr(struct pci_dev *dev, int snoop_lat_ns, int nosnoop_lat_ns) +{ + int pos, ret, snoop_scale, nosnoop_scale; + u16 val; + + if (!pci_ltr_supported(dev)) + return -ENOTSUPP; + + snoop_scale = __pci_ltr_scale(&snoop_lat_ns); + nosnoop_scale = __pci_ltr_scale(&nosnoop_lat_ns); + + if (snoop_lat_ns > PCI_LTR_VALUE_MASK || + nosnoop_lat_ns > PCI_LTR_VALUE_MASK) + return -EINVAL; + + if ((snoop_scale > (PCI_LTR_SCALE_MASK >> PCI_LTR_SCALE_SHIFT)) || + (nosnoop_scale > (PCI_LTR_SCALE_MASK >> PCI_LTR_SCALE_SHIFT))) + return -EINVAL; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR); + if (!pos) + return -ENOTSUPP; + + val = (snoop_scale << PCI_LTR_SCALE_SHIFT) | snoop_lat_ns; + ret = pci_write_config_word(dev, pos + PCI_LTR_MAX_SNOOP_LAT, val); + if (ret != 4) + return -EIO; + + val = (nosnoop_scale << PCI_LTR_SCALE_SHIFT) | nosnoop_lat_ns; + ret = pci_write_config_word(dev, pos + PCI_LTR_MAX_NOSNOOP_LAT, val); + if (ret != 4) + return -EIO; + + return 0; +} +EXPORT_SYMBOL(pci_set_ltr); + static int pci_acs_enable; /** diff --git a/include/linux/pci.h b/include/linux/pci.h index 45a035c..df4d69b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -840,6 +840,11 @@ enum pci_obff_signal_type { int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type); void pci_disable_obff(struct pci_dev *dev); +bool pci_ltr_supported(struct pci_dev *dev); +int pci_enable_ltr(struct pci_dev *dev); +void pci_disable_ltr(struct pci_dev *dev); +int pci_set_ltr(struct pci_dev *dev, int snoop_lat_ns, int nosnoop_lat_ns); + /* For use by arch with custom probe code */ void set_pcie_port_type(struct pci_dev *pdev); void set_pcie_hotplug_bridge(struct pci_dev *pdev); diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index aa42026..e884096 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -508,6 +508,7 @@ #define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ #define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ #define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ +#define PCI_EXP_DEVCAP2_LTR 0x800 /* Latency tolerance reporting */ #define PCI_EXP_OBFF_MASK 0xc0000 /* OBFF support mechanism */ #define PCI_EXP_OBFF_MSG 0x40000 /* New message signaling */ #define PCI_EXP_OBFF_WAKE 0x80000 /* Re-use WAKE# for OBFF */ @@ -515,6 +516,7 @@ #define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */ #define PCI_EXP_IDO_REQ_EN 0x100 /* ID-based ordering request enable */ #define PCI_EXP_IDO_CMP_EN 0x200 /* ID-based ordering completion enable */ +#define PCI_EXP_LTR_EN 0x400 /* Latency tolerance reporting */ #define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message type A */ #define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message type B */ #define PCI_EXP_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ @@ -535,6 +537,7 @@ #define PCI_EXT_CAP_ID_ARI 14 #define PCI_EXT_CAP_ID_ATS 15 #define PCI_EXT_CAP_ID_SRIOV 16 +#define PCI_EXT_CAP_ID_LTR 24 /* Advanced Error Reporting */ #define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ @@ -691,6 +694,12 @@ #define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ #define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ +#define PCI_LTR_MAX_SNOOP_LAT 0x4 +#define PCI_LTR_MAX_NOSNOOP_LAT 0x6 +#define PCI_LTR_VALUE_MASK 0x000003ff +#define PCI_LTR_SCALE_MASK 0x00001c00 +#define PCI_LTR_SCALE_SHIFT 10 + /* Access Control Service */ #define PCI_ACS_CAP 0x04 /* ACS Capability Register */ #define PCI_ACS_SV 0x01 /* Source Validation */