Re: [PATCH] pci: Added flag to pci_host_bridge to hint not to use acpi

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

 



[+cc Rafael, linux-acpi]

On Thu, Mar 24, 2016 at 04:42:00PM +0000, Keith Busch wrote:
> On Wed, Mar 23, 2016 at 04:01:58PM -0600, Jon Derrick wrote:
> > This patch adds a hint, no_acpi, to the pci_host_bridge struct which
> > informs the hotplug driver to not try and release the host bridge from
> > acpi.
> > 
> > The VMD driver creates a root port which does not have an acpi entry.
> > This patch will allow the hotplug driver to bypass acpi release when
> > enumerating the VMD root port as a hotplug slot.
> 
> I want to add a little context to this for the motivation for this
> implementation.
> 
> Currently we have to set kernel parameter "pcie_ports=native" for pciehp
> to work on these domains since they are not known to ACPI. We don't want
> to force a system wide PCIe parameter for something specific to a subset
> of domains.

I agree, we shouldn't have to ask users to boot with
"pcie_ports=native".

The PCIe port driver figures out what service drivers can be enabled
by a combination of:

  - asking the platform what services it will allow the kernel to
    manage (on ACPI systems, this uses _OSC), and

  - looking at the PCIe capability to see what services the hardware
    supports.

This happens in get_port_device_capability().  When you boot with
"pcie_ports=native", get_port_device_capability() skips the _OSC part
and only looks at what the hardware supports.

Here's the rest of the path:

  pcie_portdrv_probe                     # pci_driver.probe
    pcie_port_device_register
      get_port_device_capability
        if (pcie_ports_auto)             # cleared by pcie_port=native
	  pcie_port_platform_notify
	    pcie_port_acpi_setup
	      if (no_acpi)               # added by your patch
		return 0
	      handle = acpi_find_root_bridge_handle(port)
	      if (!handle)
	        return -EINVAL
	      set mask of what we control based on _OSC
	      return 0

The spec (PCI Firmware spec 3.0, sec 4.5) says _OSC is a child of an
ACPI device and applies to that device.  In your case, I think there
is no ACPI PNP0A0x device for the VMD host bridge, and hence there is
no _OSC method for it.  There's no ACPI handle for the VMD bridge, so
I think pcie_port_acpi_setup() returns -EINVAL, which causes
get_port_device_capability() to give up and decide that the port
can't support *any* PCIe services.

I think that's the real problem: the fact that there's no ACPI device
corresponding to the bridge should not be an error.  It should just
mean the platform doesn't have an opportunity to limit what services
the kernel can manage.  I think pcie_port_acpi_setup() should return 0
in all cases.  Can you try that and see if it fixes the problem?

Bjorn

> >  arch/x86/pci/vmd.c              | 4 ++++
> >  drivers/pci/pcie/portdrv_acpi.c | 5 +++++
> >  include/linux/pci.h             | 1 +
> >  3 files changed, 10 insertions(+)
> > 
> > diff --git a/arch/x86/pci/vmd.c b/arch/x86/pci/vmd.c
> > index 7792aba..a196be3 100644
> > --- a/arch/x86/pci/vmd.c
> > +++ b/arch/x86/pci/vmd.c
> > @@ -531,6 +531,7 @@ static int vmd_find_free_domain(void)
> >  static int vmd_enable_domain(struct vmd_dev *vmd)
> >  {
> >  	struct pci_sysdata *sd = &vmd->sysdata;
> > +	struct pci_host_bridge *host_bridge;
> >  	struct resource *res;
> >  	u32 upper_bits;
> >  	unsigned long flags;
> > @@ -609,6 +610,9 @@ static int vmd_enable_domain(struct vmd_dev *vmd)
> >  		return -ENODEV;
> >  	}
> >  
> > +	host_bridge = to_pci_host_bridge(vmd->bus->bridge);
> > +	host_bridge->no_acpi = true;
> > +
> >  	vmd_attach_resources(vmd);
> >  	vmd_setup_dma_ops(vmd);
> >  	dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);
> > diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c
> > index b4d2894..0e6fa69 100644
> > --- a/drivers/pci/pcie/portdrv_acpi.c
> > +++ b/drivers/pci/pcie/portdrv_acpi.c
> > @@ -35,12 +35,17 @@
> >  int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
> >  {
> >  	struct acpi_pci_root *root;
> > +	struct pci_host_bridge *host_bridge;
> >  	acpi_handle handle;
> >  	u32 flags;
> >  
> >  	if (acpi_pci_disabled)
> >  		return 0;
> >  
> > +	host_bridge = pci_find_host_bridge(port->bus);
> > +	if (host_bridge && host_bridge->no_acpi)
> > +		return 0;
> > +
> >  	handle = acpi_find_root_bridge_handle(port);
> >  	if (!handle)
> >  		return -EINVAL;
> > diff --git a/include/linux/pci.h b/include/linux/pci.h
> > index 15f466e..a6958e9b 100644
> > --- a/include/linux/pci.h
> > +++ b/include/linux/pci.h
> > @@ -407,6 +407,7 @@ struct pci_host_bridge {
> >  	void (*release_fn)(struct pci_host_bridge *);
> >  	void *release_data;
> >  	unsigned int ignore_reset_delay:1;	/* for entire hierarchy */
> > +	unsigned int no_acpi:1;			/* bypasses acpi release */
> >  	/* Resource alignment requirements */
> >  	resource_size_t (*align_resource)(struct pci_dev *dev,
> >  			const struct resource *res,
> > -- 
> > 1.8.3.1
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[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