aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra20.c12
-rw-r--r--arch/arm/mach-tegra/cpuidle.c10
-rw-r--r--arch/arm/mach-tegra/cpuidle.h1
-rw-r--r--drivers/pci/host/pci-tegra.c5
-rw-r--r--include/linux/tegra-cpuidle.h19
5 files changed, 47 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c
index 706aa4215c36..b82dcaee2ef4 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,
211} 211}
212#endif 212#endif
213 213
214/*
215 * Tegra20 HW appears to have a bug such that PCIe device interrupts, whether
216 * they are legacy IRQs or MSI, are lost when LP2 is enabled. To work around
217 * this, simply disable LP2 if the PCI driver and DT node are both enabled.
218 */
219void tegra20_cpuidle_pcie_irqs_in_use(void)
220{
221 pr_info_once(
222 "Disabling cpuidle LP2 state, since PCIe IRQs are in use\n");
223 tegra_idle_driver.states[1].disabled = true;
224}
225
214int __init tegra20_cpuidle_init(void) 226int __init tegra20_cpuidle_init(void)
215{ 227{
216 return cpuidle_register(&tegra_idle_driver, cpu_possible_mask); 228 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 e85973cef037..0961dfcf83a4 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)
44 break; 44 break;
45 } 45 }
46} 46}
47
48void tegra_cpuidle_pcie_irqs_in_use(void)
49{
50 switch (tegra_chip_id) {
51 case TEGRA20:
52 if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
53 tegra20_cpuidle_pcie_irqs_in_use();
54 break;
55 }
56}
diff --git a/arch/arm/mach-tegra/cpuidle.h b/arch/arm/mach-tegra/cpuidle.h
index 9ec2c1ab0fa4..c017dab60ffa 100644
--- a/arch/arm/mach-tegra/cpuidle.h
+++ b/arch/arm/mach-tegra/cpuidle.h
@@ -19,6 +19,7 @@
19 19
20#ifdef CONFIG_CPU_IDLE 20#ifdef CONFIG_CPU_IDLE
21int tegra20_cpuidle_init(void); 21int tegra20_cpuidle_init(void);
22void tegra20_cpuidle_pcie_irqs_in_use(void);
22int tegra30_cpuidle_init(void); 23int tegra30_cpuidle_init(void);
23int tegra114_cpuidle_init(void); 24int tegra114_cpuidle_init(void);
24void tegra_cpuidle_init(void); 25void tegra_cpuidle_init(void);
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index ad95c406a6d0..7356741de36b 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -41,6 +41,7 @@
41#include <linux/platform_device.h> 41#include <linux/platform_device.h>
42#include <linux/sizes.h> 42#include <linux/sizes.h>
43#include <linux/slab.h> 43#include <linux/slab.h>
44#include <linux/tegra-cpuidle.h>
44#include <linux/tegra-powergate.h> 45#include <linux/tegra-powergate.h>
45#include <linux/vmalloc.h> 46#include <linux/vmalloc.h>
46#include <linux/regulator/consumer.h> 47#include <linux/regulator/consumer.h>
@@ -636,6 +637,8 @@ static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
636{ 637{
637 struct tegra_pcie *pcie = sys_to_pcie(pdev->bus->sysdata); 638 struct tegra_pcie *pcie = sys_to_pcie(pdev->bus->sysdata);
638 639
640 tegra_cpuidle_pcie_irqs_in_use();
641
639 return pcie->irq; 642 return pcie->irq;
640} 643}
641 644
@@ -1221,6 +1224,8 @@ static int tegra_msi_map(struct irq_domain *domain, unsigned int irq,
1221 irq_set_chip_data(irq, domain->host_data); 1224 irq_set_chip_data(irq, domain->host_data);
1222 set_irq_flags(irq, IRQF_VALID); 1225 set_irq_flags(irq, IRQF_VALID);
1223 1226
1227 tegra_cpuidle_pcie_irqs_in_use();
1228
1224 return 0; 1229 return 0;
1225} 1230}
1226 1231
diff --git a/include/linux/tegra-cpuidle.h b/include/linux/tegra-cpuidle.h
new file mode 100644
index 000000000000..dda3647242a4
--- /dev/null
+++ b/include/linux/tegra-cpuidle.h
@@ -0,0 +1,19 @@
1/*
2 * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#ifndef __LINUX_TEGRA_CPUIDLE_H__
15#define __LINUX_TEGRA_CPUIDLE_H__
16
17void tegra_cpuidle_pcie_irqs_in_use(void);
18
19#endif