Re: [PATCH 3/7] PCI / PCIe: Ask BIOS for control of all native services at once (v5)

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

 



(2010/07/31 7:32), Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@xxxxxxx>
> 
> PCIe port service drivers ask the BIOS, through _OSC, for control of
> the services they handle.  Unfortunately, each of them individually
> asks for control of the PCIe capability structure and if that is
> granted, some BIOSes expect that the other PCIe port services will be
> configured and handled by the kernel as well.  If that is not the
> case (eg. one of the PCIe port service drivers is not loaded), the
> BIOS may be confused and may cause the system as a whole to misbehave
> (eg. on one of such systems enabling the native PCIe PME service
> without loading the native PCIe hot-plug service driver causes a
> storm of ACPI notify requests to appear).
> 
> For this reason rework the PCIe port driver so that (1) it checks
> which native PCIe port services can be enabled, according to the
> BIOS, and (2) it requests control of all these services
> simultaneously.  In particular, this causes pcie_portdrv_probe() to
> fail if the BIOS refuses to grant control of the PCIe capability
> structure, which means that no native PCIe port services can be
> enabled for the PCIe root complex the given port belongs to.
> 
> Make it possible to override this behavior using a new command line
> switch pcie_ports= that can be set to 'auto' (ask the BIOS, the
> default), 'native' (use the PCIe native services regardless of the
> BIOS response to the control request), or 'compat' (do not use the
> PCIe native services at all).
> 
> Accordingly, rework the existing PCIe port service drivers so that
> they don't request control of the services directly.
> 
> Signed-off-by: Rafael J. Wysocki <rjw@xxxxxxx>
> ---

It seems that this patch still have more than one logical changes.

I think that "pcie_ports=compat" has an independent function, so
it could be in a separated patch.

Maybe we can have 2 patches (at least) before this change:
 [1] aerdrv: introduce pci_aer_available()
 [2] portdrv: introduce pcie_ports=
      'compat' to disable all port services
 [3] (this patch)

>  Documentation/kernel-parameters.txt  |   17 ++++--
>  drivers/pci/hotplug/acpi_pcihp.c     |    4 -
>  drivers/pci/hotplug/pciehp.h         |   12 ----
>  drivers/pci/hotplug/pciehp_acpi.c    |    4 -
>  drivers/pci/hotplug/pciehp_core.c    |    4 -
>  drivers/pci/pci.h                    |    2 
>  drivers/pci/pcie/Makefile            |    3 -
>  drivers/pci/pcie/aer/aerdrv.c        |    9 ++-
>  drivers/pci/pcie/aer/aerdrv_acpi.c   |   36 --------------
>  drivers/pci/pcie/aer/aerdrv_core.c   |   14 -----
>  drivers/pci/pcie/pme/Makefile        |    8 ---
>  drivers/pci/pcie/pme/pcie_pme.c      |   64 ++-----------------------
>  drivers/pci/pcie/pme/pcie_pme.h      |   28 -----------
>  drivers/pci/pcie/pme/pcie_pme_acpi.c |   54 ---------------------
>  drivers/pci/pcie/portdrv.h           |   22 ++++++++
>  drivers/pci/pcie/portdrv_acpi.c      |   87 +++++++++++++++++++++++++++++++++++
>  drivers/pci/pcie/portdrv_core.c      |   25 ++++++++--
>  drivers/pci/pcie/portdrv_pci.c       |   30 ++++++++++++
>  18 files changed, 191 insertions(+), 232 deletions(-)
> 
> Index: linux-2.6/drivers/pci/pcie/portdrv_pci.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pcie/portdrv_pci.c
> +++ linux-2.6/drivers/pci/pcie/portdrv_pci.c
> @@ -29,6 +29,32 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
>  MODULE_DESCRIPTION(DRIVER_DESC);
>  MODULE_LICENSE("GPL");
>  
> +/* If this switch is set, PCIe port native services should not be enabled. */
> +bool pcie_ports_disabled;
> +
> +/*
> + * If this switch is set, ACPI _OSC will be used to determine whether or not to
> + * enable PCIe port native services.
> + */
> +bool pcie_ports_auto = true;
> +
> +static int __init pcie_port_setup(char *str)
> +{
> +	if (!strncmp(str, "auto", 4)) {
> +		pcie_ports_disabled = false;
> +		pcie_ports_auto = true;
> +	} else if (!strncmp(str, "native", 6)) {
> +		pcie_ports_disabled = false;
> +		pcie_ports_auto = false;
> +	} else if (!strncmp(str, "compat", 6)) {
> +		pcie_ports_disabled = true;
> +		pcie_ports_auto = false;
> +	}
> +
> +	return 1;
> +}
> +__setup("pcie_ports=", pcie_port_setup);
> +
>  /* global data */
>  
>  static int pcie_portdrv_restore_config(struct pci_dev *dev)
> @@ -82,6 +108,7 @@ static int __devinit pcie_portdrv_probe(
>  		dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; "
>  			 "check vendor BIOS\n", dev->vendor, dev->device);
>  	}
> +
>  	status = pcie_port_device_register(dev);
>  	if (status)
>  		return status;

