lkml.org 
[lkml]   [2009]   [Dec]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[RFC][PATCH 5/12] PCI PM: Make it possible to force using INTx for PCIe PME signaling (updated)
Date
On Sunday 29 November 2009, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
>
> Apparently, some machines may have problems with PCI run-time power
> management if MSIs are used for the hative PCIe PME signaling. In
> particular, on the MSI Wind U-100 PCIe PME interrupts are not
> generated by a PCIe root port after a resume from suspend to RAM, if
> the system wake-up was triggered by a PME from the device attached to
> this port. [It doesn't help to free the interrupt on suspend and
> request it back on resume, even if that is done along with disabling
> the MSI and re-enabling it, respectively.] However, if INTx
> interrupts are used for this purpose on the same machine, everything
> works just fine.
>
> For this reason, add a kernel command line switch allowing one to
> request that MSIs be not used for the native PCIe PME signaling,
> introduce a DMI table allowing us to blacklist machines that need
> this switch to be set by default and put the MSI Wind U-100 into this
> table.

The DMI table has to be terminated appropriately. Fixed version is appended.

---
From: Rafael J. Wysocki <rjw@sisk.pl>
Subject: PCI PM: Make it possible to force using INTx for PCIe PME signaling

Apparently, some machines may have problems with PCI run-time power
management if MSIs are used for the hative PCIe PME signaling. In
particular, on the MSI Wind U-100 PCIe PME interrupts are not
generated by a PCIe root port after a resume from suspend to RAM, if
the system wake-up was triggered by a PME from the device attached to
this port. [It doesn't help to free the interrupt on suspend and
request it back on resume, even if that is done along with disabling
the MSI and re-enabling it, respectively.] However, if INTx
interrupts are used for this purpose on the same machine, everything
works just fine.

For this reason, add a kernel command line switch allowing one to
request that MSIs be not used for the native PCIe PME signaling,
introduce a DMI table allowing us to blacklist machines that need
this switch to be set by default and put the MSI Wind U-100 into this
table.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
Documentation/kernel-parameters.txt | 2 ++
drivers/pci/pcie/pme/pcie_pme.c | 14 +++++++++++++-
drivers/pci/pcie/portdrv.h | 17 +++++++++++++++++
drivers/pci/pcie/portdrv_core.c | 5 +++++
drivers/pci/pcie/portdrv_pci.c | 27 +++++++++++++++++++++++++++
5 files changed, 64 insertions(+), 1 deletion(-)

Index: linux-2.6/drivers/pci/pcie/pme/pcie_pme.c
===================================================================
--- linux-2.6.orig/drivers/pci/pcie/pme/pcie_pme.c
+++ linux-2.6/drivers/pci/pcie/pme/pcie_pme.c
@@ -53,12 +53,22 @@ static bool pcie_pme_disabled;
*/
static bool pcie_pme_force_enable;

+/*
+ * If this switch is set, MSI will not be used for PCIe PME signaling. This
+ * causes the PCIe port driver to use INTx interrupts only, but it turns out
+ * that using MSI for PCIe PME signaling doesn't play well with PCIe PME-based
+ * wake-up from system sleep states.
+ */
+bool pcie_pme_msi_disabled;
+
static int __init pcie_pme_setup(char *str)
{
if (!strcmp(str, "off"))
pcie_pme_disabled = true;
else if (!strcmp(str, "force"))
pcie_pme_force_enable = true;
+ else if (!strcmp(str, "nomsi"))
+ pcie_pme_msi_disabled = true;
return 1;
}
__setup("pcie_pme=", pcie_pme_setup);
@@ -73,7 +83,9 @@ __setup("pcie_pme=", pcie_pme_setup);
*/
static bool pcie_pme_platform_setup(struct pcie_device *srv)
{
- return !pcie_pme_platform_notify(srv) || pcie_pme_force_enable;
+ if (!pcie_pme_platform_notify(srv))
+ return true;
+ return pcie_pme_force_enable;
}

