Fix more PCIe ASPM bugs

- kworker task over 65% after resume (#683156)
- ASPM powersave mode does not get enabled
This commit is contained in:
Chuck Ebbert 2011-03-27 20:14:26 -04:00
parent 1590df9db8
commit 073133a682
4 changed files with 213 additions and 70 deletions

View File

@ -51,7 +51,7 @@ Summary: The Linux kernel
# For non-released -rc kernels, this will be prepended with "0.", so
# for example a 3 here will become 0.3
#
%global baserelease 7
%global baserelease 8
%global fedora_build %{baserelease}
# base_sublevel is the kernel version we're starting with and patching
@ -633,7 +633,6 @@ Patch204: linux-2.6-debug-always-inline-kzalloc.patch
Patch380: linux-2.6-defaults-pci_no_msi.patch
Patch381: linux-2.6-defaults-pci_use_crs.patch
Patch383: linux-2.6-defaults-aspm.patch
Patch386: pci-_osc-supported-field-should-contain-supported-features-not-enabled-ones.patch
Patch385: ima-allow-it-to-be-completely-disabled-and-default-off.patch
@ -728,6 +727,8 @@ Patch12200: acpi_reboot.patch
Patch12203: linux-2.6-usb-pci-autosuspend.patch
Patch12204: linux-2.6-enable-more-pci-autosuspend.patch
Patch12205: runtime_pm_fixups.patch
Patch12206: pci-acpi-report-aspm-support-to-bios-if-not-disabled-from-command-line.patch
Patch12207: pci-pcie-links-may-not-get-configured-for-aspm-under-powersave-mode.patch
Patch12303: dmar-disable-when-ricoh-multifunction.patch
@ -1247,8 +1248,10 @@ ApplyPatch linux-2.6-defaults-pci_no_msi.patch
ApplyPatch linux-2.6-defaults-pci_use_crs.patch
# enable ASPM by default on hardware we expect to work
ApplyPatch linux-2.6-defaults-aspm.patch
# rhbz#638912
#ApplyPatch pci-_osc-supported-field-should-contain-supported-features-not-enabled-ones.patch
# rhbz #683156
ApplyPatch pci-acpi-report-aspm-support-to-bios-if-not-disabled-from-command-line.patch
#
ApplyPatch pci-pcie-links-may-not-get-configured-for-aspm-under-powersave-mode.patch
#ApplyPatch ima-allow-it-to-be-completely-disabled-and-default-off.patch
@ -1980,6 +1983,11 @@ fi
# and build.
%changelog
* Sat Mar 26 2011 Chuck Ebbert <cebbert@redhat.com>
- Fix more PCIe ASPM bugs:
kworker task over 65% after resume (#683156)
ASPM powersave mode does not get enabled
* Sat Mar 26 2011 Chuck Ebbert <cebbert@redhat.com> 2.6.38.2-7.rc1
- Linux 2.6.38.2-rc1

View File

@ -1,66 +0,0 @@
commit 885c252ffb059dc493200bdb981bdd21cabe4442
Author: Matthew Garrett <mjg@redhat.com>
Date: Thu Dec 9 18:31:59 2010 -0500
PCI: _OSC "supported" field should contain supported features, not enabled ones
From testing with Windows, the call to the PCI root _OSC method includes
the full set of features supported by the operating system even if the
hardware has already indicated that it doesn't support ASPM or MSI.
https://bugzilla.redhat.com/show_bug.cgi?id=638912 is a case where making
the _OSC call will incorrectly configure the chipset unless the supported
field has bits 1, 2 and 4 set. Rework the functionality to ensure that
we match this behaviour.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 96668ad..afb5d08 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -450,7 +450,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
struct acpi_pci_root *root;
acpi_handle handle;
struct acpi_device *child;
- u32 flags, base_flags;
+ u32 flags;
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root)
@@ -498,10 +498,15 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
device->driver_data = root;
/*
- * All supported architectures that use ACPI have support for
- * PCI domains, so we indicate this in _OSC support capabilities.
+ * Indicate support for various _OSC capabilities. These match
+ * what the operating system supports, not what the hardware supports,
+ * so they shouldn't be conditional on functionality that's been
+ * blacklisted
*/
- flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
+ flags = OSC_EXT_PCI_CONFIG_SUPPORT | OSC_ACTIVE_STATE_PWR_SUPPORT |
+ OSC_CLOCK_PWR_CAPABILITY_SUPPORT |
+ OSC_PCI_SEGMENT_GROUPS_SUPPORT | OSC_MSI_SUPPORT;
+
acpi_pci_osc_support(root, flags);
/*
@@ -555,17 +560,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
list_for_each_entry(child, &device->children, node)
acpi_pci_bridge_scan(child);
- /* Indicate support for various _OSC capabilities. */
- if (pci_ext_cfg_avail(root->bus->self))
- flags |= OSC_EXT_PCI_CONFIG_SUPPORT;
- if (pcie_aspm_enabled())
- flags |= OSC_ACTIVE_STATE_PWR_SUPPORT |
- OSC_CLOCK_PWR_CAPABILITY_SUPPORT;
- if (pci_msi_enabled())
- flags |= OSC_MSI_SUPPORT;
- if (flags != base_flags)
- acpi_pci_osc_support(root, flags);
-
pci_acpi_add_bus_pm_notifier(device, root->bus);
if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true);

