All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Patterson <andrew.patterson@hp.com>
To: Matthew Wilcox <matthew@wil.cx>
Cc: linux-pci@vger.kernel.org, linux-acpi@vger.kernel.org
Subject: Re: Doing _OSC right
Date: Mon, 27 Oct 2008 16:12:19 +0000	[thread overview]
Message-ID: <1225123939.6725.83.camel@grinch> (raw)
In-Reply-To: <20081025053029.GT26094@parisc-linux.org>

On Fri, 2008-10-24 at 23:30 -0600, Matthew Wilcox wrote:
> Andrew Patterson recently reported a problem where a machine with dozens
> of PCIe root bridges would take half an hour just calling _OSC.  The
> root cause is the AER code calling:
> 
> 	pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
> 
> for each bridge.  pcie_osc_support_set() also iterates over each bridge,
> so _OSC is called a quadratic number of times.  Obviously, this isn't
> hard to fix -- just moving the call to pcie_osc_support_set() to
> aer_service_init() would do.
> 
> But why should a driver be calling pcie_osc_support_set() anyway?  This
> is something the PCI core should be taking care of for it.
> 
> The patch below illustrates one possible solution.  I create a new
> function (pci_acpi_osc_support()) which is called from pci_root.c before
> we call any other methods on the device (as recommended by the ACPI spec).
> Since we know what capabilities the system supports, individual modules
> do not now need to inform the core of their support for various
> capabilities.
> 
> I do not think this patch is perfect.  One defect is that there are
> now no callers of pci_osc_support_set nor pcie_osc_support_set, so they
> could be deleted.
> 
> Another problem is that if, for example, MSI is disabled at boot time,
> we will incorrectly inform ACPI that we support MSI.  So something more
> flexible is needed.

Check pci_msi_enable? After exposing it.

> 
> I think all the existing _OSC code should be moved from pci-acpi.c to
> pci_root.c.  I also think the acpi_osc_data should be made part of the
> acpi_pci_root struct, eliminating a separate allocation.
> 
> We could also use an interface that iterates over all existing busses
> calling _OSC with new flags.  Shouldn't be hard, once it's integrated
> into pci_root.c.
> 

Need to think about root hotplug at some point.

> Further ahead, we don't actually check that the bits we asked for (in
> 'control') were actually granted to us.  The PCI firmware spec is quite
> explicit about interdependencies amongst the bits.

Do we need to do this in addition to the typical
pci_find_capability(dev, PCI_CAP_ID_MSIX) check? Perhaps we can write a
function that does both?

> 
> We also need to re-evaluate _OSC when coming out of S4.  I'm not much of
> a power-management maven so I don't know where to put this call.
> 
> Thoughts on the road ahead?
> 

This patch does not compile on pci-2.6/linux-next with ia-64.

> diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
> index 1b8f67d..3af9fff 100644
> --- a/drivers/acpi/pci_root.c
> +++ b/drivers/acpi/pci_root.c
> @@ -31,6 +31,7 @@
>  #include <linux/spinlock.h>
>  #include <linux/pm.h>
>  #include <linux/pci.h>
> +#include <linux/pci-acpi.h>
>  #include <linux/acpi.h>
>  #include <acpi/acpi_bus.h>
>  #include <acpi/acpi_drivers.h>
> @@ -210,6 +211,18 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
>  
>  	device->ops.bind = acpi_pci_bind;
>  
> +	pci_acpi_osc_support(device->handle,
> +					OSC_EXT_PCI_CONFIG_SUPPORT |
> +					OSC_PCI_SEGMENT_GROUPS_SUPPORT |
> +#ifdef CONFIG_PCI_MSI
> +					OSC_MSI_SUPPORT |
> +#endif
> +#ifdef CONFIG_PCIEASPM
> +					OSC_ACTIVE_STATE_PWR_SUPPORT |
> +					OSC_CLOCK_PWR_CAPABILITY_SUPPORT |
> +#endif
> +					0);
> +
>  	/* 
>  	 * Segment
>  	 * -------
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index 74801f7..d281201 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -759,24 +759,3 @@ void pci_msi_init_pci_dev(struct pci_dev *dev)
>  {
>  	INIT_LIST_HEAD(&dev->msi_list);
>  }
> -
> -#ifdef CONFIG_ACPI
> -#include <linux/acpi.h>
> -#include <linux/pci-acpi.h>
> -static void __devinit msi_acpi_init(void)
> -{
> -	if (acpi_pci_disabled)
> -		return;
> -	pci_osc_support_set(OSC_MSI_SUPPORT);
> -	pcie_osc_support_set(OSC_MSI_SUPPORT);

Calling pcie_osc_support_set() here is redundant. pci_osc_support_set
will get all PCI/PCIe root bridges.

> -}
> -#else
> -static inline void msi_acpi_init(void) { }
> -#endif /* CONFIG_ACPI */
> -
> -void __devinit msi_init(void)
> -{
> -	if (!pci_msi_enable)
> -		return;
> -	msi_acpi_init();
> -}
> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
> index dfe7c8e..3ec5ecc 100644
> --- a/drivers/pci/pci-acpi.c
> +++ b/drivers/pci/pci-acpi.c
> @@ -139,28 +139,41 @@ static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data,
>  	return status;
>  }
>  
> -static acpi_status acpi_query_osc(acpi_handle handle,
> -				  u32 level, void *context, void **retval)
> +/*
> + * acpi_osc_support: Invoke _OSC indicating support for the given feature
> + * flags: Bitmask of flags to support
> + *
> + * See the ACPI spec for the definition of the flags
> + */
> +int pci_acpi_osc_support(acpi_handle handle, u32 flags)
>  {
> +	u32 dummy;
>  	acpi_status status;
> -	struct acpi_osc_data *osc_data;
> -	u32 flags = (unsigned long)context, dummy;
>  	acpi_handle tmp;
> +	struct acpi_osc_data *osc_data;
> +	int rc = 0;
>  
>  	status = acpi_get_handle(handle, "_OSC", &tmp);
>  	if (ACPI_FAILURE(status))
> -		return AE_OK;
> -
> +		return -ENODEV;
>  	mutex_lock(&pci_acpi_lock);
>  	osc_data = acpi_get_osc_data(handle);
>  	if (!osc_data) {
>  		printk(KERN_ERR "acpi osc data array is full\n");
> +		rc = -ENOMEM;
>  		goto out;
>  	}
>  
>  	__acpi_query_osc(flags, osc_data, &dummy);
> -out:
> + out:
>  	mutex_unlock(&pci_acpi_lock);
> +	return rc;
> +}
> +
> +static acpi_status acpi_query_osc(acpi_handle handle, u32 level,
> +						void *context, void **retval)
> +{
> +	pci_acpi_osc_support(handle, (unsigned long)context);
>  	return AE_OK;
>  }
>  
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 21f2ac6..44d00c9 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -2037,8 +2037,6 @@ static int __devinit pci_init(void)
>  		pci_fixup_device(pci_fixup_final, dev);
>  	}
>  
> -	msi_init();
> -
>  	return 0;
>  }
>  
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 9de87e9..b205ab8 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -98,11 +98,9 @@ extern unsigned int pci_pm_d3_delay;
>  #ifdef CONFIG_PCI_MSI
>  void pci_no_msi(void);
>  extern void pci_msi_init_pci_dev(struct pci_dev *dev);
> -extern void __devinit msi_init(void);
>  #else
>  static inline void pci_no_msi(void) { }
>  static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
> -static inline void msi_init(void) { }
>  #endif
>  
>  #ifdef CONFIG_PCIEAER
> diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
> index 6dd7b13..ebce26c 100644
> --- a/drivers/pci/pcie/aer/aerdrv_acpi.c
> +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
> @@ -38,7 +38,6 @@ int aer_osc_setup(struct pcie_device *pciedev)
>  
>  	handle = acpi_find_root_bridge_handle(pdev);
>  	if (handle) {
> -		pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
>  		status = pci_osc_control_set(handle,
>  					OSC_PCI_EXPRESS_AER_CONTROL |
>  					OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
> diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
> index 8f63f4c..2c87883 100644
> --- a/drivers/pci/pcie/aspm.c
> +++ b/drivers/pci/pcie/aspm.c
> @@ -833,25 +833,3 @@ void pcie_no_aspm(void)
>  	if (!aspm_force)
>  		aspm_disabled = 1;
>  }
> -
> -#ifdef CONFIG_ACPI
> -#include <acpi/acpi_bus.h>
> -#include <linux/pci-acpi.h>
> -static void pcie_aspm_platform_init(void)
> -{
> -	pcie_osc_support_set(OSC_ACTIVE_STATE_PWR_SUPPORT|
> -		OSC_CLOCK_PWR_CAPABILITY_SUPPORT);
> -}
> -#else
> -static inline void pcie_aspm_platform_init(void) { }
> -#endif
> -
> -static int __init pcie_aspm_init(void)
> -{
> -	if (aspm_disabled)
> -		return 0;
> -	pcie_aspm_platform_init();
> -	return 0;
> -}
> -

I suspect the following was not supposed to be included.

> -fs_initcall(pcie_aspm_init);
> diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
> index d1fcd7e..ec048d3 100644
> --- a/drivers/scsi/sym53c8xx_2/sym_glue.c
> +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
> @@ -605,17 +605,17 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
>   * interrupt.  This can happen for a number of reasons, including buggy
>   * hardware and interrupt handler failures.
>   */
> -static enum scsi_eh_timer_return sym53c8xx_eh_timed_out(struct scsi_cmnd *cmd)
> +static enum blk_eh_timer_return sym53c8xx_eh_timed_out(struct scsi_cmnd *cmd)
>  {
>  	static int printed_warning;
>  	int result = sym53c8xx_intr(0, cmd->device->host);
>  
>  	if (result == IRQ_NONE)
> -		return EH_NOT_HANDLED;
> +		return BLK_EH_NOT_HANDLED;
>  
>  	/* When commands have been handled, host_data is set to NULL */
>  	if (cmd->host_data)
> -		return EH_NOT_HANDLED;
> +		return BLK_EH_NOT_HANDLED;
>  
>  	if (!printed_warning) {
>  		scmd_printk(KERN_ERR, cmd, "Command timed out and was "
> @@ -624,7 +624,7 @@ static enum scsi_eh_timer_return sym53c8xx_eh_timed_out(struct scsi_cmnd *cmd)
>  		printed_warning = 1;
>  	}
>  
> -	return EH_HANDLED;
> +	return BLK_EH_HANDLED;
>  }
>  

Separate patch?

>  static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd)
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index 8837928..424f06f 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -8,6 +8,8 @@
>  #ifndef _PCI_ACPI_H_
>  #define _PCI_ACPI_H_
>  
> +#include <linux/acpi.h>
> +
>  #define OSC_QUERY_TYPE			0
>  #define OSC_SUPPORT_TYPE 		1
>  #define OSC_CONTROL_TYPE		2
> @@ -49,6 +51,7 @@
>  #ifdef CONFIG_ACPI
>  extern acpi_status pci_osc_control_set(acpi_handle handle, u32 flags);
>  extern acpi_status __pci_osc_support_set(u32 flags, const char *hid);
> +int pci_acpi_osc_support(acpi_handle handle, u32 flags);
>  static inline acpi_status pci_osc_support_set(u32 flags)
>  {
>  	return __pci_osc_support_set(flags, PCI_ROOT_HID_STRING);

Andrew


  reply	other threads:[~2008-10-27 16:12 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-10-25  5:30 Doing _OSC right Matthew Wilcox
2008-10-27 16:12 ` Andrew Patterson [this message]
2008-10-27 16:31   ` Andrew Patterson

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=1225123939.6725.83.camel@grinch \
    --to=andrew.patterson@hp.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=matthew@wil.cx \
    /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.