Re: [PATCH v2] acpi: Populate DIDL before registering ACPI video device on Intel

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

 



On Thu, 2009-03-19 at 21:35 +0000, Matthew Garrett wrote:
> [ACPI] Populate DIDL before registering ACPI video device on Intel
> 
> Intel graphics hardware that implements the ACPI IGD OpRegion spec 
> requires that the list of display devices be populated before any ACPI 
> video methods are called. Detect when this is the case and defer 
> registration until the opregion code calls it. Fixes crashes on HP 
> laptops as seen in kernel bugzilla #11259.
>     
> Signed-off-by: Matthew Garrett <mjg@xxxxxxxxxx>

As far as DRM changes,

Acked-by: Eric Anholt <eric@xxxxxxxxxx>

(I'm assuming this'll go through the ACPI tree)


> ---
> 
> This version fixes an attempted re-registration of the video device on 
> resume.
> 
> diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
> index bb5ed05..64e987c 100644
> --- a/drivers/acpi/video.c
> +++ b/drivers/acpi/video.c
> @@ -37,6 +37,8 @@
>  #include <linux/thermal.h>
>  #include <linux/video_output.h>
>  #include <linux/sort.h>
> +#include <linux/pci.h>
> +#include <linux/pci_ids.h>
>  #include <asm/uaccess.h>
>  
>  #include <acpi/acpi_bus.h>
> @@ -2124,7 +2126,27 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
>  	return 0;
>  }
>  
> -static int __init acpi_video_init(void)
> +static int __init intel_opregion_present(void)
> +{
> +#if defined(CONFIG_DRM_I915) || defined(CONFIG_DRM_I915_MODULE)
> +	struct pci_dev *dev = NULL;
> +	u32 address;
> +
> +	for_each_pci_dev(dev) {
> +		if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
> +			continue;
> +		if (dev->vendor != PCI_VENDOR_ID_INTEL)
> +			continue;
> +		pci_read_config_dword(dev, 0xfc, &address);
> +		if (!address)
> +			continue;
> +		return 1;
> +	}
> +#endif
> +	return 0;
> +}
> +
> +int acpi_video_register(void)
>  {
>  	int result = 0;
>  
> @@ -2141,6 +2163,22 @@ static int __init acpi_video_init(void)
>  
>  	return 0;
>  }
> +EXPORT_SYMBOL(acpi_video_register);
> +
> +/*
> + * This is kind of nasty. Hardware using Intel chipsets may require
> + * the video opregion code to be run first in order to initialise
> + * state before any ACPI video calls are made. To handle this we defer
> + * registration of the video class until the opregion code has run.
> + */
> +
> +static int __init acpi_video_init(void)
> +{
> +	if (intel_opregion_present())
> +		return 0;
> +
> +	return acpi_video_register();
> +}
>  
>  static void __exit acpi_video_exit(void)
>  {
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 6dab63b..5881b6a 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1144,8 +1144,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>  	if (!IS_I945G(dev) && !IS_I945GM(dev))
>  		pci_enable_msi(dev->pdev);
>  
> -	intel_opregion_init(dev);
> -
>  	spin_lock_init(&dev_priv->user_irq_lock);
>  	dev_priv->user_irq_refcount = 0;
>  
> @@ -1164,6 +1162,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>  		}
>  	}
>  
> +	/* Must be done after probing outputs */
> +	intel_opregion_init(dev, 0);
> +
>  	return 0;
>  
>  out_iomapfree:
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index b293ef0..209592f 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -99,7 +99,7 @@ static int i915_resume(struct drm_device *dev)
>  
>  	i915_restore_state(dev);
>  
> -	intel_opregion_init(dev);
> +	intel_opregion_init(dev, 1);
>  
>  	/* KMS EnterVT equivalent */
>  	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 17fa408..aee6f9e 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -654,7 +654,7 @@ extern int i915_restore_state(struct drm_device *dev);
>  
>  #ifdef CONFIG_ACPI
>  /* i915_opregion.c */
> -extern int intel_opregion_init(struct drm_device *dev);
> +extern int intel_opregion_init(struct drm_device *dev, int resume);
>  extern void intel_opregion_free(struct drm_device *dev);
>  extern void opregion_asle_intr(struct drm_device *dev);
>  extern void opregion_enable_asle(struct drm_device *dev);
> diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c
> index ff01283..6942772 100644
> --- a/drivers/gpu/drm/i915/i915_opregion.c
> +++ b/drivers/gpu/drm/i915/i915_opregion.c
> @@ -26,6 +26,7 @@
>   */
>  
>  #include <linux/acpi.h>
> +#include <acpi/video.h>
>  
>  #include "drmP.h"
>  #include "i915_drm.h"
> @@ -136,6 +137,12 @@ struct opregion_asle {
>  
>  #define ASLE_CBLV_VALID         (1<<31)
>  
> +#define ACPI_OTHER_OUTPUT (0<<8)
> +#define ACPI_VGA_OUTPUT (1<<8)
> +#define ACPI_TV_OUTPUT (2<<8)
> +#define ACPI_DIGITAL_OUTPUT (3<<8)
> +#define ACPI_LVDS_OUTPUT (4<<8)
> +
>  static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -282,7 +289,58 @@ static struct notifier_block intel_opregion_notifier = {
>  	.notifier_call = intel_opregion_video_event,
>  };
>  
> -int intel_opregion_init(struct drm_device *dev)
> +/*
> + * Initialise the DIDL field in opregion. This passes a list of devices to
> + * the firmware. Values are defined by section B.4.2 of the ACPI specification
> + * (version 3)
> + */
> +
> +static void intel_didl_outputs(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_opregion *opregion = &dev_priv->opregion;
> +	struct drm_connector *connector;
> +	int i = 0;
> +
> +	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
> +		int output_type = ACPI_OTHER_OUTPUT;
> +		if (i >= 8) {
> +			dev_printk (KERN_ERR, &dev->pdev->dev,
> +				    "More than 8 outputs detected\n");
> +			return;
> +		}
> +		switch (connector->connector_type) {
> +		case DRM_MODE_CONNECTOR_VGA:
> +		case DRM_MODE_CONNECTOR_DVIA:
> +			output_type = ACPI_VGA_OUTPUT;
> +			break;
> +		case DRM_MODE_CONNECTOR_Composite:
> +		case DRM_MODE_CONNECTOR_SVIDEO:
> +		case DRM_MODE_CONNECTOR_Component:
> +		case DRM_MODE_CONNECTOR_9PinDIN:
> +			output_type = ACPI_TV_OUTPUT;
> +			break;
> +		case DRM_MODE_CONNECTOR_DVII:
> +		case DRM_MODE_CONNECTOR_DVID:
> +		case DRM_MODE_CONNECTOR_DisplayPort:
> +		case DRM_MODE_CONNECTOR_HDMIA:
> +		case DRM_MODE_CONNECTOR_HDMIB:
> +			output_type = ACPI_DIGITAL_OUTPUT;
> +			break;
> +		case DRM_MODE_CONNECTOR_LVDS:
> +			output_type = ACPI_LVDS_OUTPUT;
> +			break;
> +		}
> +		opregion->acpi->didl[i] |= (1<<31) | output_type | i;
> +		i++;
> +	}
> +
> +	/* If fewer than 8 outputs, the list must be null terminated */
> +	if (i < 8)
> +		opregion->acpi->didl[i] = 0;
> +}
> +
> +int intel_opregion_init(struct drm_device *dev, int resume)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct intel_opregion *opregion = &dev_priv->opregion;
> @@ -312,6 +370,11 @@ int intel_opregion_init(struct drm_device *dev)
>  	if (mboxes & MBOX_ACPI) {
>  		DRM_DEBUG("Public ACPI methods supported\n");
>  		opregion->acpi = base + OPREGION_ACPI_OFFSET;
> +		if (drm_core_check_feature(dev, DRIVER_MODESET)) {
> +			intel_didl_outputs(dev);
> +			if (!resume)
> +				acpi_video_register();
> +		}
>  	} else {
>  		DRM_DEBUG("Public ACPI methods not supported\n");
>  		err = -ENOTSUPP;
> diff --git a/include/acpi/video.h b/include/acpi/video.h
> new file mode 100644
> index 0000000..f0275bb
> --- /dev/null
> +++ b/include/acpi/video.h
> @@ -0,0 +1,11 @@
> +#ifndef __ACPI_VIDEO_H
> +#define __ACPI_VIDEO_H
> +
> +#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
> +extern int acpi_video_register(void);
> +#else
> +static inline int acpi_video_register(void) { return 0; }
> +#endif
> +
> +#endif
> +
> 
-- 
Eric Anholt
eric@xxxxxxxxxx                         eric.anholt@xxxxxxxxx


Attachment: signature.asc
Description: This is a digitally signed message part


[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux