From: Lukas Wunner <lukas@wunner.de>
To: Bjorn Helgaas <bhelgaas@google.com>
Cc: linux-pci@vger.kernel.org, Rajat Jain <rajatja@google.com>,
Yinghai Lu <yinghai@kernel.org>, Len Brown <lenb@kernel.org>
Subject: Re: [PATCH] PCI: pciehp: Check for PCIe capabilities change after resume
Date: Fri, 11 Nov 2016 00:18:08 +0100 [thread overview]
Message-ID: <20161110231808.GA8155@wunner.de> (raw)
In-Reply-To: <20161110185520.19461.9789.stgit@bhelgaas-glaptop.roam.corp.google.com>
On Thu, Nov 10, 2016 at 12:55:20PM -0600, Bjorn Helgaas wrote:
> Len Brown reported that resume on a Dell XPS11 laptop takes longer than it
> should. The delay is caused by pciehp scanning for a device below a Root
> Port that has nothing connected to it.
>
> At boot-time, the 00:1c.0 Root Port's PCI Express Capabilities Register
> (PCIe spec r3.0, sec 7.8.2) advertises a slot (PCI_EXP_FLAGS_SLOT is set),
> so pciehp claims the port.
>
> At resume-time, PCI_EXP_FLAGS_SLOT is clear, so the Root Port no longer
> advertises a slot. But pciehp doesn't notice that change, and it reads
> Slot Status to see if anything changed. Slot Status says a device is
> present (Ports not connected to slots are required to report "Card Present"
> per sec 7.8.11), so pciehp tries to bring up the link and scan for the
> device, which accounts for the delay.
>
> Per sec 7.8.2, the PCIe Capabilities Register is all read-only, so I
> think the fact that it changes between boot- and resume-time is a
> firmware defect.
>
> Work around this by re-reading the Capabilites at resume-time and updating
> the cached copy in pci_dev->pcie_flags_reg. Then stop using pciehp on the
> port if it no longer advertises a slot.
>
> Reported-and-tested-by: Len Brown <lenb@kernel.org>
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=99751
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/pci/hotplug/pciehp_core.c | 10 ++++++++++
> drivers/pci/pci-driver.c | 13 +++++++++++++
> 2 files changed, 23 insertions(+)
>
> diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
> index 7d32fa33..f5461cb 100644
> --- a/drivers/pci/hotplug/pciehp_core.c
> +++ b/drivers/pci/hotplug/pciehp_core.c
> @@ -278,6 +278,9 @@ static void pciehp_remove(struct pcie_device *dev)
> {
> struct controller *ctrl = get_service_data(dev);
>
> + if (!ctrl)
> + return;
> +
> cleanup_slot(ctrl);
> pciehp_release_ctrl(ctrl);
> }
> @@ -296,6 +299,13 @@ static int pciehp_resume(struct pcie_device *dev)
>
> ctrl = get_service_data(dev);
>
> + if (!(pcie_caps_reg(dev->port) & PCI_EXP_FLAGS_SLOT)) {
> + dev_info(&dev->port->dev, "No longer supports hotplug\n");
> + pciehp_remove(dev);
> + set_service_data(dev, NULL);
> + return 0;
> + }
> +
> /* reinitialize the chipset's event detection logic */
> pcie_enable_notification(ctrl);
>
> diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
> index 1ccce1c..fe8e964 100644
> --- a/drivers/pci/pci-driver.c
> +++ b/drivers/pci/pci-driver.c
> @@ -505,7 +505,20 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
>
> static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
> {
> + u16 flags;
> +
> pci_power_up(pci_dev);
> +
> + if (pci_dev->pcie_cap) {
> + pci_read_config_word(pci_dev, pci_dev->pcie_cap + PCI_EXP_FLAGS,
> + &flags);
> + if (pci_dev->pcie_flags_reg != flags) {
> + dev_info(&pci_dev->dev, "PCIe Capabilities was %#06x, is %#06x after resume (possible firmware defect)\n",
> + pci_dev->pcie_flags_reg, flags);
> + pci_dev->pcie_flags_reg = flags;
> + }
> + }
> +
Is there a reason that this must happen at ->resume_noirq time rather than
->resume time?
If not, you could move this to pciehp_resume(), no?
If yes, I think the above is suboptimal because it is executed for any
decice, even though it only concerns hotplug ports handled by pciehp.
(What if pciehp isn't compiled in at all?) A better way would IMHO be to:
- add a ->resume_noirq callback to struct pcie_port_service_driver,
- amend pcie_port_resume_noirq() to iterate over all port services and
call down to the ->resume_noirq callback of each, just like in
pcie_port_device_resume(),
- declare a ->resume_noirq callback for pciehp containing the above code.
Thanks,
Lukas
> pci_restore_state(pci_dev);
> pci_fixup_device(pci_fixup_resume_early, pci_dev);
> }
next prev parent reply other threads:[~2016-11-10 23:17 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-11-10 18:55 [PATCH] PCI: pciehp: Check for PCIe capabilities change after resume Bjorn Helgaas
2016-11-10 19:46 ` Rajat Jain
2016-11-10 23:18 ` Lukas Wunner [this message]
2016-11-11 0:24 ` Bjorn Helgaas
2016-11-11 6:44 ` Lukas Wunner
2016-11-11 6:47 ` Lukas Wunner
2016-11-11 15:49 ` Lukas Wunner
2016-11-11 18:28 ` Bjorn Helgaas
2016-11-14 12:10 ` Lukas Wunner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20161110231808.GA8155@wunner.de \
--to=lukas@wunner.de \
--cc=bhelgaas@google.com \
--cc=lenb@kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=rajatja@google.com \
--cc=yinghai@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.