struct pcie_pme_service_data {
Index: linux-2.6/drivers/pci/pcie/portdrv_core.c
===================================================================
--- linux-2.6.orig/drivers/pci/pcie/portdrv_core.c
+++ linux-2.6/drivers/pci/pcie/portdrv_core.c
@@ -190,6 +190,10 @@ static int assign_interrupt_mode(struct
int irq, interrupt_mode = PCIE_PORT_NO_IRQ;
int i;

+ /* We have to use INTx if MSI cannot be used for PCIe PME. */
+ if ((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi())
+ goto no_msi;
+
/* Try to use MSI-X if supported */
if (!pcie_port_enable_msix(dev, vectors, mask))
return PCIE_PORT_MSIX_MODE;
@@ -198,6 +202,7 @@ static int assign_interrupt_mode(struct
if (!pci_enable_msi(dev))
interrupt_mode = PCIE_PORT_MSI_MODE;

+ no_msi:
if (interrupt_mode == PCIE_PORT_NO_IRQ && dev->pin)
interrupt_mode = PCIE_PORT_INTx_MODE;

Index: linux-2.6/drivers/pci/pcie/portdrv_pci.c
===================================================================
--- linux-2.6.orig/drivers/pci/pcie/portdrv_pci.c
+++ linux-2.6/drivers/pci/pcie/portdrv_pci.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/pcieport_if.h>
#include <linux/aer.h>
+#include <linux/dmi.h>

#include "portdrv.h"
#include "aer/aerdrv.h"
@@ -272,10 +273,36 @@ static struct pci_driver pcie_portdriver
.driver.pm = PCIE_PORTDRV_PM_OPS,
};

+static int __init dmi_pcie_pme_disable_msi(const struct dmi_system_id *d)
+{
+ pr_notice("%s detected: will not use MSI for PCIe PME signaling\n",
+ d->ident);
+ pcie_pme_disable_msi();
+ return 0;
+}
+
+static struct dmi_system_id __initdata pcie_portdrv_dmi_table[] = {
+ /*
+ * Boxes that should not use MSI for PCIe PME signaling.
+ */
+ {
+ .callback = dmi_pcie_pme_disable_msi,
+ .ident = "MSI Wind U-100",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "MICRO-STAR INTERNATIONAL CO., LTD"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "U-100"),
+ },
+ },
+ {}
+};
+
static int __init pcie_portdrv_init(void)
{
int retval;

+ dmi_check_system(pcie_portdrv_dmi_table);
+
retval = pcie_port_bus_register();
if (retval) {
printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval);
Index: linux-2.6/drivers/pci/pcie/portdrv.h
===================================================================
--- linux-2.6.orig/drivers/pci/pcie/portdrv.h
+++ linux-2.6/drivers/pci/pcie/portdrv.h
@@ -45,4 +45,21 @@ extern void pcie_port_device_remove(stru
extern int __must_check pcie_port_bus_register(void);
extern void pcie_port_bus_unregister(void);

+#ifdef CONFIG_PCIE_PME
+extern bool pcie_pme_msi_disabled;
+
+static inline void pcie_pme_disable_msi(void)
+{
+ pcie_pme_msi_disabled = true;
+}
+
+static inline bool pcie_pme_no_msi(void)
+{
+ return pcie_pme_msi_disabled;
+}
+#else /* !CONFIG_PCIE_PME */
+static inline void pcie_pme_disable_msi(void) {}
+static inline bool pcie_pme_no_msi(void) { return false; }
+#endif /* !CONFIG_PCIE_PME */
+
#endif /* _PORTDRV_H_ */
Index: linux-2.6/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.orig/Documentation/kernel-parameters.txt
+++ linux-2.6/Documentation/kernel-parameters.txt
@@ -1971,6 +1971,8 @@ and is between 256 and 4096 characters.
force Use native PCIe PME signaling even if the BIOS refuses
to allow the kernel to control the relevant PCIe config
registers.
+ nomsi Do not use MSI for native PCIe PME signaling (this makes
+ all PCIe root ports use INTx for everything).

pcmv= [HW,PCMCIA] BadgePAD 4


\
 
 \ /
  Last update: 2009-12-04 22:19    [W:0.172 / U:1.112 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site