diff options
-rw-r--r-- | arch/arm/mach-tegra/cpuidle-tegra20.c | 12 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpuidle.c | 10 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpuidle.h | 1 | ||||
-rw-r--r-- | drivers/pci/host/pci-tegra.c | 5 | ||||
-rw-r--r-- | include/linux/tegra-cpuidle.h | 19 |
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 | */ | ||
219 | void 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 | |||
214 | int __init tegra20_cpuidle_init(void) | 226 | int __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 | |||
48 | void 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 |
21 | int tegra20_cpuidle_init(void); | 21 | int tegra20_cpuidle_init(void); |
22 | void tegra20_cpuidle_pcie_irqs_in_use(void); | ||
22 | int tegra30_cpuidle_init(void); | 23 | int tegra30_cpuidle_init(void); |
23 | int tegra114_cpuidle_init(void); | 24 | int tegra114_cpuidle_init(void); |
24 | void tegra_cpuidle_init(void); | 25 | void 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 | |||
17 | void tegra_cpuidle_pcie_irqs_in_use(void); | ||
18 | |||
19 | #endif | ||