Re: [PATCH] PCI: Drop unnecessary retries when restoring BARs

Bjorn Helgaas <[email protected]> Thu, 7 May 2026 19:17:00 -0500
Newsgroups dev.linux.lists.sashiko,org.kernel.vger.linux-pci
Message-ID <20260508001700.GA52868@bhelgaas>
On Tue, May 05, 2026 at 12:43:17PM +0200, Rafael J. Wysocki wrote:
> On Mon, May 4, 2026 at 11:17 PM Bjorn Helgaas <[email protected]> wrote:
> ...

> > If pci_power_up() is doing D3cold -> D0, main power is initially
> > off, so platform_pci_set_power_state(PCI_D0) would turn on main
> > power, which is a Fundamental Reset leaving the device in
> > D0uninitialized.  In general the device needs at least 100 ms
> > after that reset before any access, e.g., before the PMCSR read.
> 
> Yes, it does in general, but that should be covered by
> platform_pci_set_power_state() because on some platforms the delay
> can be shorter.

It's surprising to me that platform_pci_set_power_state() takes
care of that delay because there's so much PCIe infrastructure
(dependencies on link speed, RRS polling, Immediate Readiness,
Readiness Notifications, etc), much of which sounds more like
OS-level support than firmware support.

But if platform_pci_set_power_state() does guarantee that the device
is Configuration-Ready, we should document that somewhere.

> > If pci_power_up() is doing D3hot -> D0, the device already has
> > main power, so I suppose platform_pci_set_power_state(PCI_D0)
> > doesn't do anything.
> 
> It may or may not.  Some platforms supply AML to run during D3hot ->
> D0 transitions (and the ACPI spec allows that).

If the device started in D3hot, it never lost main power, and I
assumed platform_pci_set_power_state(PCI_D0) might just leave it in
D3hot.  It sounds like it takes it all the way to D0, although the
subsequent code that checks the PMCSR state does suggest that the
device might *not* be in D0:

    platform_pci_set_power_state(dev, PCI_D0);

    pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
    state = pmcsr & PCI_PM_CTRL_STATE_MASK;
    if (state == PCI_D0)
      goto end;

    pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, 0);
    if (state == PCI_D3hot)
      pci_dev_d3_sleep(dev);
    ...

  end:

If platform_pci_set_power_state(PCI_D0) puts the device in D0 and
takes care of all the delays, "state" should always be PCI_D0, and we
shouldn't need the D3hot and D2 delays here.

Bjorn