From patchwork Mon Aug 12 16:00:04 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Warren X-Patchwork-Id: 2843102 Return-Path: X-Original-To: patchwork-linux-arm@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 ACB449F239 for ; Mon, 12 Aug 2013 16:01:01 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D2E252020C for ; Mon, 12 Aug 2013 16:00:56 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E110220189 for ; Mon, 12 Aug 2013 16:00:51 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V8uXv-0002Cg-1r; Mon, 12 Aug 2013 16:00:39 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1V8uXs-00055h-Qv; Mon, 12 Aug 2013 16:00:36 +0000 Received: from avon.wwwdotorg.org ([2001:470:1f0f:bd7::2]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V8uXp-00054w-73 for linux-arm-kernel@lists.infradead.org; Mon, 12 Aug 2013 16:00:33 +0000 Received: from severn.wwwdotorg.org (unknown [192.168.65.5]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by avon.wwwdotorg.org (Postfix) with ESMTPS id 04CEF6257; Mon, 12 Aug 2013 10:00:11 -0600 (MDT) Received: from swarren-lx1.nvidia.com (localhost [127.0.0.1]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by severn.wwwdotorg.org (Postfix) with ESMTPSA id 9AF58E4622; Mon, 12 Aug 2013 10:00:10 -0600 (MDT) From: Stephen Warren To: Stephen Warren Subject: [PATCH V4] ARM: tegra: disable LP2 cpuidle state if PCIe is enabled Date: Mon, 12 Aug 2013 10:00:04 -0600 Message-Id: <1376323204-25952-1-git-send-email-swarren@wwwdotorg.org> X-Mailer: git-send-email 1.8.1.5 X-NVConfidentiality: public X-Virus-Scanned: clamav-milter 0.97.8 at avon.wwwdotorg.org X-Virus-Status: Clean X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130812_120033_458167_6B9331BE X-CRM114-Status: GOOD ( 20.68 ) X-Spam-Score: -4.7 (----) Cc: linux-tegra@vger.kernel.org, linux-pci@vger.kernel.org, Thierry Reding , Stephen Warren , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-7.0 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, 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: Stephen Warren Tegra20 HW appears to have a bug such that PCIe device interrupts, whether they are legacy IRQs or MSI, are lost when LP2 is enabled. To work around this, simply disable LP2 if any PCIe devices with interrupts are present. Detect this via the IRQ domain map operation. This is slightly over-conservative; if a device with an interrupt is present but the driver does not actually use them, LP2 will still be disabled. However, this is a reasonable trade-off which enables a simpler workaround. Signed-off-by: Stephen Warren Tested-by: Thierry Reding Acked-by: Thierry Reding --- v4: Add missing tegra-cpuidle.h, re-write commit description. Add acks. v3: Only disable LP2 if a PCIe device that requests an interrupt is actually present. This prevents the loss of power-saving when the WAR isn't required. --- arch/arm/mach-tegra/cpuidle-tegra20.c | 12 ++++++++++++ arch/arm/mach-tegra/cpuidle.c | 10 ++++++++++ arch/arm/mach-tegra/cpuidle.h | 1 + drivers/pci/host/pci-tegra.c | 5 +++++ include/linux/tegra-cpuidle.h | 19 +++++++++++++++++++ 5 files changed, 47 insertions(+) create mode 100644 include/linux/tegra-cpuidle.h diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index 706aa42..b82dcae 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -211,6 +211,18 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, } #endif +/* + * Tegra20 HW appears to have a bug such that PCIe device interrupts, whether + * they are legacy IRQs or MSI, are lost when LP2 is enabled. To work around + * this, simply disable LP2 if the PCI driver and DT node are both enabled. + */ +void tegra20_cpuidle_pcie_irqs_in_use(void) +{ + pr_info_once( + "Disabling cpuidle LP2 state, since PCIe IRQs are in use\n"); + tegra_idle_driver.states[1].disabled = true; +} + int __init tegra20_cpuidle_init(void) { return cpuidle_register(&tegra_idle_driver, cpu_possible_mask); diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c index e85973c..0961dfc 100644 --- a/arch/arm/mach-tegra/cpuidle.c +++ b/arch/arm/mach-tegra/cpuidle.c @@ -44,3 +44,13 @@ void __init tegra_cpuidle_init(void) break; } } + +void tegra_cpuidle_pcie_irqs_in_use(void) +{ + switch (tegra_chip_id) { + case TEGRA20: + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) + tegra20_cpuidle_pcie_irqs_in_use(); + break; + } +} diff --git a/arch/arm/mach-tegra/cpuidle.h b/arch/arm/mach-tegra/cpuidle.h index 9ec2c1a..c017dab 100644 --- a/arch/arm/mach-tegra/cpuidle.h +++ b/arch/arm/mach-tegra/cpuidle.h @@ -19,6 +19,7 @@ #ifdef CONFIG_CPU_IDLE int tegra20_cpuidle_init(void); +void tegra20_cpuidle_pcie_irqs_in_use(void); int tegra30_cpuidle_init(void); int tegra114_cpuidle_init(void); void tegra_cpuidle_init(void); diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index ad95c40..7356741 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -636,6 +637,8 @@ static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) { struct tegra_pcie *pcie = sys_to_pcie(pdev->bus->sysdata); + tegra_cpuidle_pcie_irqs_in_use(); + return pcie->irq; } @@ -1221,6 +1224,8 @@ static int tegra_msi_map(struct irq_domain *domain, unsigned int irq, irq_set_chip_data(irq, domain->host_data); set_irq_flags(irq, IRQF_VALID); + tegra_cpuidle_pcie_irqs_in_use(); + return 0; } diff --git a/include/linux/tegra-cpuidle.h b/include/linux/tegra-cpuidle.h new file mode 100644 index 0000000..dda3647 --- /dev/null +++ b/include/linux/tegra-cpuidle.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __LINUX_TEGRA_CPUIDLE_H__ +#define __LINUX_TEGRA_CPUIDLE_H__ + +void tegra_cpuidle_pcie_irqs_in_use(void); + +#endif