View File

@ -0,0 +1,89 @@
From: Rafael J. Wysocki <rjw@sisk.pl>
Date: Sat, 5 Mar 2011 12:21:51 +0000 (+0100)
Subject: PCI/ACPI: Report ASPM support to BIOS if not disabled from command line
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=8b8bae901ce23addbdcdb54fa1696fb2d049feb5
PCI/ACPI: Report ASPM support to BIOS if not disabled from command line
We need to distinguish the situation in which ASPM support is
disabled from the command line or through .config from the situation
in which it is disabled, because the hardware or BIOS can't handle
it. In the former case we should not report ASPM support to the BIOS
through ACPI _OSC, but in the latter case we should do that.
Introduce pcie_aspm_support_enabled() that can be used by
acpi_pci_root_add() to determine whether or not it should report ASPM
support to the BIOS through _OSC.
Cc: stable@kernel.org
References: https://bugzilla.kernel.org/show_bug.cgi?id=29722
References: https://bugzilla.kernel.org/show_bug.cgi?id=20232
Reported-and-tested-by: Ortwin Glück <odi@odi.ch>
Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Tested-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 8524939..c7358dd 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -564,7 +564,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
/* Indicate support for various _OSC capabilities. */
if (pci_ext_cfg_avail(root->bus->self))
flags |= OSC_EXT_PCI_CONFIG_SUPPORT;
- if (pcie_aspm_enabled())
+ if (pcie_aspm_support_enabled())
flags |= OSC_ACTIVE_STATE_PWR_SUPPORT |
OSC_CLOCK_PWR_CAPABILITY_SUPPORT;
if (pci_msi_enabled())
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 3188cd9..bbdb4fd 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -69,6 +69,7 @@ struct pcie_link_state {
};
static int aspm_disabled, aspm_force, aspm_clear_state;
+static bool aspm_support_enabled = true;
static DEFINE_MUTEX(aspm_lock);
static LIST_HEAD(link_list);
@@ -896,6 +897,7 @@ static int __init pcie_aspm_disable(char *str)
{
if (!strcmp(str, "off")) {
aspm_disabled = 1;
+ aspm_support_enabled = false;
printk(KERN_INFO "PCIe ASPM is disabled\n");
} else if (!strcmp(str, "force")) {
aspm_force = 1;
@@ -930,3 +932,8 @@ int pcie_aspm_enabled(void)
}
EXPORT_SYMBOL(pcie_aspm_enabled);
+bool pcie_aspm_support_enabled(void)
+{
+ return aspm_support_enabled;
+}
+EXPORT_SYMBOL(pcie_aspm_support_enabled);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 16c9f2e..96f70d7 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1002,12 +1002,11 @@ extern bool pcie_ports_auto;
#endif
#ifndef CONFIG_PCIEASPM
-static inline int pcie_aspm_enabled(void)
-{
- return 0;
-}
+static inline int pcie_aspm_enabled(void) { return 0; }
+static inline bool pcie_aspm_support_enabled(void) { return false; }
#else
extern int pcie_aspm_enabled(void);
+extern bool pcie_aspm_support_enabled(void);
#endif
#ifdef CONFIG_PCIEAER

View File

@ -0,0 +1,112 @@
From: Naga Chumbalkar <nagananda.chumbalkar@hp.com>
Date: Mon, 21 Mar 2011 03:29:08 +0000 (+0000)
Subject: PCI: PCIe links may not get configured for ASPM under POWERSAVE mode
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=1a680b7c325882188865f05b9a88d32f75f26495
PCI: PCIe links may not get configured for ASPM under POWERSAVE mode
v3 -> v2: Moved ASPM enabling logic to pci_set_power_state()
v2 -> v1: Preserved the logic in pci_raw_set_power_state()
: Added ASPM enabling logic after scanning Root Bridge
: http://marc.info/?l=linux-pci&m=130046996216391&w=2
v1 : http://marc.info/?l=linux-pci&m=130013164703283&w=2
The assumption made in commit 41cd766b065970ff6f6c89dd1cf55fa706c84a3d
(PCI: Don't enable aspm before drivers have had a chance to veto it) that
pci_enable_device() will result in re-configuring ASPM when aspm_policy is
POWERSAVE is no longer valid. This is due to commit
97c145f7c87453cec90e91238fba5fe2c1561b32 (PCI: read current power state
at enable time) which resets dev->current_state to D0. Due to this the
call to pcie_aspm_pm_state_change() is never made. Note the equality check
(below) that returns early:
./drivers/pci/pci.c: pci_raw_set_pci_power_state()
546 /* Check if we're already there */
547 if (dev->current_state == state)
548 return 0;
Therefore OSPM never configures the PCIe links for ASPM to turn them "on".
Fix it by configuring ASPM from the pci_enable_device() code path. This
also allows a driver such as the e1000e networking driver a chance to
disable ASPM (L0s, L1), if need be, prior to enabling the device. A
driver may perform this action if the device is known to mis-behave
wrt ASPM.
Signed-off-by: Naga Chumbalkar <nagananda.chumbalkar@hp.com>
Acked-by: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b714d78..2472e71 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -740,6 +740,12 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
if (!__pci_complete_power_transition(dev, state))
error = 0;
+ /*
+ * When aspm_policy is "powersave" this call ensures
+ * that ASPM is configured.
+ */
+ if (!error && dev->bus->self)
+ pcie_aspm_powersave_config_link(dev->bus->self);
return error;
}
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index bbdb4fd..e61b82e 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -708,6 +708,28 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev)
up_read(&pci_bus_sem);
}
+void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
+{
+ struct pcie_link_state *link = pdev->link_state;
+
+ if (aspm_disabled || !pci_is_pcie(pdev) || !link)
+ return;
+
+ if (aspm_policy != POLICY_POWERSAVE)
+ return;
+
+ if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
+ (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
+ return;
+
+ down_read(&pci_bus_sem);
+ mutex_lock(&aspm_lock);
+ pcie_config_aspm_path(link);
+ pcie_set_clkpm(link, policy_to_clkpm_state(link));
+ mutex_unlock(&aspm_lock);
+ up_read(&pci_bus_sem);
+}
+
/*
* pci_disable_link_state - disable pci device's link state, so the link will
* never enter specific states
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h
index ce68105..67cb3ae 100644
--- a/include/linux/pci-aspm.h
+++ b/include/linux/pci-aspm.h
@@ -26,6 +26,7 @@
extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
+extern void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
extern void pci_disable_link_state(struct pci_dev *pdev, int state);
extern void pcie_clear_aspm(void);
extern void pcie_no_aspm(void);
@@ -39,6 +40,9 @@ static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev)
static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev)
{
}
+static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
+{
+}
static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
{
}