[PATCH 2/2] UBUNTU: SAUCE: i915: enable MCHBAR if needed

Stefan Bader stefan.bader at canonical.com
Thu May 7 09:25:27 UTC 2009


Andy Whitcroft wrote:
> From: Jesse Barnes <jbarnes at virtuousgeek.org>
> 
> BugLink: http://bugs.launchpad.net/bugs/349314
> 
> Using the new PNP resource checking code, this patch allows the i915
> driver to allocate MCHBAR space if needed and use the BAR to determine
> current memory settings.
> 
> [apw at canonical.com: moved to the new generic PNP resource interface]
> Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
> Signed-off-by: Andy Whitcroft <apw at canonical.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h        |    2 +
>  drivers/gpu/drm/i915/i915_gem_tiling.c |  145 ++++++++++++++++++++++++++++++++
>  2 files changed, 147 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 1b16482..a522c55 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -122,6 +122,8 @@ typedef struct drm_i915_private {
>  	drm_local_map_t hws_map;
>  	struct drm_gem_object *hws_obj;
>  
> +	struct resource mch_res;
> +
>  	unsigned int cpp;
>  	int back_offset;
>  	int front_offset;
> diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
> index a8cb694..63ff07b 100644
> --- a/drivers/gpu/drm/i915/i915_gem_tiling.c
> +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
> @@ -24,6 +24,8 @@
>   *    Eric Anholt <eric at anholt.net>
>   *
>   */
> +#include <linux/acpi.h>
> +#include <linux/pnp.h>
>  
>  #include "drmP.h"
>  #include "drm.h"
> @@ -79,6 +81,143 @@
>   * to match what the GPU expects.
>   */
>  
> +#define MCHBAR_I915 0x44
> +#define MCHBAR_I965 0x48
> +#define MCHBAR_SIZE (4*4096)
> +
> +#define DEVEN_REG 0x54
> +#define   DEVEN_MCHBAR_EN (1 << 28)
> +
> +/* Allocate space for the MCH regs if needed, return nonzero on error */
> +static int
> +intel_alloc_mchbar_resource(struct drm_device *dev)
> +{
> +	struct pci_dev *bridge_dev;
> +	drm_i915_private_t *dev_priv = dev->dev_private;
> +	int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
> +	u32 temp_lo, temp_hi = 0;
> +	u64 mchbar_addr;
> +	int ret = 0;
> +
> +	bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
> +	if (!bridge_dev) {
> +		DRM_DEBUG("no bridge dev?!\n");
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	if (IS_I965G(dev))
> +		pci_read_config_dword(bridge_dev, reg + 4, &temp_hi);
> +	pci_read_config_dword(bridge_dev, reg, &temp_lo);
> +	mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
> +
> +	/* If ACPI doesn't have it, assume we need to allocate it ourselves */
> +	if (mchbar_addr &&
> +	    pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
> +		ret = 0;
> +		goto out_put;
> +	}
> +
> +	/* Get some space for it */
> +	ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res,
> +				     MCHBAR_SIZE, MCHBAR_SIZE,
> +				     PCIBIOS_MIN_MEM,
> +				     0,   pcibios_align_resource,
> +				     bridge_dev);
> +	if (ret) {
> +		DRM_DEBUG("failed bus alloc: %d\n", ret);
> +		dev_priv->mch_res.start = 0;
> +		goto out_put;
> +	}
> +
> +	if (IS_I965G(dev))
> +		pci_write_config_dword(bridge_dev, reg + 4,
> +				       upper_32_bits(dev_priv->mch_res.start));
> +
> +	pci_write_config_dword(bridge_dev, reg,
> +			       lower_32_bits(dev_priv->mch_res.start));
> +out_put:
> +	pci_dev_put(bridge_dev);
> +out:
> +	return ret;
> +}
> +
> +/* Setup MCHBAR if possible, return true if we should disable it again */
> +static bool
> +intel_setup_mchbar(struct drm_device *dev)
> +{
> +	struct pci_dev *bridge_dev;
> +	int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
> +	u32 temp;
> +	bool need_disable = false, enabled;
> +
> +	bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
> +	if (!bridge_dev) {
> +		DRM_DEBUG("no bridge dev?!\n");
> +		goto out;
> +	}
> +
> +	if (IS_I915G(dev) || IS_I915GM(dev)) {
> +		pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
> +		enabled = !!(temp & DEVEN_MCHBAR_EN);
> +	} else {
> +		pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
> +		enabled = temp & 1;
> +	}
> +
> +	/* If it's already enabled, don't have to do anything */
> +	if (enabled)
> +		goto out_put;
> +
> +	if (intel_alloc_mchbar_resource(dev))
> +		goto out_put;
> +
> +	need_disable = true;
> +
> +	/* Space is allocated or reserved, so enable it. */
> +	if (IS_I915G(dev) || IS_I915GM(dev)) {
> +		pci_write_config_dword(bridge_dev, DEVEN_REG,
> +				       temp | DEVEN_MCHBAR_EN);
> +	} else {
> +		pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
> +		pci_write_config_dword(bridge_dev, mchbar_reg, temp | 1);
> +	}
> +out_put:
> +	pci_dev_put(bridge_dev);
> +out:
> +	return need_disable;
> +}
> +
> +static void
> +intel_teardown_mchbar(struct drm_device *dev, bool disable)
> +{
> +	drm_i915_private_t *dev_priv = dev->dev_private;
> +	struct pci_dev *bridge_dev;
> +	int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
> +	u32 temp;
> +
> +	bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
> +	if (!bridge_dev) {
> +		DRM_DEBUG("no bridge dev?!\n");
> +		return;
> +	}
> +
> +	if (disable) {
> +		if (IS_I915G(dev) || IS_I915GM(dev)) {
> +			pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
> +			temp &= ~DEVEN_MCHBAR_EN;
> +			pci_write_config_dword(bridge_dev, DEVEN_REG, temp);
> +		} else {
> +			pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
> +			temp &= ~1;
> +			pci_write_config_dword(bridge_dev, mchbar_reg, temp);
> +		}
> +	}
> +
> +	if (dev_priv->mch_res.start)
> +		release_resource(&dev_priv->mch_res);
> +}
> +
>  /**
>   * Detects bit 6 swizzling of address lookup between IGD access and CPU
>   * access through main memory.
> @@ -89,6 +228,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
>  	drm_i915_private_t *dev_priv = dev->dev_private;
>  	uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
>  	uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
> +	bool need_disable;
>  
>  	if (!IS_I9XX(dev)) {
>  		/* As far as we know, the 865 doesn't have these bit 6
> @@ -100,6 +240,9 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
>  		   IS_GM45(dev)) {
>  		uint32_t dcc;
>  
> +		/* Try to make sure MCHBAR is enabled before poking at it */
> +		need_disable = intel_setup_mchbar(dev);
> +
>  		/* On 915-945 and GM965, channel interleave by the CPU is
>  		 * determined by DCC.  The CPU will alternate based on bit 6
>  		 * in interleaved mode, and the GPU will then also alternate
> @@ -139,6 +282,8 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
>  			swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
>  			swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
>  		}
> +
> +		intel_teardown_mchbar(dev, need_disable);
>  	} else {
>  		/* The 965, G33, and newer, have a very flexible memory
>  		 * configuration.  It will enable dual-channel mode
Based on the user comments ACK as well. Before I pull I give it a quick test on 
my Acer as well.

-- 

When all other means of communication fail, try words!






More information about the kernel-team mailing list