A blank line?

> @@ -301,6 +328,9 @@ static int __init pcie_portdrv_init(void
>  {
>  	int retval;
>  
> +	if (pcie_ports_disabled)
> +		return -EACCES;
> +
>  	dmi_check_system(pcie_portdrv_dmi_table);
>  
>  	retval = pcie_port_bus_register();
> Index: linux-2.6/drivers/pci/pcie/portdrv_acpi.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6/drivers/pci/pcie/portdrv_acpi.c
> @@ -0,0 +1,87 @@
> +/*
> + * PCIe Port Native Services Support, ACPI-Related Part
> + *
> + * Copyright (C) 2010 Rafael J. Wysocki <rjw@xxxxxxx>, Novell Inc.
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License V2.  See the file "COPYING" in the main directory of this archive
> + * for more details.
> + */
> +
> +#include <linux/pci.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/acpi.h>
> +#include <linux/pci-acpi.h>
> +#include <linux/pcieport_if.h>
> +
> +#include "aer/aerdrv.h"
> +#include "../pci.h"
> +
> +/**
> + * pcie_port_acpi_setup - Request the BIOS to release control of PCIe services.
> + * @port: PCIe Port service for a root port or event collector.
> + * @srv_mask: Bit mask of services that can be enabled for @port.
> + *
> + * Invoked when @port is identified as a PCIe port device.  To avoid conflicts
> + * with the BIOS PCIe port native services support requires the BIOS to yield
> + * control of these services to the kernel.  The mask of services that the BIOS
> + * allows to be enabled for @port is written to @srv_mask.
> + *
> + * NOTE: It turns out that we cannot do that for individual port services
> + * separately, because that would make some systems work incorrectly.
> + */
> +int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
> +{
> +	acpi_status status;
> +	acpi_handle handle;
> +	u32 flags;
> +
> +	if (acpi_pci_disabled)
> +		return 0;
> +
> +	handle = acpi_find_root_bridge_handle(port);
> +	if (!handle)
> +		return -EINVAL;
> +
> +	flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
> +		| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
> +		| OSC_PCI_EXPRESS_PME_CONTROL;
> +
> +	if (pcie_aer_get_firmware_first(port))
> +		dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
> +	else if (pci_aer_available())
> +		flags |= OSC_PCI_EXPRESS_AER_CONTROL;

Debug message will not be interested when AER is not available.
(and of course when AER is disabled intentionally)
How about:

if (pci_aer_available()) {
	if (pcie_aer_get_firmware_first(port))
		dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
	else
		flags |= OSC_PCI_EXPRESS_AER_CONTROL;
}

> +
> +	status = acpi_pci_root_osc_query(handle, &flags);
> +	if (ACPI_FAILURE(status)) {
> +		dev_dbg(&port->dev, "ACPI _OSC query failed (code %d)\n",
> +			status);
> +		return -ENODEV;
> +	}
> +
> +	if (!(flags & OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)) {
> +		dev_dbg(&port->dev, "BIOS refuses to grant control of PCIe "
> +			"Capability Structure\n");
> +		return -EACCES;
> +	}
> +
> +	status = acpi_pci_osc_control_set(handle, flags);
> +	if (ACPI_FAILURE(status)) {
> +		dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n",
> +			status);
> +		return -ENODEV;
> +	}
> +
> +	dev_info(&port->dev, "ACPI _OSC control granted for 0x%02x\n", flags);
> +
> +	*srv_mask = PCIE_PORT_SERVICE_VC;
> +	if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)
> +		*srv_mask |= PCIE_PORT_SERVICE_HP;
> +	if (flags & OSC_PCI_EXPRESS_PME_CONTROL)
> +		*srv_mask |= PCIE_PORT_SERVICE_PME;
> +	if (flags & OSC_PCI_EXPRESS_AER_CONTROL)
> +		*srv_mask |= PCIE_PORT_SERVICE_AER;
> +
> +	return 0;
> +}
> Index: linux-2.6/drivers/pci/pcie/portdrv.h
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pcie/portdrv.h
> +++ linux-2.6/drivers/pci/pcie/portdrv.h
> @@ -20,6 +20,9 @@
>  
>  #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
>  
> +extern bool pcie_ports_disabled;
> +extern bool pcie_ports_auto;
> +
>  extern struct bus_type pcie_port_bus_type;
>  extern int pcie_port_device_register(struct pci_dev *dev);
>  #ifdef CONFIG_PM
> @@ -30,6 +33,8 @@ extern void pcie_port_device_remove(stru
>  extern int __must_check pcie_port_bus_register(void);
>  extern void pcie_port_bus_unregister(void);
>  
> +struct pci_dev;
> +
>  #ifdef CONFIG_PCIE_PME
>  extern bool pcie_pme_msi_disabled;
>  
> @@ -42,9 +47,26 @@ static inline bool pcie_pme_no_msi(void)
>  {
>  	return pcie_pme_msi_disabled;
>  }
> +
> +extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable);
>  #else /* !CONFIG_PCIE_PME */
>  static inline void pcie_pme_disable_msi(void) {}
>  static inline bool pcie_pme_no_msi(void) { return false; }
> +static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
>  #endif /* !CONFIG_PCIE_PME */
>  
> +#ifdef CONFIG_ACPI
> +extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask);
> +
> +static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
> +{
> +	return pcie_port_acpi_setup(port, mask);
> +}
> +#else /* !CONFIG_ACPI */
> +static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
> +{
> +	return 0;
> +}
> +#endif /* !CONFIG_ACPI */
> +
>  #endif /* _PORTDRV_H_ */
> Index: linux-2.6/drivers/pci/pcie/Makefile
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pcie/Makefile
> +++ linux-2.6/drivers/pci/pcie/Makefile
> @@ -6,10 +6,11 @@
>  obj-$(CONFIG_PCIEASPM)		+= aspm.o
>  
>  pcieportdrv-y			:= portdrv_core.o portdrv_pci.o portdrv_bus.o
> +pcieportdrv-$(CONFIG_ACPI)	+= portdrv_acpi.o
>  
>  obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
>  
>  # Build PCI Express AER if needed
>  obj-$(CONFIG_PCIEAER)		+= aer/
>  
> -obj-$(CONFIG_PCIE_PME) += pme/
> +obj-$(CONFIG_PCIE_PME) += pme/pcie_pme.o
> Index: linux-2.6/drivers/pci/pcie/portdrv_core.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pcie/portdrv_core.c
> +++ linux-2.6/drivers/pci/pcie/portdrv_core.c
> @@ -14,6 +14,7 @@
>  #include <linux/string.h>
>  #include <linux/slab.h>
>  #include <linux/pcieport_if.h>
> +#include <linux/aer.h>
>  
>  #include "../pci.h"
>  #include "portdrv.h"
> @@ -236,23 +237,38 @@ static int get_port_device_capability(st
>  	int services = 0, pos;
>  	u16 reg16;
>  	u32 reg32;
> +	int cap_mask;
> +	int err;
> +
> +	err = pcie_port_platform_notify(dev, &cap_mask);
> +	if (pcie_ports_auto) {
> +		if (err)
> +			return 0;
> +	} else {
> +		cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
> +				| PCIE_PORT_SERVICE_VC;
> +		if (pci_aer_available())
> +			cap_mask |= PCIE_PORT_SERVICE_AER;
> +	}
>  
>  	pos = pci_pcie_cap(dev);
>  	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
>  	/* Hot-Plug Capable */
> -	if (reg16 & PCI_EXP_FLAGS_SLOT) {
> +	if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) {
>  		pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32);
>  		if (reg32 & PCI_EXP_SLTCAP_HPC)
>  			services |= PCIE_PORT_SERVICE_HP;
>  	}
>  	/* AER capable */
> -	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
> +	if ((cap_mask & PCIE_PORT_SERVICE_AER)
> +	    && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
>  		services |= PCIE_PORT_SERVICE_AER;
>  	/* VC support */
>  	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
>  		services |= PCIE_PORT_SERVICE_VC;
>  	/* Root ports are capable of generating PME too */
> -	if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
> +	if ((cap_mask & PCIE_PORT_SERVICE_PME)
> +	    && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
>  		services |= PCIE_PORT_SERVICE_PME;
>  
>  	return services;
> @@ -494,6 +510,9 @@ static void pcie_port_shutdown_service(s
>   */
>  int pcie_port_service_register(struct pcie_port_service_driver *new)
>  {
> +	if (pcie_ports_disabled)
> +		return -ENODEV;
> +
>  	new->driver.name = (char *)new->name;
>  	new->driver.bus = &pcie_port_bus_type;
>  	new->driver.probe = pcie_port_probe_service;
> Index: linux-2.6/drivers/pci/pcie/pme/pcie_pme.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pcie/pme/pcie_pme.c
> +++ linux-2.6/drivers/pci/pcie/pme/pcie_pme.c
> @@ -24,37 +24,12 @@
>  #include <linux/pm_runtime.h>
>  
>  #include "../../pci.h"
> -#include "pcie_pme.h"
> +#include "../portdrv.h"
>  
>  #define PCI_EXP_RTSTA_PME	0x10000 /* PME status */
>  #define PCI_EXP_RTSTA_PENDING	0x20000 /* PME pending */
>  
>  /*
> - * If set, this switch will prevent the PCIe root port PME service driver from
> - * being registered.  Consequently, the interrupt-based PCIe PME signaling will
> - * not be used by any PCIe root ports in that case.
> - */
> -static bool pcie_pme_disabled = true;
> -
> -/*
> - * The PCI Express Base Specification 2.0, Section 6.1.8, states the following:
> - * "In order to maintain compatibility with non-PCI Express-aware system
> - * software, system power management logic must be configured by firmware to use
> - * the legacy mechanism of signaling PME by default.  PCI Express-aware system
> - * software must notify the firmware prior to enabling native, interrupt-based
> - * PME signaling."  However, if the platform doesn't provide us with a suitable
> - * notification mechanism or the notification fails, it is not clear whether or
> - * not we are supposed to use the interrupt-based PCIe PME signaling.  The
> - * switch below can be used to indicate the desired behaviour.  When set, it
> - * will make the kernel use the interrupt-based PCIe PME signaling regardless of
> - * the platform notification status, although the kernel will attempt to notify
> - * the platform anyway.  When unset, it will prevent the kernel from using the
> - * the interrupt-based PCIe PME signaling if the platform notification fails,
> - * which is the default.
> - */
> -static bool pcie_pme_force_enable;
> -
> -/*
>   * If this switch is set, MSI will not be used for PCIe PME signaling.  This
>   * causes the PCIe port driver to use INTx interrupts only, but it turns out
>   * that using MSI for PCIe PME signaling doesn't play well with PCIe PME-based
> @@ -64,38 +39,13 @@ bool pcie_pme_msi_disabled;
>  
>  static int __init pcie_pme_setup(char *str)
>  {
> -	if (!strncmp(str, "auto", 4))
> -		pcie_pme_disabled = false;
> -	else if (!strncmp(str, "force", 5))
> -		pcie_pme_force_enable = true;
> -
> -	str = strchr(str, ',');
> -	if (str) {
> -		str++;
> -		str += strspn(str, " \t");
> -		if (*str && !strcmp(str, "nomsi"))
> -			pcie_pme_msi_disabled = true;
> -	}
> +	if (!strncmp(str, "nomsi", 5))
> +		pcie_pme_msi_disabled = true;
>  
>  	return 1;
>  }
>  __setup("pcie_pme=", pcie_pme_setup);
>  
> -/**
> - * pcie_pme_platform_setup - Ensure that the kernel controls the PCIe PME.
> - * @srv: PCIe PME root port service to use for carrying out the check.
> - *
> - * Notify the platform that the native PCIe PME is going to be used and return
> - * 'true' if the control of the PCIe PME registers has been acquired from the
> - * platform.
> - */
> -static bool pcie_pme_platform_setup(struct pcie_device *srv)
> -{
> -	if (!pcie_pme_platform_notify(srv))
> -		return true;
> -	return pcie_pme_force_enable;
> -}
> -
>  struct pcie_pme_service_data {
>  	spinlock_t lock;
>  	struct pcie_device *srv;
> @@ -108,7 +58,7 @@ struct pcie_pme_service_data {
>   * @dev: PCIe root port or event collector.
>   * @enable: Enable or disable the interrupt.
>   */
> -static void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable)
> +void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable)
>  {
>  	int rtctl_pos;
>  	u16 rtctl;
> @@ -417,9 +367,6 @@ static int pcie_pme_probe(struct pcie_de
>  	struct pcie_pme_service_data *data;
>  	int ret;
>  
> -	if (!pcie_pme_platform_setup(srv))
> -		return -EACCES;
> -
>  	data = kzalloc(sizeof(*data), GFP_KERNEL);
>  	if (!data)
>  		return -ENOMEM;
> @@ -509,8 +456,7 @@ static struct pcie_port_service_driver p
>   */
>  static int __init pcie_pme_service_init(void)
>  {
> -	return pcie_pme_disabled ?
> -		-ENODEV : pcie_port_service_register(&pcie_pme_driver);
> +	return pcie_port_service_register(&pcie_pme_driver);
>  }
>  
>  module_init(pcie_pme_service_init);
> Index: linux-2.6/drivers/pci/pcie/pme/pcie_pme.h
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pcie/pme/pcie_pme.h
> +++ /dev/null
> @@ -1,28 +0,0 @@
> -/*
> - * drivers/pci/pcie/pme/pcie_pme.h
> - *
> - * PCI Express Root Port PME signaling support
> - *
> - * Copyright (C) 2009 Rafael J. Wysocki <rjw@xxxxxxx>, Novell Inc.
> - */
> -
> -#ifndef _PCIE_PME_H_
> -#define _PCIE_PME_H_
> -
> -struct pcie_device;
> -
> -#ifdef CONFIG_ACPI
> -extern int pcie_pme_acpi_setup(struct pcie_device *srv);
> -
> -static inline int pcie_pme_platform_notify(struct pcie_device *srv)
> -{
> -	return pcie_pme_acpi_setup(srv);
> -}
> -#else /* !CONFIG_ACPI */
> -static inline int pcie_pme_platform_notify(struct pcie_device *srv)
> -{
> -	return 0;
> -}
> -#endif /* !CONFIG_ACPI */
> -
> -#endif
> Index: linux-2.6/drivers/pci/pcie/pme/pcie_pme_acpi.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pcie/pme/pcie_pme_acpi.c
> +++ /dev/null
> @@ -1,54 +0,0 @@
> -/*
> - * PCIe Native PME support, ACPI-related part
> - *
> - * Copyright (C) 2009 Rafael J. Wysocki <rjw@xxxxxxx>, Novell Inc.
> - *
> - * This file is subject to the terms and conditions of the GNU General Public
> - * License V2.  See the file "COPYING" in the main directory of this archive
> - * for more details.
> - */
> -
> -#include <linux/pci.h>
> -#include <linux/kernel.h>
> -#include <linux/errno.h>
> -#include <linux/acpi.h>
> -#include <linux/pci-acpi.h>
> -#include <linux/pcieport_if.h>
> -
> -/**
> - * pcie_pme_acpi_setup - Request the ACPI BIOS to release control over PCIe PME.
> - * @srv - PCIe PME service for a root port or event collector.
> - *
> - * Invoked when the PCIe bus type loads PCIe PME service driver.  To avoid
> - * conflict with the BIOS PCIe support requires the BIOS to yield PCIe PME
> - * control to the kernel.
> - */
> -int pcie_pme_acpi_setup(struct pcie_device *srv)
> -{
> -	acpi_status status = AE_NOT_FOUND;
> -	struct pci_dev *port = srv->port;
> -	acpi_handle handle;
> -	int error = 0;
> -
> -	if (acpi_pci_disabled)
> -		return -ENOSYS;
> -
> -	dev_info(&port->dev, "Requesting control of PCIe PME from ACPI BIOS\n");
> -
> -	handle = acpi_find_root_bridge_handle(port);
> -	if (!handle)
> -		return -EINVAL;
> -
> -	status = acpi_pci_osc_control_set(handle,
> -			OSC_PCI_EXPRESS_PME_CONTROL |
> -			OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
> -	if (ACPI_FAILURE(status)) {
> -		dev_info(&port->dev,
> -			"Failed to receive control of PCIe PME service: %s\n",
> -			(status == AE_SUPPORT || status == AE_NOT_FOUND) ?
> -			"no _OSC support" : "ACPI _OSC failed");
> -		error = -ENODEV;
> -	}
> -
> -	return error;
> -}
> Index: linux-2.6/drivers/pci/pcie/pme/Makefile
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pcie/pme/Makefile
> +++ /dev/null
> @@ -1,8 +0,0 @@
> -#
> -# Makefile for PCI-Express Root Port PME signaling driver
> -#
> -
> -obj-$(CONFIG_PCIE_PME) += pmedriver.o
> -
> -pmedriver-objs := pcie_pme.o
> -pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o
> Index: linux-2.6/drivers/pci/pcie/aer/aerdrv_acpi.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pcie/aer/aerdrv_acpi.c
> +++ linux-2.6/drivers/pci/pcie/aer/aerdrv_acpi.c
> @@ -19,42 +19,6 @@
>  #include <acpi/apei.h>
>  #include "aerdrv.h"
>  
> -/**
> - * aer_osc_setup - run ACPI _OSC method
> - * @pciedev: pcie_device which AER is being enabled on
> - *
> - * @return: Zero on success. Nonzero otherwise.
> - *
> - * Invoked when PCIe bus loads AER service driver. To avoid conflict with
> - * BIOS AER support requires BIOS to yield AER control to OS native driver.
> - **/
> -int aer_osc_setup(struct pcie_device *pciedev)
> -{
> -	acpi_status status = AE_NOT_FOUND;
> -	struct pci_dev *pdev = pciedev->port;
> -	acpi_handle handle = NULL;
> -
> -	if (acpi_pci_disabled)
> -		return -1;
> -
> -	handle = acpi_find_root_bridge_handle(pdev);
> -	if (handle) {
> -		status = acpi_pci_osc_control_set(handle,
> -					OSC_PCI_EXPRESS_AER_CONTROL |
> -					OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
> -	}
> -
> -	if (ACPI_FAILURE(status)) {
> -		dev_printk(KERN_DEBUG, &pciedev->device, "AER service couldn't "
> -			   "init device: %s\n",
> -			   (status == AE_SUPPORT || status == AE_NOT_FOUND) ?
> -			   "no _OSC support" : "_OSC failed");
> -		return -1;
> -	}
> -
> -	return 0;
> -}
> -
>  #ifdef CONFIG_ACPI_APEI
>  static inline int hest_match_pci(struct acpi_hest_aer_common *p,
>  				 struct pci_dev *pci)
> Index: linux-2.6/drivers/pci/pcie/aer/aerdrv_core.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pcie/aer/aerdrv_core.c
> +++ linux-2.6/drivers/pci/pcie/aer/aerdrv_core.c
> @@ -771,22 +771,10 @@ void aer_isr(struct work_struct *work)
>   */
>  int aer_init(struct pcie_device *dev)
>  {
> -	if (pcie_aer_get_firmware_first(dev->port)) {
> -		dev_printk(KERN_DEBUG, &dev->device,
> -			   "PCIe errors handled by platform firmware.\n");
> -		goto out;
> -	}
> -
> -	if (aer_osc_setup(dev))
> -		goto out;
> -
> -	return 0;
> -out:
>  	if (forceload) {
>  		dev_printk(KERN_DEBUG, &dev->device,
>  			   "aerdrv forceload requested.\n");
>  		pcie_aer_force_firmware_first(dev->port, 0);
> -		return 0;
>  	}
> -	return -ENXIO;
> +	return 0;
>  }
> Index: linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/hotplug/acpi_pcihp.c
> +++ linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
> @@ -338,9 +338,7 @@ int acpi_get_hp_hw_control_from_firmware
>  	acpi_handle chandle, handle;
>  	struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
>  
> -	flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
> -		  OSC_SHPC_NATIVE_HP_CONTROL |
> -		  OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
> +	flags &= OSC_SHPC_NATIVE_HP_CONTROL;
>  	if (!flags) {
>  		err("Invalid flags %u specified!\n", flags);
>  		return -EINVAL;
> Index: linux-2.6/drivers/pci/hotplug/pciehp.h
> ===================================================================
> --- linux-2.6.orig/drivers/pci/hotplug/pciehp.h
> +++ linux-2.6/drivers/pci/hotplug/pciehp.h
> @@ -176,19 +176,7 @@ static inline void pciehp_firmware_init(
>  {
>  	pciehp_acpi_slot_detection_init();
>  }
> -
> -static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
> -{
> -	int retval;
> -	u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
> -		     OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
> -	retval = acpi_get_hp_hw_control_from_firmware(dev, flags);
> -	if (retval)
> -		return retval;
> -	return pciehp_acpi_slot_detection_check(dev);
> -}
>  #else
>  #define pciehp_firmware_init()				do {} while (0)
> -#define pciehp_get_hp_hw_control_from_firmware(dev) 	0
>  #endif 				/* CONFIG_ACPI */
>  #endif				/* _PCIEHP_H */
> Index: linux-2.6/drivers/pci/hotplug/pciehp_core.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/hotplug/pciehp_core.c
> +++ linux-2.6/drivers/pci/hotplug/pciehp_core.c
> @@ -59,7 +59,7 @@ module_param(pciehp_force, bool, 0644);
>  MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
>  MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
>  MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
> -MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing");
> +MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if OSHP is missing");
>  
>  #define PCIE_MODULE_NAME "pciehp"
>  
> @@ -235,7 +235,7 @@ static int pciehp_probe(struct pcie_devi
>  		dev_info(&dev->device,
>  			 "Bypassing BIOS check for pciehp use on %s\n",
>  			 pci_name(dev->port));
> -	else if (pciehp_get_hp_hw_control_from_firmware(dev->port))
> +	else if (pciehp_acpi_slot_detection_check(dev->port))
>  		goto err_out_none;
>  
>  	ctrl = pcie_init(dev);
> Index: linux-2.6/drivers/pci/hotplug/pciehp_acpi.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/hotplug/pciehp_acpi.c
> +++ linux-2.6/drivers/pci/hotplug/pciehp_acpi.c
> @@ -85,9 +85,7 @@ static int __init dummy_probe(struct pci
>  	acpi_handle handle;
>  	struct dummy_slot *slot, *tmp;
>  	struct pci_dev *pdev = dev->port;
> -	/* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
> -	if (pciehp_get_hp_hw_control_from_firmware(pdev))
> -		return -ENODEV;
> +
>  	pos = pci_pcie_cap(pdev);
>  	if (!pos)
>  		return -ENODEV;
> Index: linux-2.6/Documentation/kernel-parameters.txt
> ===================================================================
> --- linux-2.6.orig/Documentation/kernel-parameters.txt
> +++ linux-2.6/Documentation/kernel-parameters.txt
> @@ -2047,15 +2047,18 @@ and is between 256 and 4096 characters. 
>  		force	Enable ASPM even on devices that claim not to support it.
>  			WARNING: Forcing ASPM on may cause system lockups.
>  
> +	pcie_ports=	[PCIE] PCIe ports handling:
> +		auto	Ask the BIOS whether or not to use native PCIe services
> +			associated with PCIe ports (PME, hot-plug, AER).  Use
> +			them only if that is allowed by the BIOS.
> +		native	Use native PCIe services associated with PCIe ports
> +			unconditionally.
> +		compat	Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe
> +			ports driver.
> +
>  	pcie_pme=	[PCIE,PM] Native PCIe PME signaling options:
> -			Format: {auto|force}[,nomsi]
> -		auto	Use native PCIe PME signaling if the BIOS allows the
> -			kernel to control PCIe config registers of root ports.
> -		force	Use native PCIe PME signaling even if the BIOS refuses
> -			to allow the kernel to control the relevant PCIe config
> -			registers.
>  		nomsi	Do not use MSI for native PCIe PME signaling (this makes
> -			all PCIe root ports use INTx for everything).
> +			all PCIe root ports use INTx for all services).
>  
>  	pcmv=		[HW,PCMCIA] BadgePAD 4
>  
> Index: linux-2.6/drivers/pci/pci.h
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pci.h
> +++ linux-2.6/drivers/pci/pci.h
> @@ -131,8 +131,10 @@ static inline void pci_msi_init_pci_dev(
>  
>  #ifdef CONFIG_PCIEAER
>  void pci_no_aer(void);
> +bool pci_aer_available(void);
>  #else
>  static inline void pci_no_aer(void) { }
> +static inline bool pci_aer_available(void) { return false; }
>  #endif
>  
>  static inline int pci_no_d1d2(struct pci_dev *dev)
> Index: linux-2.6/drivers/pci/pcie/aer/aerdrv.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pcie/aer/aerdrv.c
> +++ linux-2.6/drivers/pci/pcie/aer/aerdrv.c
> @@ -72,6 +72,11 @@ void pci_no_aer(void)
>  	pcie_aer_disable = 1;	/* has priority over 'forceload' */
>  }
>  
> +bool pci_aer_available(void)
> +{
> +	return !pcie_aer_disable && pci_msi_enabled();
> +}
> +
>  static int set_device_error_reporting(struct pci_dev *dev, void *data)
>  {
>  	bool enable = *((bool *)data);
> @@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_
>   */
>  static int __init aer_service_init(void)
>  {
> -	if (pcie_aer_disable)
> -		return -ENXIO;
> -	if (!pci_msi_enabled())
> +	if (pci_aer_available())
>  		return -ENXIO;

Please continue initialization if aer is available.

if (!pci_aer_available())

Thanks,
H.Seto

>  	return pcie_port_service_register(&aerdriver);
>  }
> 
> --
> 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
> 
> 

_______________________________________________
linux-pm mailing list
linux-pm@xxxxxxxxxxxxxxxxxxxxxxxxxx
https://lists.linux-foundation.org/mailman/listinfo/linux-pm


[Index of Archives]     [Linux ACPI]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [CPU Freq]     [Kernel Newbies]     [Fedora Kernel]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux