Re: [PATCHv3 01/10] PCI/portdrv: Use subsys_init for service drivers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Sep 18, 2018 at 05:56:53PM -0600, Keith Busch wrote:
> The PCI port driver saves the PCI state after initializing all the
> service devices. This was, however, before the service drivers were even
> registered. The config space state that the service drivers were setting
> up were not being saved.
> 
> This patch fixes this by changing the service drivers use the
> subsys_init, which gets the service drivers registered after the pci bus
> system is initialized, but before the pci devices are probed. This gets
> the state saved as expected.

I agree this is a problem.  What are the user-visible symptoms of it?
Incorrect service behavior after a resume?  Nice debugging and fix!

I think the ordering here is pretty obscure.  We have a lot of
initcalls here and they all have to line up exactly right.  If I
understand correctly, the flow of the required pieces (after this
patch) is like this:

  pci_driver_init                             # postcore_initcall (2)
    bus_register(&pcie_port_bus_type)

  pcied_init (pciehp)                         # subsys_initcall (4)
    pcie_port_service_register(&hpdriver_portdrv)
      new->driver.bus = &pcie_port_bus_type   # depends on above
                                              # bus_register()
      driver_register(&new->driver)

  pcie_portdrv_init                           # device_initcall (6)
    pci_register_driver(&pcie_portdriver)

  pcie_portdrv_probe                          # pcie_portdriver.probe
    pcie_port_device_register
      pcie_device_init
        device_register
          device_add
            bus_probe_device
              ...
                pciehp_probe                  # <-- critical init
                                              # depends on above
                                              # service_register() and
                                              # eager probing
    pci_save_state                            # <-- critical save

The problem used to be that both pcied_init() (for pciehp) and
pcie_portdrv_init() were device initcalls and pcie_portdrv_init() was
called before pcied_init() because of link order, so the
pci_save_state() happened before the pciehp init.

Since none of the service drivers can be modules, I don't think it
buys us much to make their init functions initcalls.  Can we
explicitly call them from the pcie_portdrv_probe() path?

> Note, 70626d88385 ("PCI: pciehp: Make explicitly non-modular") already
> mentioned this exact change should be done, but declined to at the time
> until there was a real need for it.
> 
> Signed-off-by: Keith Busch <keith.busch@xxxxxxxxx>
> ---
>  drivers/pci/hotplug/pciehp_core.c | 2 +-
>  drivers/pci/pcie/aer.c            | 2 +-
>  drivers/pci/pcie/dpc.c            | 2 +-
>  drivers/pci/pcie/pme.c            | 2 +-
>  4 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
> index ccaf01e6eced..334044814dbe 100644
> --- a/drivers/pci/hotplug/pciehp_core.c
> +++ b/drivers/pci/hotplug/pciehp_core.c
> @@ -322,4 +322,4 @@ static int __init pcied_init(void)
>  
>  	return retval;
>  }
> -device_initcall(pcied_init);
> +subsys_initcall(pcied_init);
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index 83180edd6ed4..1d2159409b01 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -1575,4 +1575,4 @@ static int __init aer_service_init(void)
>  		return -ENXIO;
>  	return pcie_port_service_register(&aerdriver);
>  }
> -device_initcall(aer_service_init);
> +subsys_initcall(aer_service_init);
> diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
> index f03279fc87cd..aacfb50eccfc 100644
> --- a/drivers/pci/pcie/dpc.c
> +++ b/drivers/pci/pcie/dpc.c
> @@ -286,4 +286,4 @@ static int __init dpc_service_init(void)
>  {
>  	return pcie_port_service_register(&dpcdriver);
>  }
> -device_initcall(dpc_service_init);
> +subsys_initcall(dpc_service_init);
> diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
> index 3ed67676ea2a..cd8c1adb9b0a 100644
> --- a/drivers/pci/pcie/pme.c
> +++ b/drivers/pci/pcie/pme.c
> @@ -450,4 +450,4 @@ static int __init pcie_pme_service_init(void)
>  {
>  	return pcie_port_service_register(&pcie_pme_driver);
>  }
> -device_initcall(pcie_pme_service_init);
> +subsys_initcall(pcie_pme_service_init);
> -- 
> 2.14.4
> 



[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux