diff options
50 files changed, 1164 insertions, 848 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e43eb1a9d8c..ee63a123235 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2104,7 +2104,7 @@ int drm_mode_addfb(struct drm_device *dev,  	fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);  	if (IS_ERR(fb)) { -		DRM_ERROR("could not create framebuffer\n"); +		DRM_DEBUG_KMS("could not create framebuffer\n");  		ret = PTR_ERR(fb);  		goto out;  	} @@ -2193,7 +2193,7 @@ static int framebuffer_check(struct drm_mode_fb_cmd2 *r)  	ret = format_check(r);  	if (ret) { -		DRM_ERROR("bad framebuffer format 0x%08x\n", r->pixel_format); +		DRM_DEBUG_KMS("bad framebuffer format 0x%08x\n", r->pixel_format);  		return ret;  	} @@ -2202,12 +2202,12 @@ static int framebuffer_check(struct drm_mode_fb_cmd2 *r)  	num_planes = drm_format_num_planes(r->pixel_format);  	if (r->width == 0 || r->width % hsub) { -		DRM_ERROR("bad framebuffer width %u\n", r->height); +		DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height);  		return -EINVAL;  	}  	if (r->height == 0 || r->height % vsub) { -		DRM_ERROR("bad framebuffer height %u\n", r->height); +		DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);  		return -EINVAL;  	} @@ -2215,12 +2215,12 @@ static int framebuffer_check(struct drm_mode_fb_cmd2 *r)  		unsigned int width = r->width / (i != 0 ? hsub : 1);  		if (!r->handles[i]) { -			DRM_ERROR("no buffer object handle for plane %d\n", i); +			DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);  			return -EINVAL;  		}  		if (r->pitches[i] < drm_format_plane_cpp(r->pixel_format, i) * width) { -			DRM_ERROR("bad pitch %u for plane %d\n", r->pitches[i], i); +			DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);  			return -EINVAL;  		}  	} @@ -2257,12 +2257,12 @@ int drm_mode_addfb2(struct drm_device *dev,  		return -EINVAL;  	if ((config->min_width > r->width) || (r->width > config->max_width)) { -		DRM_ERROR("bad framebuffer width %d, should be >= %d && <= %d\n", +		DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",  			  r->width, config->min_width, config->max_width);  		return -EINVAL;  	}  	if ((config->min_height > r->height) || (r->height > config->max_height)) { -		DRM_ERROR("bad framebuffer height %d, should be >= %d && <= %d\n", +		DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",  			  r->height, config->min_height, config->max_height);  		return -EINVAL;  	} @@ -2275,7 +2275,7 @@ int drm_mode_addfb2(struct drm_device *dev,  	fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);  	if (IS_ERR(fb)) { -		DRM_ERROR("could not create framebuffer\n"); +		DRM_DEBUG_KMS("could not create framebuffer\n");  		ret = PTR_ERR(fb);  		goto out;  	} diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile index 1583982917c..dd7d6b57996 100644 --- a/drivers/gpu/drm/gma500/Makefile +++ b/drivers/gpu/drm/gma500/Makefile @@ -1,7 +1,7 @@  #  #	KMS driver for the GMA500  # -ccflags-y += -Iinclude/drm +ccflags-y += -I$(srctree)/include/drm  gma500_gfx-y += gem_glue.o \  	  accel_2d.o \ @@ -12,8 +12,8 @@ gma500_gfx-y += gem_glue.o \  	  intel_bios.o \  	  intel_i2c.o \  	  intel_gmbus.o \ -	  intel_opregion.o \  	  mmu.o \ +	  opregion.o \  	  power.o \  	  psb_drv.o \  	  psb_intel_display.o \ diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c index 62f9b735459..c10f02068d1 100644 --- a/drivers/gpu/drm/gma500/cdv_device.c +++ b/drivers/gpu/drm/gma500/cdv_device.c @@ -57,8 +57,7 @@ static int cdv_output_init(struct drm_device *dev)  	cdv_intel_crt_init(dev, &dev_priv->mode_dev);  	cdv_intel_lvds_init(dev, &dev_priv->mode_dev); -	/* These bits indicate HDMI not SDVO on CDV, but we don't yet support -	   the HDMI interface */ +	/* These bits indicate HDMI not SDVO on CDV */  	if (REG_READ(SDVOB) & SDVO_DETECTED)  		cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOB);  	if (REG_READ(SDVOC) & SDVO_DETECTED) @@ -69,76 +68,71 @@ static int cdv_output_init(struct drm_device *dev)  #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE  /* - *	Poulsbo Backlight Interfaces + *	Cedartrail Backlght Interfaces   */ -#define BLC_PWM_PRECISION_FACTOR 100	/* 10000000 */ -#define BLC_PWM_FREQ_CALC_CONSTANT 32 -#define MHz 1000000 - -#define PSB_BLC_PWM_PRECISION_FACTOR    10 -#define PSB_BLC_MAX_PWM_REG_FREQ        0xFFFE -#define PSB_BLC_MIN_PWM_REG_FREQ        0x2 - -#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) -#define PSB_BACKLIGHT_PWM_CTL_SHIFT	(16) - -static int cdv_brightness;  static struct backlight_device *cdv_backlight_device; -static int cdv_get_brightness(struct backlight_device *bd) +static int cdv_backlight_combination_mode(struct drm_device *dev)  { -	/* return locally cached var instead of HW read (due to DPST etc.) */ -	/* FIXME: ideally return actual value in case firmware fiddled with -	   it */ -	return cdv_brightness; +	return REG_READ(BLC_PWM_CTL2) & PWM_LEGACY_MODE;  } - -static int cdv_backlight_setup(struct drm_device *dev) +static int cdv_get_brightness(struct backlight_device *bd)  { -	struct drm_psb_private *dev_priv = dev->dev_private; -	unsigned long core_clock; -	/* u32 bl_max_freq; */ -	/* unsigned long value; */ -	u16 bl_max_freq; -	uint32_t value; -	uint32_t blc_pwm_precision_factor; +	struct drm_device *dev = bl_get_data(bd); +	u32 val = REG_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; -	/* get bl_max_freq and pol from dev_priv*/ -	if (!dev_priv->lvds_bl) { -		dev_err(dev->dev, "Has no valid LVDS backlight info\n"); -		return -ENOENT; -	} -	bl_max_freq = dev_priv->lvds_bl->freq; -	blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR; +	if (cdv_backlight_combination_mode(dev)) { +		u8 lbpc; -	core_clock = dev_priv->core_freq; +		val &= ~1; +		pci_read_config_byte(dev->pdev, 0xF4, &lbpc); +		val *= lbpc; +	} +	return val; +} -	value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT; -	value *= blc_pwm_precision_factor; -	value /= bl_max_freq; -	value /= blc_pwm_precision_factor; +static u32 cdv_get_max_backlight(struct drm_device *dev) +{ +	u32 max = REG_READ(BLC_PWM_CTL); -	if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ || -		 value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ) -				return -ERANGE; -	else { -		/* FIXME */ +	if (max == 0) { +		DRM_DEBUG_KMS("LVDS Panel PWM value is 0!\n"); +		/* i915 does this, I believe which means that we should not +		 * smash PWM control as firmware will take control of it. */ +		return 1;  	} -	return 0; + +	max >>= 16; +	if (cdv_backlight_combination_mode(dev)) +		max *= 0xff; +	return max;  }  static int cdv_set_brightness(struct backlight_device *bd)  { +	struct drm_device *dev = bl_get_data(bd);  	int level = bd->props.brightness; +	u32 blc_pwm_ctl;  	/* Percentage 1-100% being valid */  	if (level < 1)  		level = 1; -	/*cdv_intel_lvds_set_brightness(dev, level); FIXME */ -	cdv_brightness = level; +	if (cdv_backlight_combination_mode(dev)) { +		u32 max = cdv_get_max_backlight(dev); +		u8 lbpc; + +		lbpc = level * 0xfe / max + 1; +		level /= lbpc; + +		pci_write_config_byte(dev->pdev, 0xF4, lbpc); +	} + +	blc_pwm_ctl = REG_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; +	REG_WRITE(BLC_PWM_CTL, (blc_pwm_ctl | +				(level << BACKLIGHT_DUTY_CYCLE_SHIFT)));  	return 0;  } @@ -150,7 +144,6 @@ static const struct backlight_ops cdv_ops = {  static int cdv_backlight_init(struct drm_device *dev)  {  	struct drm_psb_private *dev_priv = dev->dev_private; -	int ret;  	struct backlight_properties props;  	memset(&props, 0, sizeof(struct backlight_properties)); @@ -162,14 +155,9 @@ static int cdv_backlight_init(struct drm_device *dev)  	if (IS_ERR(cdv_backlight_device))  		return PTR_ERR(cdv_backlight_device); -	ret = cdv_backlight_setup(dev); -	if (ret < 0) { -		backlight_device_unregister(cdv_backlight_device); -		cdv_backlight_device = NULL; -		return ret; -	} -	cdv_backlight_device->props.brightness = 100; -	cdv_backlight_device->props.max_brightness = 100; +	cdv_backlight_device->props.brightness = +			cdv_get_brightness(cdv_backlight_device); +	cdv_backlight_device->props.max_brightness = cdv_get_max_backlight(dev);  	backlight_update_status(cdv_backlight_device);  	dev_priv->backlight_device = cdv_backlight_device;  	return 0; @@ -244,11 +232,12 @@ static void cdv_init_pm(struct drm_device *dev)  static void cdv_errata(struct drm_device *dev)  {  	/* Disable bonus launch. -	 *	CPU and GPU competes for memory and display misses updates and flickers. -	 *	Worst with dual core, dual displays. +	 *	CPU and GPU competes for memory and display misses updates and +	 *	flickers. Worst with dual core, dual displays.  	 * -	 *	Fixes were done to Win 7 gfx driver to disable a feature called Bonus -	 *	Launch to work around the issue, by degrading performance. +	 *	Fixes were done to Win 7 gfx driver to disable a feature called +	 *	Bonus Launch to work around the issue, by degrading +	 *	performance.  	 */  	 CDV_MSG_WRITE32(3, 0x30, 0x08027108);  } @@ -501,7 +490,7 @@ static int cdv_chip_setup(struct drm_device *dev)  	struct drm_psb_private *dev_priv = dev->dev_private;  	INIT_WORK(&dev_priv->hotplug_work, cdv_hotplug_work_func);  	cdv_get_core_freq(dev); -	gma_intel_opregion_init(dev); +	psb_intel_opregion_init(dev);  	psb_intel_init_bios(dev);  	cdv_hotplug_enable(dev, false);  	return 0; diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index 44a8353d92b..ff5b58eb878 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -556,7 +556,7 @@ static void cdv_intel_lvds_enc_destroy(struct drm_encoder *encoder)  	drm_encoder_cleanup(encoder);  } -const struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = { +static const struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = {  	.destroy = cdv_intel_lvds_enc_destroy,  }; diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index c9fe4bdeb68..f47f883ff9e 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -408,6 +408,8 @@ static int psbfb_create(struct psb_fbdev *fbdev,  			return -ENOMEM;  	} +	memset(dev_priv->vram_addr + backing->offset, 0, size); +  	mutex_lock(&dev->struct_mutex);  	info = framebuffer_alloc(0, device); @@ -453,8 +455,7 @@ static int psbfb_create(struct psb_fbdev *fbdev,  	info->fix.ypanstep = 0;  	/* Accessed stolen memory directly */ -	info->screen_base = (char *)dev_priv->vram_addr + -							backing->offset; +	info->screen_base = dev_priv->vram_addr + backing->offset;  	info->screen_size = size;  	if (dev_priv->gtt.stolen_size) { @@ -571,7 +572,7 @@ static int psbfb_probe(struct drm_fb_helper *helper,  	return new_fb;  } -struct drm_fb_helper_funcs psb_fb_helper_funcs = { +static struct drm_fb_helper_funcs psb_fb_helper_funcs = {  	.gamma_set = psbfb_gamma_set,  	.gamma_get = psbfb_gamma_get,  	.fb_probe = psbfb_probe, diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c index 54e5c9e1e6f..4cd33df5f93 100644 --- a/drivers/gpu/drm/gma500/gtt.c +++ b/drivers/gpu/drm/gma500/gtt.c @@ -61,7 +61,7 @@ static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type)   *	Given a gtt_range object return the GTT offset of the page table   *	entries for this gtt_range   */ -static u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r) +static u32 __iomem *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)  {  	struct drm_psb_private *dev_priv = dev->dev_private;  	unsigned long offset; @@ -82,7 +82,8 @@ static u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)   */  static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)  { -	u32 *gtt_slot, pte; +	u32 __iomem *gtt_slot; +	u32 pte;  	struct page **pages;  	int i; @@ -126,7 +127,8 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)  static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r)  {  	struct drm_psb_private *dev_priv = dev->dev_private; -	u32 *gtt_slot, pte; +	u32 __iomem *gtt_slot; +	u32 pte;  	int i;  	WARN_ON(r->stolen); @@ -152,7 +154,8 @@ static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r)   */  void psb_gtt_roll(struct drm_device *dev, struct gtt_range *r, int roll)  { -	u32 *gtt_slot, pte; +	u32 __iomem *gtt_slot; +	u32 pte;  	int i;  	if (roll >= r->npage) { @@ -413,7 +416,6 @@ int psb_gtt_init(struct drm_device *dev, int resume)  	unsigned long stolen_size, vram_stolen_size;  	unsigned i, num_pages;  	unsigned pfn_base; -	uint32_t vram_pages;  	uint32_t dvmt_mode = 0;  	struct psb_gtt *pg; @@ -529,7 +531,7 @@ int psb_gtt_init(struct drm_device *dev, int resume)  	 */  	pfn_base = dev_priv->stolen_base >> PAGE_SHIFT; -	vram_pages = num_pages = vram_stolen_size >> PAGE_SHIFT; +	num_pages = vram_stolen_size >> PAGE_SHIFT;  	printk(KERN_INFO"Set up %d stolen pages starting at 0x%08x, GTT offset %dK\n",  		num_pages, pfn_base << PAGE_SHIFT, 0);  	for (i = 0; i < num_pages; ++i) { diff --git a/drivers/gpu/drm/gma500/intel_opregion.c b/drivers/gpu/drm/gma500/intel_opregion.c deleted file mode 100644 index 7041f40afff..00000000000 --- a/drivers/gpu/drm/gma500/intel_opregion.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * FIXME: resolve with the i915 version - */ - -#include "psb_drv.h" - -#define PCI_ASLE 0xe4 -#define PCI_ASLS 0xfc - -#define OPREGION_HEADER_OFFSET 0 -#define OPREGION_ACPI_OFFSET   0x100 -#define   ACPI_CLID 0x01ac /* current lid state indicator */ -#define   ACPI_CDCK 0x01b0 /* current docking state indicator */ -#define OPREGION_SWSCI_OFFSET  0x200 -#define OPREGION_ASLE_OFFSET   0x300 -#define OPREGION_VBT_OFFSET    0x400 - -#define OPREGION_SIGNATURE "IntelGraphicsMem" -#define MBOX_ACPI      (1<<0) -#define MBOX_SWSCI     (1<<1) -#define MBOX_ASLE      (1<<2) - -struct opregion_header { -	u8 signature[16]; -	u32 size; -	u32 opregion_ver; -	u8 bios_ver[32]; -	u8 vbios_ver[16]; -	u8 driver_ver[16]; -	u32 mboxes; -	u8 reserved[164]; -} __packed; - -/* OpRegion mailbox #1: public ACPI methods */ -struct opregion_acpi { -	u32 drdy;       /* driver readiness */ -	u32 csts;       /* notification status */ -	u32 cevt;       /* current event */ -	u8 rsvd1[20]; -	u32 didl[8];    /* supported display devices ID list */ -	u32 cpdl[8];    /* currently presented display list */ -	u32 cadl[8];    /* currently active display list */ -	u32 nadl[8];    /* next active devices list */ -	u32 aslp;       /* ASL sleep time-out */ -	u32 tidx;       /* toggle table index */ -	u32 chpd;       /* current hotplug enable indicator */ -	u32 clid;       /* current lid state*/ -	u32 cdck;       /* current docking state */ -	u32 sxsw;       /* Sx state resume */ -	u32 evts;       /* ASL supported events */ -	u32 cnot;       /* current OS notification */ -	u32 nrdy;       /* driver status */ -	u8 rsvd2[60]; -} __attribute__((packed)); - -/* OpRegion mailbox #2: SWSCI */ -struct opregion_swsci { -	u32 scic;       /* SWSCI command|status|data */ -	u32 parm;       /* command parameters */ -	u32 dslp;       /* driver sleep time-out */ -	u8 rsvd[244]; -} __attribute__((packed)); - -/* OpRegion mailbox #3: ASLE */ -struct opregion_asle { -	u32 ardy;       /* driver readiness */ -	u32 aslc;       /* ASLE interrupt command */ -	u32 tche;       /* technology enabled indicator */ -	u32 alsi;       /* current ALS illuminance reading */ -	u32 bclp;       /* backlight brightness to set */ -	u32 pfit;       /* panel fitting state */ -	u32 cblv;       /* current brightness level */ -	u16 bclm[20];   /* backlight level duty cycle mapping table */ -	u32 cpfm;       /* current panel fitting mode */ -	u32 epfm;       /* enabled panel fitting modes */ -	u8 plut[74];    /* panel LUT and identifier */ -	u32 pfmb;       /* PWM freq and min brightness */ -	u8 rsvd[102]; -} __attribute__((packed)); - -/* ASLE irq request bits */ -#define ASLE_SET_ALS_ILLUM     (1 << 0) -#define ASLE_SET_BACKLIGHT     (1 << 1) -#define ASLE_SET_PFIT          (1 << 2) -#define ASLE_SET_PWM_FREQ      (1 << 3) -#define ASLE_REQ_MSK           0xf - -/* response bits of ASLE irq request */ -#define ASLE_ALS_ILLUM_FAILED	(1<<10) -#define ASLE_BACKLIGHT_FAILED	(1<<12) -#define ASLE_PFIT_FAILED	(1<<14) -#define ASLE_PWM_FREQ_FAILED	(1<<16) - -/* ASLE backlight brightness to set */ -#define ASLE_BCLP_VALID                (1<<31) -#define ASLE_BCLP_MSK          (~(1<<31)) - -/* ASLE panel fitting request */ -#define ASLE_PFIT_VALID         (1<<31) -#define ASLE_PFIT_CENTER (1<<0) -#define ASLE_PFIT_STRETCH_TEXT (1<<1) -#define ASLE_PFIT_STRETCH_GFX (1<<2) - -/* PWM frequency and minimum brightness */ -#define ASLE_PFMB_BRIGHTNESS_MASK (0xff) -#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8) -#define ASLE_PFMB_PWM_MASK (0x7ffffe00) -#define ASLE_PFMB_PWM_VALID (1<<31) - -#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) - -int gma_intel_opregion_init(struct drm_device *dev) -{ -	struct drm_psb_private *dev_priv = dev->dev_private; -	struct psb_intel_opregion *opregion = &dev_priv->opregion; -	u32 opregion_phy; -	void *base; -	u32 *lid_state; - -	dev_priv->lid_state = NULL; - -	pci_read_config_dword(dev->pdev, 0xfc, &opregion_phy); -	if (opregion_phy == 0) -		return -ENOTSUPP; - -	base = ioremap(opregion_phy, 8*1024); -	if (!base) -		return -ENOMEM; -	/* FIXME: should use _io ops - ditto on i915 */ -	if (memcmp(base, OPREGION_SIGNATURE, 16)) { -		DRM_ERROR("opregion signature mismatch\n"); -		iounmap(base); -		return -EINVAL; -	} - -	lid_state = base + 0x01ac; - -	dev_priv->lid_state = lid_state; -	dev_priv->lid_last_state = readl(lid_state); -	opregion->header = base; -	opregion->vbt = base + OPREGION_VBT_OFFSET; -	return 0; -} - -int gma_intel_opregion_exit(struct drm_device *dev) -{ -	struct drm_psb_private *dev_priv = dev->dev_private; -	if (dev_priv->opregion.header) -		iounmap(dev_priv->opregion.header); -	return 0; -} diff --git a/drivers/gpu/drm/gma500/mdfld_device.c b/drivers/gpu/drm/gma500/mdfld_device.c index a0bd48cd92f..717f4db28c3 100644 --- a/drivers/gpu/drm/gma500/mdfld_device.c +++ b/drivers/gpu/drm/gma500/mdfld_device.c @@ -672,8 +672,8 @@ const struct psb_ops mdfld_chip_ops = {  	.accel_2d = 0,  	.pipes = 3,  	.crtcs = 3, -	.lvds_mask = (1 << 1); -	.hdmi_mask = (1 << 1); +	.lvds_mask = (1 << 1), +	.hdmi_mask = (1 << 1),  	.sgx_offset = MRST_SGX_OFFSET,  	.chip_setup = mid_chip_setup, diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c index d52358b744a..b34ff097b97 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c +++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c @@ -869,7 +869,6 @@ void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder,  		mdfld_set_pipe_timing(dsi_config, pipe);  		REG_WRITE(DSPABASE, 0x00); -		REG_WRITE(DSPASTRIDE, (mode->hdisplay * 4));  		REG_WRITE(DSPASIZE,  			((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); diff --git a/drivers/gpu/drm/gma500/mid_bios.c b/drivers/gpu/drm/gma500/mid_bios.c index 5eee9ad80da..b2a790bd989 100644 --- a/drivers/gpu/drm/gma500/mid_bios.c +++ b/drivers/gpu/drm/gma500/mid_bios.c @@ -118,139 +118,214 @@ static void mid_get_pci_revID(struct drm_psb_private *dev_priv)  					dev_priv->platform_rev_id);  } +struct vbt_header { +	u32 signature; +	u8 revision; +} __packed; + +/* The same for r0 and r1 */ +struct vbt_r0 { +	struct vbt_header vbt_header; +	u8 size; +	u8 checksum; +} __packed; + +struct vbt_r10 { +	struct vbt_header vbt_header; +	u8 checksum; +	u16 size; +	u8 panel_count; +	u8 primary_panel_idx; +	u8 secondary_panel_idx; +	u8 __reserved[5]; +} __packed; + +static int read_vbt_r0(u32 addr, struct vbt_r0 *vbt) +{ +	void __iomem *vbt_virtual; + +	vbt_virtual = ioremap(addr, sizeof(*vbt)); +	if (vbt_virtual == NULL) +		return -1; + +	memcpy_fromio(vbt, vbt_virtual, sizeof(*vbt)); +	iounmap(vbt_virtual); + +	return 0; +} + +static int read_vbt_r10(u32 addr, struct vbt_r10 *vbt) +{ +	void __iomem *vbt_virtual; + +	vbt_virtual = ioremap(addr, sizeof(*vbt)); +	if (!vbt_virtual) +		return -1; + +	memcpy_fromio(vbt, vbt_virtual, sizeof(*vbt)); +	iounmap(vbt_virtual); + +	return 0; +} + +static int mid_get_vbt_data_r0(struct drm_psb_private *dev_priv, u32 addr) +{ +	struct vbt_r0 vbt; +	void __iomem *gct_virtual; +	struct gct_r0 gct; +	u8 bpi; + +	if (read_vbt_r0(addr, &vbt)) +		return -1; + +	gct_virtual = ioremap(addr + sizeof(vbt), vbt.size - sizeof(vbt)); +	if (!gct_virtual) +		return -1; +	memcpy_fromio(&gct, gct_virtual, sizeof(gct)); +	iounmap(gct_virtual); + +	bpi = gct.PD.BootPanelIndex; +	dev_priv->gct_data.bpi = bpi; +	dev_priv->gct_data.pt = gct.PD.PanelType; +	dev_priv->gct_data.DTD = gct.panel[bpi].DTD; +	dev_priv->gct_data.Panel_Port_Control = +		gct.panel[bpi].Panel_Port_Control; +	dev_priv->gct_data.Panel_MIPI_Display_Descriptor = +		gct.panel[bpi].Panel_MIPI_Display_Descriptor; + +	return 0; +} + +static int mid_get_vbt_data_r1(struct drm_psb_private *dev_priv, u32 addr) +{ +	struct vbt_r0 vbt; +	void __iomem *gct_virtual; +	struct gct_r1 gct; +	u8 bpi; + +	if (read_vbt_r0(addr, &vbt)) +		return -1; + +	gct_virtual = ioremap(addr + sizeof(vbt), vbt.size - sizeof(vbt)); +	if (!gct_virtual) +		return -1; +	memcpy_fromio(&gct, gct_virtual, sizeof(gct)); +	iounmap(gct_virtual); + +	bpi = gct.PD.BootPanelIndex; +	dev_priv->gct_data.bpi = bpi; +	dev_priv->gct_data.pt = gct.PD.PanelType; +	dev_priv->gct_data.DTD = gct.panel[bpi].DTD; +	dev_priv->gct_data.Panel_Port_Control = +		gct.panel[bpi].Panel_Port_Control; +	dev_priv->gct_data.Panel_MIPI_Display_Descriptor = +		gct.panel[bpi].Panel_MIPI_Display_Descriptor; + +	return 0; +} + +static int mid_get_vbt_data_r10(struct drm_psb_private *dev_priv, u32 addr) +{ +	struct vbt_r10 vbt; +	void __iomem *gct_virtual; +	struct gct_r10 *gct; +	struct oaktrail_timing_info *dp_ti = &dev_priv->gct_data.DTD; +	struct gct_r10_timing_info *ti; +	int ret = -1; + +	if (read_vbt_r10(addr, &vbt)) +		return -1; + +	gct = kmalloc(sizeof(*gct) * vbt.panel_count, GFP_KERNEL); +	if (!gct) +		return -1; + +	gct_virtual = ioremap(addr + sizeof(vbt), +			sizeof(*gct) * vbt.panel_count); +	if (!gct_virtual) +		goto out; +	memcpy_fromio(gct, gct_virtual, sizeof(*gct)); +	iounmap(gct_virtual); + +	dev_priv->gct_data.bpi = vbt.primary_panel_idx; +	dev_priv->gct_data.Panel_MIPI_Display_Descriptor = +		gct[vbt.primary_panel_idx].Panel_MIPI_Display_Descriptor; + +	ti = &gct[vbt.primary_panel_idx].DTD; +	dp_ti->pixel_clock = ti->pixel_clock; +	dp_ti->hactive_hi = ti->hactive_hi; +	dp_ti->hactive_lo = ti->hactive_lo; +	dp_ti->hblank_hi = ti->hblank_hi; +	dp_ti->hblank_lo = ti->hblank_lo; +	dp_ti->hsync_offset_hi = ti->hsync_offset_hi; +	dp_ti->hsync_offset_lo = ti->hsync_offset_lo; +	dp_ti->hsync_pulse_width_hi = ti->hsync_pulse_width_hi; +	dp_ti->hsync_pulse_width_lo = ti->hsync_pulse_width_lo; +	dp_ti->vactive_hi = ti->vactive_hi; +	dp_ti->vactive_lo = ti->vactive_lo; +	dp_ti->vblank_hi = ti->vblank_hi; +	dp_ti->vblank_lo = ti->vblank_lo; +	dp_ti->vsync_offset_hi = ti->vsync_offset_hi; +	dp_ti->vsync_offset_lo = ti->vsync_offset_lo; +	dp_ti->vsync_pulse_width_hi = ti->vsync_pulse_width_hi; +	dp_ti->vsync_pulse_width_lo = ti->vsync_pulse_width_lo; + +	ret = 0; +out: +	kfree(gct); +	return ret; +} +  static void mid_get_vbt_data(struct drm_psb_private *dev_priv)  {  	struct drm_device *dev = dev_priv->dev; -	struct oaktrail_vbt *vbt = &dev_priv->vbt_data;  	u32 addr; -	u16 new_size; -	u8 *vbt_virtual; -	u8 bpi; -	u8 number_desc = 0; -	struct oaktrail_timing_info *dp_ti = &dev_priv->gct_data.DTD; -	struct gct_r10_timing_info ti; -	void *pGCT; +	u8 __iomem *vbt_virtual; +	struct vbt_header vbt_header;  	struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); +	int ret = -1; -	/* Get the address of the platform config vbt, B0:D2:F0;0xFC */ +	/* Get the address of the platform config vbt */  	pci_read_config_dword(pci_gfx_root, 0xFC, &addr);  	pci_dev_put(pci_gfx_root);  	dev_dbg(dev->dev, "drm platform config address is %x\n", addr); -	/* check for platform config address == 0. */ -	/* this means fw doesn't support vbt */ - -	if (addr == 0) { -		vbt->size = 0; -		return; -	} +	if (!addr) +		goto out;  	/* get the virtual address of the vbt */ -	vbt_virtual = ioremap(addr, sizeof(*vbt)); -	if (vbt_virtual == NULL) { -		vbt->size = 0; -		return; -	} +	vbt_virtual = ioremap(addr, sizeof(vbt_header)); +	if (!vbt_virtual) +		goto out; -	memcpy(vbt, vbt_virtual, sizeof(*vbt)); -	iounmap(vbt_virtual); /* Free virtual address space */ +	memcpy_fromio(&vbt_header, vbt_virtual, sizeof(vbt_header)); +	iounmap(vbt_virtual); -	/* No matching signature don't process the data */ -	if (memcmp(vbt->signature, "$GCT", 4)) { -		vbt->size = 0; -		return; -	} +	if (memcmp(&vbt_header.signature, "$GCT", 4)) +		goto out; -	dev_dbg(dev->dev, "GCT revision is %x\n", vbt->revision); +	dev_dbg(dev->dev, "GCT revision is %02x\n", vbt_header.revision); -	switch (vbt->revision) { -	case 0: -		vbt->oaktrail_gct = ioremap(addr + sizeof(*vbt) - 4, -					vbt->size - sizeof(*vbt) + 4); -		pGCT = vbt->oaktrail_gct; -		bpi = ((struct oaktrail_gct_v1 *)pGCT)->PD.BootPanelIndex; -		dev_priv->gct_data.bpi = bpi; -		dev_priv->gct_data.pt = -			((struct oaktrail_gct_v1 *)pGCT)->PD.PanelType; -		memcpy(&dev_priv->gct_data.DTD, -			&((struct oaktrail_gct_v1 *)pGCT)->panel[bpi].DTD, -				sizeof(struct oaktrail_timing_info)); -		dev_priv->gct_data.Panel_Port_Control = -		  ((struct oaktrail_gct_v1 *)pGCT)->panel[bpi].Panel_Port_Control; -		dev_priv->gct_data.Panel_MIPI_Display_Descriptor = -			((struct oaktrail_gct_v1 *)pGCT)->panel[bpi].Panel_MIPI_Display_Descriptor; +	switch (vbt_header.revision) { +	case 0x00: +		ret = mid_get_vbt_data_r0(dev_priv, addr);  		break; -	case 1: -		vbt->oaktrail_gct = ioremap(addr + sizeof(*vbt) - 4, -					vbt->size - sizeof(*vbt) + 4); -		pGCT = vbt->oaktrail_gct; -		bpi = ((struct oaktrail_gct_v2 *)pGCT)->PD.BootPanelIndex; -		dev_priv->gct_data.bpi = bpi; -		dev_priv->gct_data.pt = -			((struct oaktrail_gct_v2 *)pGCT)->PD.PanelType; -		memcpy(&dev_priv->gct_data.DTD, -			&((struct oaktrail_gct_v2 *)pGCT)->panel[bpi].DTD, -				sizeof(struct oaktrail_timing_info)); -		dev_priv->gct_data.Panel_Port_Control = -		  ((struct oaktrail_gct_v2 *)pGCT)->panel[bpi].Panel_Port_Control; -		dev_priv->gct_data.Panel_MIPI_Display_Descriptor = -			((struct oaktrail_gct_v2 *)pGCT)->panel[bpi].Panel_MIPI_Display_Descriptor; +	case 0x01: +		ret = mid_get_vbt_data_r1(dev_priv, addr);  		break;  	case 0x10: -		/*header definition changed from rev 01 (v2) to rev 10h. */ -		/*so, some values have changed location*/ -		new_size = vbt->checksum; /*checksum contains lo size byte*/ -		/*LSB of oaktrail_gct contains hi size byte*/ -		new_size |= ((0xff & (unsigned int)(long)vbt->oaktrail_gct)) << 8; - -		vbt->checksum = vbt->size; /*size contains the checksum*/ -		if (new_size > 0xff) -			vbt->size = 0xff; /*restrict size to 255*/ -		else -			vbt->size = new_size; - -		/* number of descriptors defined in the GCT */ -		number_desc = ((0xff00 & (unsigned int)(long)vbt->oaktrail_gct)) >> 8; -		bpi = ((0xff0000 & (unsigned int)(long)vbt->oaktrail_gct)) >> 16; -		vbt->oaktrail_gct = ioremap(addr + GCT_R10_HEADER_SIZE, -				GCT_R10_DISPLAY_DESC_SIZE * number_desc); -		pGCT = vbt->oaktrail_gct; -		pGCT = (u8 *)pGCT + (bpi*GCT_R10_DISPLAY_DESC_SIZE); -		dev_priv->gct_data.bpi = bpi; /*save boot panel id*/ - -		/*copy the GCT display timings into a temp structure*/ -		memcpy(&ti, pGCT, sizeof(struct gct_r10_timing_info)); - -		/*now copy the temp struct into the dev_priv->gct_data*/ -		dp_ti->pixel_clock = ti.pixel_clock; -		dp_ti->hactive_hi = ti.hactive_hi; -		dp_ti->hactive_lo = ti.hactive_lo; -		dp_ti->hblank_hi = ti.hblank_hi; -		dp_ti->hblank_lo = ti.hblank_lo; -		dp_ti->hsync_offset_hi = ti.hsync_offset_hi; -		dp_ti->hsync_offset_lo = ti.hsync_offset_lo; -		dp_ti->hsync_pulse_width_hi = ti.hsync_pulse_width_hi; -		dp_ti->hsync_pulse_width_lo = ti.hsync_pulse_width_lo; -		dp_ti->vactive_hi = ti.vactive_hi; -		dp_ti->vactive_lo = ti.vactive_lo; -		dp_ti->vblank_hi = ti.vblank_hi; -		dp_ti->vblank_lo = ti.vblank_lo; -		dp_ti->vsync_offset_hi = ti.vsync_offset_hi; -		dp_ti->vsync_offset_lo = ti.vsync_offset_lo; -		dp_ti->vsync_pulse_width_hi = ti.vsync_pulse_width_hi; -		dp_ti->vsync_pulse_width_lo = ti.vsync_pulse_width_lo; - -		/* Move the MIPI_Display_Descriptor data from GCT to dev priv */ -		dev_priv->gct_data.Panel_MIPI_Display_Descriptor = -							*((u8 *)pGCT + 0x0d); -		dev_priv->gct_data.Panel_MIPI_Display_Descriptor |= -						(*((u8 *)pGCT + 0x0e)) << 8; +		ret = mid_get_vbt_data_r10(dev_priv, addr);  		break;  	default:  		dev_err(dev->dev, "Unknown revision of GCT!\n"); -		vbt->size = 0;  	} + +out: +	if (ret) +		dev_err(dev->dev, "Unable to read GCT!"); +	else +		dev_priv->has_gct = true;  }  int mid_chip_setup(struct drm_device *dev) diff --git a/drivers/gpu/drm/gma500/oaktrail.h b/drivers/gpu/drm/gma500/oaktrail.h index 2da1f368f14..f2f9f38a536 100644 --- a/drivers/gpu/drm/gma500/oaktrail.h +++ b/drivers/gpu/drm/gma500/oaktrail.h @@ -19,14 +19,6 @@  /* MID device specific descriptors */ -struct oaktrail_vbt { -	s8 signature[4];	/*4 bytes,"$GCT" */ -	u8 revision; -	u8 size; -	u8 checksum; -	void *oaktrail_gct; -} __packed; -  struct oaktrail_timing_info {  	u16 pixel_clock;  	u8 hactive_lo; @@ -161,7 +153,7 @@ union oaktrail_panel_rx {  	u16 panel_receiver;  } __packed; -struct oaktrail_gct_v1 { +struct gct_r0 {  	union { /*8 bits,Defined as follows: */  		struct {  			u8 PanelType:4; /*4 bits, Bit field for panels*/ @@ -178,7 +170,7 @@ struct oaktrail_gct_v1 {  	union oaktrail_panel_rx panelrx[4]; /* panel receivers*/  } __packed; -struct oaktrail_gct_v2 { +struct gct_r1 {  	union { /*8 bits,Defined as follows: */  		struct {  			u8 PanelType:4; /*4 bits, Bit field for panels*/ @@ -195,6 +187,16 @@ struct oaktrail_gct_v2 {  	union oaktrail_panel_rx panelrx[4]; /* panel receivers*/  } __packed; +struct gct_r10 { +	struct gct_r10_timing_info DTD; +	u16 Panel_MIPI_Display_Descriptor; +	u16 Panel_MIPI_Receiver_Descriptor; +	u16 Panel_Backlight_Inverter_Descriptor; +	u8 Panel_Initial_Brightness; +	u32 MIPI_Ctlr_Init_ptr; +	u32 MIPI_Panel_Init_ptr; +} __packed; +  struct oaktrail_gct_data {  	u8 bpi; /* boot panel index, number of panel used during boot */  	u8 pt; /* panel type, 4 bit field, 0=lvds, 1=mipi */ @@ -213,9 +215,6 @@ struct oaktrail_gct_data {  #define MODE_SETTING_IN_DSR		0x4  #define MODE_SETTING_ENCODER_DONE	0x8 -#define GCT_R10_HEADER_SIZE		16 -#define GCT_R10_DISPLAY_DESC_SIZE	28 -  /*   *	Moorestown HDMI interfaces   */ diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c index 4c5a1864adf..0bb74cc3ecf 100644 --- a/drivers/gpu/drm/gma500/oaktrail_device.c +++ b/drivers/gpu/drm/gma500/oaktrail_device.c @@ -458,27 +458,26 @@ static int oaktrail_power_up(struct drm_device *dev)  static int oaktrail_chip_setup(struct drm_device *dev)  {  	struct drm_psb_private *dev_priv = dev->dev_private; -	struct oaktrail_vbt *vbt = &dev_priv->vbt_data;  	int ret; -	 +  	ret = mid_chip_setup(dev);  	if (ret < 0)  		return ret; -	if (vbt->size == 0) { +	if (!dev_priv->has_gct) {  		/* Now pull the BIOS data */ -		gma_intel_opregion_init(dev); +		psb_intel_opregion_init(dev);  		psb_intel_init_bios(dev);  	} +	oaktrail_hdmi_setup(dev);  	return 0;  }  static void oaktrail_teardown(struct drm_device *dev)  {  	struct drm_psb_private *dev_priv = dev->dev_private; -	struct oaktrail_vbt *vbt = &dev_priv->vbt_data;  	oaktrail_hdmi_teardown(dev); -	if (vbt->size == 0) +	if (!dev_priv->has_gct)  		psb_intel_destroy_bios(dev);  } diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c index 5e84fbde749..88627e3ba1e 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c @@ -250,7 +250,7 @@ static irqreturn_t oaktrail_hdmi_i2c_handler(int this_irq, void *dev)   */  static void oaktrail_hdmi_i2c_gpio_fix(void)  { -	void *base; +	void __iomem *base;  	unsigned int gpio_base = 0xff12c000;  	int gpio_len = 0x1000;  	u32 temp; diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index 654f32b22b2..558c77fb55e 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -257,7 +257,7 @@ static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev,  	mode_dev->panel_fixed_mode = NULL;  	/* Use the firmware provided data on Moorestown */ -	if (dev_priv->vbt_data.size != 0x00) { /*if non-zero, then use vbt*/ +	if (dev_priv->has_gct) {  		mode = kzalloc(sizeof(*mode), GFP_KERNEL);  		if (!mode)  			return; @@ -371,7 +371,7 @@ void oaktrail_lvds_init(struct drm_device *dev,  					BRIGHTNESS_MAX_LEVEL);  	mode_dev->panel_wants_dither = false; -	if (dev_priv->vbt_data.size != 0x00) +	if (dev_priv->has_gct)  		mode_dev->panel_wants_dither = (dev_priv->gct_data.  			Panel_Port_Control & MRST_PANEL_8TO6_DITHER_ENABLE);          if (dev_priv->lvds_dither) diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c new file mode 100644 index 00000000000..05661bfeac7 --- /dev/null +++ b/drivers/gpu/drm/gma500/opregion.c @@ -0,0 +1,350 @@ +/* + * Copyright 2011 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#include <linux/acpi_io.h> +#endif +#include "psb_drv.h" +#include "psb_intel_reg.h" + +#define PCI_ASLE 0xe4 +#define PCI_ASLS 0xfc + +#define OPREGION_HEADER_OFFSET 0 +#define OPREGION_ACPI_OFFSET   0x100 +#define   ACPI_CLID 0x01ac /* current lid state indicator */ +#define   ACPI_CDCK 0x01b0 /* current docking state indicator */ +#define OPREGION_SWSCI_OFFSET  0x200 +#define OPREGION_ASLE_OFFSET   0x300 +#define OPREGION_VBT_OFFSET    0x400 + +#define OPREGION_SIGNATURE "IntelGraphicsMem" +#define MBOX_ACPI      (1<<0) +#define MBOX_SWSCI     (1<<1) +#define MBOX_ASLE      (1<<2) + +struct opregion_header { +	u8 signature[16]; +	u32 size; +	u32 opregion_ver; +	u8 bios_ver[32]; +	u8 vbios_ver[16]; +	u8 driver_ver[16]; +	u32 mboxes; +	u8 reserved[164]; +} __packed; + +/* OpRegion mailbox #1: public ACPI methods */ +struct opregion_acpi { +	u32 drdy;	/* driver readiness */ +	u32 csts;	/* notification status */ +	u32 cevt;	/* current event */ +	u8 rsvd1[20]; +	u32 didl[8];	/* supported display devices ID list */ +	u32 cpdl[8];	/* currently presented display list */ +	u32 cadl[8];	/* currently active display list */ +	u32 nadl[8];	/* next active devices list */ +	u32 aslp;	/* ASL sleep time-out */ +	u32 tidx;	/* toggle table index */ +	u32 chpd;	/* current hotplug enable indicator */ +	u32 clid;	/* current lid state*/ +	u32 cdck;	/* current docking state */ +	u32 sxsw;	/* Sx state resume */ +	u32 evts;	/* ASL supported events */ +	u32 cnot;	/* current OS notification */ +	u32 nrdy;	/* driver status */ +	u8 rsvd2[60]; +} __packed; + +/* OpRegion mailbox #2: SWSCI */ +struct opregion_swsci { +	/*FIXME: add it later*/ +} __packed; + +/* OpRegion mailbox #3: ASLE */ +struct opregion_asle { +	u32 ardy;	/* driver readiness */ +	u32 aslc;	/* ASLE interrupt command */ +	u32 tche;	/* technology enabled indicator */ +	u32 alsi;	/* current ALS illuminance reading */ +	u32 bclp;	/* backlight brightness to set */ +	u32 pfit;	/* panel fitting state */ +	u32 cblv;	/* current brightness level */ +	u16 bclm[20];	/* backlight level duty cycle mapping table */ +	u32 cpfm;	/* current panel fitting mode */ +	u32 epfm;	/* enabled panel fitting modes */ +	u8 plut[74];	/* panel LUT and identifier */ +	u32 pfmb;	/* PWM freq and min brightness */ +	u8 rsvd[102]; +} __packed; + +/* ASLE irq request bits */ +#define ASLE_SET_ALS_ILLUM     (1 << 0) +#define ASLE_SET_BACKLIGHT     (1 << 1) +#define ASLE_SET_PFIT          (1 << 2) +#define ASLE_SET_PWM_FREQ      (1 << 3) +#define ASLE_REQ_MSK           0xf + +/* response bits of ASLE irq request */ +#define ASLE_ALS_ILLUM_FAILED   (1<<10) +#define ASLE_BACKLIGHT_FAILED   (1<<12) +#define ASLE_PFIT_FAILED        (1<<14) +#define ASLE_PWM_FREQ_FAILED    (1<<16) + +/* ASLE backlight brightness to set */ +#define ASLE_BCLP_VALID                (1<<31) +#define ASLE_BCLP_MSK          (~(1<<31)) + +/* ASLE panel fitting request */ +#define ASLE_PFIT_VALID         (1<<31) +#define ASLE_PFIT_CENTER (1<<0) +#define ASLE_PFIT_STRETCH_TEXT (1<<1) +#define ASLE_PFIT_STRETCH_GFX (1<<2) + +/* response bits of ASLE irq request */ +#define ASLE_ALS_ILLUM_FAILED	(1<<10) +#define ASLE_BACKLIGHT_FAILED	(1<<12) +#define ASLE_PFIT_FAILED	(1<<14) +#define ASLE_PWM_FREQ_FAILED	(1<<16) + +/* ASLE backlight brightness to set */ +#define ASLE_BCLP_VALID                (1<<31) +#define ASLE_BCLP_MSK          (~(1<<31)) + +/* ASLE panel fitting request */ +#define ASLE_PFIT_VALID         (1<<31) +#define ASLE_PFIT_CENTER (1<<0) +#define ASLE_PFIT_STRETCH_TEXT (1<<1) +#define ASLE_PFIT_STRETCH_GFX (1<<2) + +/* PWM frequency and minimum brightness */ +#define ASLE_PFMB_BRIGHTNESS_MASK (0xff) +#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8) +#define ASLE_PFMB_PWM_MASK (0x7ffffe00) +#define ASLE_PFMB_PWM_VALID (1<<31) + +#define ASLE_CBLV_VALID         (1<<31) + +static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) +{ +	struct drm_psb_private *dev_priv = dev->dev_private; +	struct opregion_asle *asle = dev_priv->opregion.asle; +	struct backlight_device *bd = dev_priv->backlight_device; +	u32 max; + +	DRM_DEBUG_DRIVER("asle set backlight %x\n", bclp); + +	if (!(bclp & ASLE_BCLP_VALID)) +		return ASLE_BACKLIGHT_FAILED; + +	if (bd == NULL) +		return ASLE_BACKLIGHT_FAILED; + +	bclp &= ASLE_BCLP_MSK; +	if (bclp > 255) +		return ASLE_BACKLIGHT_FAILED; + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE +	max = bd->props.max_brightness; +	bd->props.brightness = bclp * max / 255; +	backlight_update_status(bd); +#endif +	asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID; + +	return 0; +} + +void psb_intel_opregion_asle_intr(struct drm_device *dev) +{ +	struct drm_psb_private *dev_priv = dev->dev_private; +	struct opregion_asle *asle = dev_priv->opregion.asle; +	u32 asle_stat = 0; +	u32 asle_req; + +	if (!asle) +		return; + +	asle_req = asle->aslc & ASLE_REQ_MSK; +	if (!asle_req) { +		DRM_DEBUG_DRIVER("non asle set request??\n"); +		return; +	} + +	if (asle_req & ASLE_SET_BACKLIGHT) +		asle_stat |= asle_set_backlight(dev, asle->bclp); + +	asle->aslc = asle_stat; +} + +#define ASLE_ALS_EN    (1<<0) +#define ASLE_BLC_EN    (1<<1) +#define ASLE_PFIT_EN   (1<<2) +#define ASLE_PFMB_EN   (1<<3) + +void psb_intel_opregion_enable_asle(struct drm_device *dev) +{ +	struct drm_psb_private *dev_priv = dev->dev_private; +	struct opregion_asle *asle = dev_priv->opregion.asle; + +	if (asle) { +		/* Don't do this on Medfield or other non PC like devices, they +		   use the bit for something different altogether */ +		psb_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE); +		psb_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE); + +		asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN +								| ASLE_PFMB_EN; +		asle->ardy = 1; +	} +} + +#define ACPI_EV_DISPLAY_SWITCH (1<<0) +#define ACPI_EV_LID            (1<<1) +#define ACPI_EV_DOCK           (1<<2) + +static struct psb_intel_opregion *system_opregion; + +static int psb_intel_opregion_video_event(struct notifier_block *nb, +					  unsigned long val, void *data) +{ +	/* The only video events relevant to opregion are 0x80. These indicate +	   either a docking event, lid switch or display switch request. In +	   Linux, these are handled by the dock, button and video drivers. +	   We might want to fix the video driver to be opregion-aware in +	   future, but right now we just indicate to the firmware that the +	   request has been handled */ + +	struct opregion_acpi *acpi; + +	if (!system_opregion) +		return NOTIFY_DONE; + +	acpi = system_opregion->acpi; +	acpi->csts = 0; + +	return NOTIFY_OK; +} + +static struct notifier_block psb_intel_opregion_notifier = { +	.notifier_call = psb_intel_opregion_video_event, +}; + +void psb_intel_opregion_init(struct drm_device *dev) +{ +	struct drm_psb_private *dev_priv = dev->dev_private; +	struct psb_intel_opregion *opregion = &dev_priv->opregion; + +	if (!opregion->header) +		return; + +	if (opregion->acpi) { +		/* Notify BIOS we are ready to handle ACPI video ext notifs. +		 * Right now, all the events are handled by the ACPI video +		 * module. We don't actually need to do anything with them. */ +		opregion->acpi->csts = 0; +		opregion->acpi->drdy = 1; + +		system_opregion = opregion; +		register_acpi_notifier(&psb_intel_opregion_notifier); +	} + +	if (opregion->asle) +		psb_intel_opregion_enable_asle(dev); +} + +void psb_intel_opregion_fini(struct drm_device *dev) +{ +	struct drm_psb_private *dev_priv = dev->dev_private; +	struct psb_intel_opregion *opregion = &dev_priv->opregion; + +	if (!opregion->header) +		return; + +	if (opregion->acpi) { +		opregion->acpi->drdy = 0; + +		system_opregion = NULL; +		unregister_acpi_notifier(&psb_intel_opregion_notifier); +	} + +	/* just clear all opregion memory pointers now */ +	iounmap(opregion->header); +	opregion->header = NULL; +	opregion->acpi = NULL; +	opregion->swsci = NULL; +	opregion->asle = NULL; +	opregion->vbt = NULL; +} + +int psb_intel_opregion_setup(struct drm_device *dev) +{ +	struct drm_psb_private *dev_priv = dev->dev_private; +	struct psb_intel_opregion *opregion = &dev_priv->opregion; +	u32 opregion_phy, mboxes; +	void __iomem *base; +	int err = 0; + +	pci_read_config_dword(dev->pdev, PCI_ASLS, &opregion_phy); +	if (opregion_phy == 0) { +		DRM_DEBUG_DRIVER("ACPI Opregion not supported\n"); +		return -ENOTSUPP; +	} +	DRM_DEBUG("OpRegion detected at 0x%8x\n", opregion_phy); +#ifdef CONFIG_ACPI +	base = acpi_os_ioremap(opregion_phy, 8*1024); +#else +	base = ioremap(opregion_phy, 8*1024); +#endif +	if (!base) +		return -ENOMEM; + +	if (memcmp(base, OPREGION_SIGNATURE, 16)) { +		DRM_DEBUG_DRIVER("opregion signature mismatch\n"); +		err = -EINVAL; +		goto err_out; +	} + +	opregion->header = base; +	opregion->vbt = base + OPREGION_VBT_OFFSET; + +	opregion->lid_state = base + ACPI_CLID; + +	mboxes = opregion->header->mboxes; +	if (mboxes & MBOX_ACPI) { +		DRM_DEBUG_DRIVER("Public ACPI methods supported\n"); +		opregion->acpi = base + OPREGION_ACPI_OFFSET; +	} + +	if (mboxes & MBOX_ASLE) { +		DRM_DEBUG_DRIVER("ASLE supported\n"); +		opregion->asle = base + OPREGION_ASLE_OFFSET; +	} + +	return 0; + +err_out: +	iounmap(base); +	return err; +} + diff --git a/drivers/gpu/drm/gma500/opregion.h b/drivers/gpu/drm/gma500/opregion.h new file mode 100644 index 00000000000..a392ea8908b --- /dev/null +++ b/drivers/gpu/drm/gma500/opregion.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +extern void psb_intel_opregion_asle_intr(struct drm_device *dev); +extern void psb_intel_opregion_enable_asle(struct drm_device *dev); +extern void psb_intel_opregion_init(struct drm_device *dev); +extern void psb_intel_opregion_fini(struct drm_device *dev); +extern int psb_intel_opregion_setup(struct drm_device *dev); diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c index 34e6866a73b..e95cddbceb6 100644 --- a/drivers/gpu/drm/gma500/psb_device.c +++ b/drivers/gpu/drm/gma500/psb_device.c @@ -293,7 +293,7 @@ static int psb_chip_setup(struct drm_device *dev)  {  	psb_get_core_freq(dev);  	gma_intel_setup_gmbus(dev); -	gma_intel_opregion_init(dev); +	psb_intel_opregion_init(dev);  	psb_intel_init_bios(dev);  	return 0;  } diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index d5a6eab8227..0e85978877e 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -215,12 +215,11 @@ static int psb_driver_unload(struct drm_device *dev)  	/* Kill vblank etc here */  	gma_backlight_exit(dev); -  	psb_modeset_cleanup(dev);  	if (dev_priv) { +		psb_intel_opregion_fini(dev);  		psb_lid_timer_takedown(dev_priv); -		gma_intel_opregion_exit(dev);  		if (dev_priv->ops->chip_teardown)  			dev_priv->ops->chip_teardown(dev); @@ -310,6 +309,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)  	if (!dev_priv->sgx_reg)  		goto out_err; +	psb_intel_opregion_setup(dev); +  	ret = dev_priv->ops->chip_setup(dev);  	if (ret)  		goto out_err; @@ -349,9 +350,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)  	PSB_WSGX32(0x20000000, PSB_CR_PDS_EXEC_BASE);  	PSB_WSGX32(0x30000000, PSB_CR_BIF_3D_REQ_BASE); -/*	igd_opregion_init(&dev_priv->opregion_dev); */  	acpi_video_register(); -	if (dev_priv->lid_state) +	if (dev_priv->opregion.lid_state)  		psb_lid_timer_init(dev_priv);  	ret = drm_vblank_init(dev, dev_priv->num_pipe); diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index d3528a69420..270a27bc936 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -30,6 +30,7 @@  #include "psb_intel_drv.h"  #include "gtt.h"  #include "power.h" +#include "opregion.h"  #include "oaktrail.h"  /* Append new drm mode definition here, align with libdrm definition */ @@ -120,6 +121,7 @@ enum {  #define PSB_HWSTAM		  0x2098  #define PSB_INSTPM		  0x20C0  #define PSB_INT_IDENTITY_R        0x20A4 +#define _PSB_IRQ_ASLE		  (1<<0)  #define _MDFLD_PIPEC_EVENT_FLAG   (1<<2)  #define _MDFLD_PIPEC_VBLANK_FLAG  (1<<3)  #define _PSB_DPST_PIPEB_FLAG      (1<<4) @@ -259,7 +261,7 @@ struct psb_intel_opregion {  	struct opregion_swsci *swsci;  	struct opregion_asle *asle;  	void *vbt; -	int enabled; +	u32 __iomem *lid_state;  };  struct sdvo_device_mapping { @@ -505,9 +507,9 @@ struct drm_psb_private {  	/* GTT Memory manager */  	struct psb_gtt_mm *gtt_mm;  	struct page *scratch_page; -	u32 *gtt_map; +	u32 __iomem *gtt_map;  	uint32_t stolen_base; -	void *vram_addr; +	u8 __iomem *vram_addr;  	unsigned long vram_stolen_size;  	int gtt_initialized;  	u16 gmch_ctrl;		/* Saved GTT setup */ @@ -523,8 +525,8 @@ struct drm_psb_private {  	 * Register base  	 */ -	uint8_t *sgx_reg; -	uint8_t *vdc_reg; +	uint8_t __iomem *sgx_reg; +	uint8_t __iomem *vdc_reg;  	uint32_t gatt_free_offset;  	/* @@ -610,7 +612,7 @@ struct drm_psb_private {  	int rpm_enabled;  	/* MID specific */ -	struct oaktrail_vbt vbt_data; +	bool has_gct;  	struct oaktrail_gct_data gct_data;  	/* Oaktrail HDMI state */ @@ -638,7 +640,6 @@ struct drm_psb_private {  	spinlock_t lid_lock;  	struct timer_list lid_timer;  	struct psb_intel_opregion opregion; -	u32 *lid_state;  	u32 lid_last_state;  	/* diff --git a/drivers/gpu/drm/gma500/psb_intel_reg.h b/drivers/gpu/drm/gma500/psb_intel_reg.h index 519a9cd9ffb..8e8c8efb0a8 100644 --- a/drivers/gpu/drm/gma500/psb_intel_reg.h +++ b/drivers/gpu/drm/gma500/psb_intel_reg.h @@ -507,6 +507,7 @@  #define PIPE_VBLANK_INTERRUPT_ENABLE		(1UL << 17)  #define PIPE_START_VBLANK_INTERRUPT_ENABLE	(1UL << 18)  #define PIPE_TE_ENABLE				(1UL << 22) +#define PIPE_LEGACY_BLC_EVENT_ENABLE		(1UL << 22)  #define PIPE_DPST_EVENT_ENABLE			(1UL << 23)  #define PIPE_VSYNC_ENABL			(1UL << 25)  #define PIPE_HDMI_AUDIO_UNDERRUN		(1UL << 26) diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c index 2fcdffdc906..8652cdf3f03 100644 --- a/drivers/gpu/drm/gma500/psb_irq.c +++ b/drivers/gpu/drm/gma500/psb_irq.c @@ -190,6 +190,9 @@ static void mid_pipe_event_handler(struct drm_device *dev, int pipe)   */  static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat)  { +	if (vdc_stat & _PSB_IRQ_ASLE) +		psb_intel_opregion_asle_intr(dev); +  	if (vdc_stat & _PSB_VSYNC_PIPEA_FLAG)  		mid_pipe_event_handler(dev, 0); @@ -283,6 +286,7 @@ void psb_irq_preinstall(struct drm_device *dev)  	/* Revisit this area - want per device masks ? */  	if (dev_priv->ops->hotplug)  		dev_priv->vdc_irq_mask |= _PSB_IRQ_DISP_HOTSYNC; +	dev_priv->vdc_irq_mask |= _PSB_IRQ_ASLE;  	/* This register is safe even if display island is off */  	PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); @@ -422,7 +426,7 @@ void psb_irq_turn_off_dpst(struct drm_device *dev)  		psb_disable_pipestat(dev_priv, 0, PIPE_DPST_EVENT_ENABLE);  		pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); -		PSB_WVDC32(pwm_reg & !(PWM_PHASEIN_INT_ENABLE), +		PSB_WVDC32(pwm_reg & ~PWM_PHASEIN_INT_ENABLE,  							PWM_CONTROL_LOGIC);  		pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); diff --git a/drivers/gpu/drm/gma500/psb_lid.c b/drivers/gpu/drm/gma500/psb_lid.c index b867aabe6bf..7ff8bb2bdc2 100644 --- a/drivers/gpu/drm/gma500/psb_lid.c +++ b/drivers/gpu/drm/gma500/psb_lid.c @@ -29,7 +29,7 @@ static void psb_lid_timer_func(unsigned long data)  	struct drm_device *dev = (struct drm_device *)dev_priv->dev;  	struct timer_list *lid_timer = &dev_priv->lid_timer;  	unsigned long irq_flags; -	u32 *lid_state = dev_priv->lid_state; +	u32 __iomem *lid_state = dev_priv->opregion.lid_state;  	u32 pp_status;  	if (readl(lid_state) == dev_priv->lid_last_state) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index eed7acefb49..ecc29bc1cbe 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2424,27 +2424,18 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin  	u32 srbm_status;  	u32 grbm_status;  	u32 grbm_status_se0, grbm_status_se1; -	struct r100_gpu_lockup *lockup = &rdev->config.evergreen.lockup; -	int r;  	srbm_status = RREG32(SRBM_STATUS);  	grbm_status = RREG32(GRBM_STATUS);  	grbm_status_se0 = RREG32(GRBM_STATUS_SE0);  	grbm_status_se1 = RREG32(GRBM_STATUS_SE1);  	if (!(grbm_status & GUI_ACTIVE)) { -		r100_gpu_lockup_update(lockup, ring); +		radeon_ring_lockup_update(ring);  		return false;  	}  	/* force CP activities */ -	r = radeon_ring_lock(rdev, ring, 2); -	if (!r) { -		/* PACKET2 NOP */ -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_unlock_commit(rdev, ring); -	} -	ring->rptr = RREG32(CP_RB_RPTR); -	return r100_gpu_cp_is_lockup(rdev, lockup, ring); +	radeon_ring_force_activity(rdev, ring); +	return radeon_ring_test_lockup(rdev, ring);  }  static int evergreen_gpu_soft_reset(struct radeon_device *rdev) @@ -3376,12 +3367,9 @@ static int evergreen_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		DRM_ERROR("radeon: failed testing IB (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	}  	r = r600_audio_init(rdev);  	if (r) { diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index a48ca53fcd6..9cd2657eb2c 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1392,35 +1392,6 @@ int cayman_cp_resume(struct radeon_device *rdev)  	return 0;  } -bool cayman_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) -{ -	u32 srbm_status; -	u32 grbm_status; -	u32 grbm_status_se0, grbm_status_se1; -	struct r100_gpu_lockup *lockup = &rdev->config.cayman.lockup; -	int r; - -	srbm_status = RREG32(SRBM_STATUS); -	grbm_status = RREG32(GRBM_STATUS); -	grbm_status_se0 = RREG32(GRBM_STATUS_SE0); -	grbm_status_se1 = RREG32(GRBM_STATUS_SE1); -	if (!(grbm_status & GUI_ACTIVE)) { -		r100_gpu_lockup_update(lockup, ring); -		return false; -	} -	/* force CP activities */ -	r = radeon_ring_lock(rdev, ring, 2); -	if (!r) { -		/* PACKET2 NOP */ -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_unlock_commit(rdev, ring); -	} -	/* XXX deal with CP0,1,2 */ -	ring->rptr = RREG32(ring->rptr_reg); -	return r100_gpu_cp_is_lockup(rdev, lockup, ring); -} -  static int cayman_gpu_soft_reset(struct radeon_device *rdev)  {  	struct evergreen_mc_save save; @@ -1601,12 +1572,9 @@ static int cayman_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		DRM_ERROR("radeon: failed testing IB (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	}  	r = radeon_vm_manager_start(rdev);  	if (r) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index cb114185428..ad6ceb73171 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -660,7 +660,7 @@ int r100_pci_gart_enable(struct radeon_device *rdev)  	tmp = RREG32(RADEON_AIC_CNTL) | RADEON_PCIGART_TRANSLATE_EN;  	WREG32(RADEON_AIC_CNTL, tmp);  	r100_pci_gart_tlb_flush(rdev); -	DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", +	DRM_INFO("PCI GART of %uM enabled (table at 0x%016llX).\n",  		 (unsigned)(rdev->mc.gtt_size >> 20),  		 (unsigned long long)rdev->gart.table_addr);  	rdev->gart.ready = true; @@ -2159,79 +2159,18 @@ int r100_mc_wait_for_idle(struct radeon_device *rdev)  	return -1;  } -void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_ring *ring) -{ -	lockup->last_cp_rptr = ring->rptr; -	lockup->last_jiffies = jiffies; -} - -/** - * r100_gpu_cp_is_lockup() - check if CP is lockup by recording information - * @rdev:	radeon device structure - * @lockup:	r100_gpu_lockup structure holding CP lockup tracking informations - * @cp:		radeon_cp structure holding CP information - * - * We don't need to initialize the lockup tracking information as we will either - * have CP rptr to a different value of jiffies wrap around which will force - * initialization of the lockup tracking informations. - * - * A possible false positivie is if we get call after while and last_cp_rptr == - * the current CP rptr, even if it's unlikely it might happen. To avoid this - * if the elapsed time since last call is bigger than 2 second than we return - * false and update the tracking information. Due to this the caller must call - * r100_gpu_cp_is_lockup several time in less than 2sec for lockup to be reported - * the fencing code should be cautious about that. - * - * Caller should write to the ring to force CP to do something so we don't get - * false positive when CP is just gived nothing to do. - * - **/ -bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_ring *ring) -{ -	unsigned long cjiffies, elapsed; - -	cjiffies = jiffies; -	if (!time_after(cjiffies, lockup->last_jiffies)) { -		/* likely a wrap around */ -		lockup->last_cp_rptr = ring->rptr; -		lockup->last_jiffies = jiffies; -		return false; -	} -	if (ring->rptr != lockup->last_cp_rptr) { -		/* CP is still working no lockup */ -		lockup->last_cp_rptr = ring->rptr; -		lockup->last_jiffies = jiffies; -		return false; -	} -	elapsed = jiffies_to_msecs(cjiffies - lockup->last_jiffies); -	if (elapsed >= 10000) { -		dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed); -		return true; -	} -	/* give a chance to the GPU ... */ -	return false; -} -  bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  {  	u32 rbbm_status; -	int r;  	rbbm_status = RREG32(R_000E40_RBBM_STATUS);  	if (!G_000E40_GUI_ACTIVE(rbbm_status)) { -		r100_gpu_lockup_update(&rdev->config.r100.lockup, ring); +		radeon_ring_lockup_update(ring);  		return false;  	}  	/* force CP activities */ -	r = radeon_ring_lock(rdev, ring, 2); -	if (!r) { -		/* PACKET2 NOP */ -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_unlock_commit(rdev, ring); -	} -	ring->rptr = RREG32(ring->rptr_reg); -	return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, ring); +	radeon_ring_force_activity(rdev, ring); +	return radeon_ring_test_lockup(rdev, ring);  }  void r100_bm_disable(struct radeon_device *rdev) @@ -2300,7 +2239,6 @@ int r100_asic_reset(struct radeon_device *rdev)  	if (G_000E40_SE_BUSY(status) || G_000E40_RE_BUSY(status) ||  		G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) {  		dev_err(rdev->dev, "failed to reset GPU\n"); -		rdev->gpu_lockup = true;  		ret = -1;  	} else  		dev_info(rdev->dev, "GPU reset succeed\n"); @@ -3969,12 +3907,9 @@ static int r100_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		dev_err(rdev->dev, "failed testing IB (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	}  	return 0;  } diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index fa14383f9ca..6419a5900e6 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -377,28 +377,6 @@ void r300_gpu_init(struct radeon_device *rdev)  		 rdev->num_gb_pipes, rdev->num_z_pipes);  } -bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) -{ -	u32 rbbm_status; -	int r; - -	rbbm_status = RREG32(R_000E40_RBBM_STATUS); -	if (!G_000E40_GUI_ACTIVE(rbbm_status)) { -		r100_gpu_lockup_update(&rdev->config.r300.lockup, ring); -		return false; -	} -	/* force CP activities */ -	r = radeon_ring_lock(rdev, ring, 2); -	if (!r) { -		/* PACKET2 NOP */ -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_unlock_commit(rdev, ring); -	} -	ring->rptr = RREG32(RADEON_CP_RB_RPTR); -	return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, ring); -} -  int r300_asic_reset(struct radeon_device *rdev)  {  	struct r100_mc_save save; @@ -449,7 +427,6 @@ int r300_asic_reset(struct radeon_device *rdev)  	/* Check if GPU is idle */  	if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {  		dev_err(rdev->dev, "failed to reset GPU\n"); -		rdev->gpu_lockup = true;  		ret = -1;  	} else  		dev_info(rdev->dev, "GPU reset succeed\n"); @@ -1418,12 +1395,9 @@ static int r300_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		dev_err(rdev->dev, "failed testing IB (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	}  	return 0;  } diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index f3fcaacfea0..99137be7a30 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -279,12 +279,9 @@ static int r420_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		dev_err(rdev->dev, "failed testing IB (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	}  	return 0;  } diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index ebcc15b03c9..b5cf8375cd2 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -207,12 +207,10 @@ static int r520_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		dev_err(rdev->dev, "failed testing IB (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	} +  	return 0;  } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c37b727fda7..d02f13fdaa6 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1350,31 +1350,17 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  	u32 srbm_status;  	u32 grbm_status;  	u32 grbm_status2; -	struct r100_gpu_lockup *lockup; -	int r; - -	if (rdev->family >= CHIP_RV770) -		lockup = &rdev->config.rv770.lockup; -	else -		lockup = &rdev->config.r600.lockup;  	srbm_status = RREG32(R_000E50_SRBM_STATUS);  	grbm_status = RREG32(R_008010_GRBM_STATUS);  	grbm_status2 = RREG32(R_008014_GRBM_STATUS2);  	if (!G_008010_GUI_ACTIVE(grbm_status)) { -		r100_gpu_lockup_update(lockup, ring); +		radeon_ring_lockup_update(ring);  		return false;  	}  	/* force CP activities */ -	r = radeon_ring_lock(rdev, ring, 2); -	if (!r) { -		/* PACKET2 NOP */ -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_unlock_commit(rdev, ring); -	} -	ring->rptr = RREG32(ring->rptr_reg); -	return r100_gpu_cp_is_lockup(rdev, lockup, ring); +	radeon_ring_force_activity(rdev, ring); +	return radeon_ring_test_lockup(rdev, ring);  }  int r600_asic_reset(struct radeon_device *rdev) @@ -2494,12 +2480,9 @@ int r600_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		DRM_ERROR("radeon: failed testing IB (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	}  	return 0;  } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 610acee74a3..82ffa6a05cc 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -94,6 +94,7 @@ extern int radeon_disp_priority;  extern int radeon_hw_i2c;  extern int radeon_pcie_gen2;  extern int radeon_msi; +extern int radeon_lockup_timeout;  /*   * Copy from radeon_drv.h so we don't have to include both and have conflicting @@ -255,10 +256,8 @@ struct radeon_fence_driver {  	volatile uint32_t		*cpu_addr;  	atomic_t			seq;  	uint32_t			last_seq; -	unsigned long			last_jiffies; -	unsigned long			last_timeout; +	unsigned long			last_activity;  	wait_queue_head_t		queue; -	struct list_head		created;  	struct list_head		emitted;  	struct list_head		signaled;  	bool				initialized; @@ -286,7 +285,7 @@ void radeon_fence_process(struct radeon_device *rdev, int ring);  bool radeon_fence_signaled(struct radeon_fence *fence);  int radeon_fence_wait(struct radeon_fence *fence, bool interruptible);  int radeon_fence_wait_next(struct radeon_device *rdev, int ring); -int radeon_fence_wait_last(struct radeon_device *rdev, int ring); +int radeon_fence_wait_empty(struct radeon_device *rdev, int ring);  struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence);  void radeon_fence_unref(struct radeon_fence **fence);  int radeon_fence_count_emitted(struct radeon_device *rdev, int ring); @@ -462,6 +461,10 @@ void radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring,  				  struct radeon_semaphore *semaphore);  void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring,  				struct radeon_semaphore *semaphore); +int radeon_semaphore_sync_rings(struct radeon_device *rdev, +				struct radeon_semaphore *semaphore, +				bool sync_to[RADEON_NUM_RINGS], +				int dst_ring);  void radeon_semaphore_free(struct radeon_device *rdev,  			   struct radeon_semaphore *semaphore); @@ -668,6 +671,8 @@ struct radeon_ring {  	unsigned		ring_size;  	unsigned		ring_free_dw;  	int			count_dw; +	unsigned long		last_activity; +	unsigned		last_rptr;  	uint64_t		gpu_addr;  	uint32_t		align_mask;  	uint32_t		ptr_mask; @@ -802,6 +807,7 @@ int radeon_ib_pool_init(struct radeon_device *rdev);  void radeon_ib_pool_fini(struct radeon_device *rdev);  int radeon_ib_pool_start(struct radeon_device *rdev);  int radeon_ib_pool_suspend(struct radeon_device *rdev); +int radeon_ib_ring_tests(struct radeon_device *rdev);  /* Ring access between begin & end cannot sleep */  int radeon_ring_index(struct radeon_device *rdev, struct radeon_ring *cp);  void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *cp); @@ -811,6 +817,9 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp);  void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp);  void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *cp);  int radeon_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); +void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring); +void radeon_ring_lockup_update(struct radeon_ring *ring); +bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring);  int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ring_size,  		     unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg,  		     u32 ptr_reg_shift, u32 ptr_reg_mask, u32 nop); @@ -1162,7 +1171,6 @@ struct radeon_asic {  	int (*resume)(struct radeon_device *rdev);  	int (*suspend)(struct radeon_device *rdev);  	void (*vga_set_state)(struct radeon_device *rdev, bool state); -	bool (*gpu_is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp);  	int (*asic_reset)(struct radeon_device *rdev);  	/* ioctl hw specific callback. Some hw might want to perform special  	 * operation on specific ioctl. For instance on wait idle some hw @@ -1191,6 +1199,7 @@ struct radeon_asic {  		void (*ring_start)(struct radeon_device *rdev, struct radeon_ring *cp);  		int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp);  		int (*ib_test)(struct radeon_device *rdev, struct radeon_ring *cp); +		bool (*is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp);  	} ring[RADEON_NUM_RINGS];  	/* irqs */  	struct { @@ -1269,16 +1278,10 @@ struct radeon_asic {  /*   * Asic structures   */ -struct r100_gpu_lockup { -	unsigned long	last_jiffies; -	u32		last_cp_rptr; -}; -  struct r100_asic {  	const unsigned		*reg_safe_bm;  	unsigned		reg_safe_bm_size;  	u32			hdp_cntl; -	struct r100_gpu_lockup	lockup;  };  struct r300_asic { @@ -1286,7 +1289,6 @@ struct r300_asic {  	unsigned		reg_safe_bm_size;  	u32			resync_scratch;  	u32			hdp_cntl; -	struct r100_gpu_lockup	lockup;  };  struct r600_asic { @@ -1308,7 +1310,6 @@ struct r600_asic {  	unsigned		tiling_group_size;  	unsigned		tile_config;  	unsigned		backend_map; -	struct r100_gpu_lockup	lockup;  };  struct rv770_asic { @@ -1334,7 +1335,6 @@ struct rv770_asic {  	unsigned		tiling_group_size;  	unsigned		tile_config;  	unsigned		backend_map; -	struct r100_gpu_lockup	lockup;  };  struct evergreen_asic { @@ -1361,7 +1361,6 @@ struct evergreen_asic {  	unsigned tiling_group_size;  	unsigned tile_config;  	unsigned backend_map; -	struct r100_gpu_lockup	lockup;  };  struct cayman_asic { @@ -1400,7 +1399,6 @@ struct cayman_asic {  	unsigned multi_gpu_tile_size;  	unsigned tile_config; -	struct r100_gpu_lockup	lockup;  };  struct si_asic { @@ -1431,7 +1429,6 @@ struct si_asic {  	unsigned multi_gpu_tile_size;  	unsigned tile_config; -	struct r100_gpu_lockup	lockup;  };  union radeon_asic_config { @@ -1547,7 +1544,6 @@ struct radeon_device {  	struct radeon_mutex		cs_mutex;  	struct radeon_wb		wb;  	struct radeon_dummy_page	dummy_page; -	bool				gpu_lockup;  	bool				shutdown;  	bool				suspend;  	bool				need_dma32; @@ -1740,7 +1736,6 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);  #define radeon_suspend(rdev) (rdev)->asic->suspend((rdev))  #define radeon_cs_parse(rdev, r, p) (rdev)->asic->ring[(r)].cs_parse((p))  #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state)) -#define radeon_gpu_is_lockup(rdev, cp) (rdev)->asic->gpu_is_lockup((rdev), (cp))  #define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev))  #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev))  #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p)) @@ -1749,6 +1744,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);  #define radeon_ib_test(rdev, r, cp) (rdev)->asic->ring[(r)].ib_test((rdev), (cp))  #define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)].ib_execute((rdev), (ib))  #define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)].ib_parse((rdev), (ib)) +#define radeon_ring_is_lockup(rdev, r, cp) (rdev)->asic->ring[(r)].is_lockup((rdev), (cp))  #define radeon_irq_set(rdev) (rdev)->asic->irq.set((rdev))  #define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev))  #define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc)) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index be4dc2ff0e4..f533df5f7d5 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -134,7 +134,6 @@ static struct radeon_asic r100_asic = {  	.suspend = &r100_suspend,  	.resume = &r100_resume,  	.vga_set_state = &r100_vga_set_state, -	.gpu_is_lockup = &r100_gpu_is_lockup,  	.asic_reset = &r100_asic_reset,  	.ioctl_wait_idle = NULL,  	.gui_idle = &r100_gui_idle, @@ -152,6 +151,7 @@ static struct radeon_asic r100_asic = {  			.ring_start = &r100_ring_start,  			.ring_test = &r100_ring_test,  			.ib_test = &r100_ib_test, +			.is_lockup = &r100_gpu_is_lockup,  		}  	},  	.irq = { @@ -208,7 +208,6 @@ static struct radeon_asic r200_asic = {  	.suspend = &r100_suspend,  	.resume = &r100_resume,  	.vga_set_state = &r100_vga_set_state, -	.gpu_is_lockup = &r100_gpu_is_lockup,  	.asic_reset = &r100_asic_reset,  	.ioctl_wait_idle = NULL,  	.gui_idle = &r100_gui_idle, @@ -226,6 +225,7 @@ static struct radeon_asic r200_asic = {  			.ring_start = &r100_ring_start,  			.ring_test = &r100_ring_test,  			.ib_test = &r100_ib_test, +			.is_lockup = &r100_gpu_is_lockup,  		}  	},  	.irq = { @@ -282,7 +282,6 @@ static struct radeon_asic r300_asic = {  	.suspend = &r300_suspend,  	.resume = &r300_resume,  	.vga_set_state = &r100_vga_set_state, -	.gpu_is_lockup = &r300_gpu_is_lockup,  	.asic_reset = &r300_asic_reset,  	.ioctl_wait_idle = NULL,  	.gui_idle = &r100_gui_idle, @@ -300,6 +299,7 @@ static struct radeon_asic r300_asic = {  			.ring_start = &r300_ring_start,  			.ring_test = &r100_ring_test,  			.ib_test = &r100_ib_test, +			.is_lockup = &r100_gpu_is_lockup,  		}  	},  	.irq = { @@ -356,7 +356,6 @@ static struct radeon_asic r300_asic_pcie = {  	.suspend = &r300_suspend,  	.resume = &r300_resume,  	.vga_set_state = &r100_vga_set_state, -	.gpu_is_lockup = &r300_gpu_is_lockup,  	.asic_reset = &r300_asic_reset,  	.ioctl_wait_idle = NULL,  	.gui_idle = &r100_gui_idle, @@ -374,6 +373,7 @@ static struct radeon_asic r300_asic_pcie = {  			.ring_start = &r300_ring_start,  			.ring_test = &r100_ring_test,  			.ib_test = &r100_ib_test, +			.is_lockup = &r100_gpu_is_lockup,  		}  	},  	.irq = { @@ -430,7 +430,6 @@ static struct radeon_asic r420_asic = {  	.suspend = &r420_suspend,  	.resume = &r420_resume,  	.vga_set_state = &r100_vga_set_state, -	.gpu_is_lockup = &r300_gpu_is_lockup,  	.asic_reset = &r300_asic_reset,  	.ioctl_wait_idle = NULL,  	.gui_idle = &r100_gui_idle, @@ -448,6 +447,7 @@ static struct radeon_asic r420_asic = {  			.ring_start = &r300_ring_start,  			.ring_test = &r100_ring_test,  			.ib_test = &r100_ib_test, +			.is_lockup = &r100_gpu_is_lockup,  		}  	},  	.irq = { @@ -504,7 +504,6 @@ static struct radeon_asic rs400_asic = {  	.suspend = &rs400_suspend,  	.resume = &rs400_resume,  	.vga_set_state = &r100_vga_set_state, -	.gpu_is_lockup = &r300_gpu_is_lockup,  	.asic_reset = &r300_asic_reset,  	.ioctl_wait_idle = NULL,  	.gui_idle = &r100_gui_idle, @@ -522,6 +521,7 @@ static struct radeon_asic rs400_asic = {  			.ring_start = &r300_ring_start,  			.ring_test = &r100_ring_test,  			.ib_test = &r100_ib_test, +			.is_lockup = &r100_gpu_is_lockup,  		}  	},  	.irq = { @@ -578,7 +578,6 @@ static struct radeon_asic rs600_asic = {  	.suspend = &rs600_suspend,  	.resume = &rs600_resume,  	.vga_set_state = &r100_vga_set_state, -	.gpu_is_lockup = &r300_gpu_is_lockup,  	.asic_reset = &rs600_asic_reset,  	.ioctl_wait_idle = NULL,  	.gui_idle = &r100_gui_idle, @@ -596,6 +595,7 @@ static struct radeon_asic rs600_asic = {  			.ring_start = &r300_ring_start,  			.ring_test = &r100_ring_test,  			.ib_test = &r100_ib_test, +			.is_lockup = &r100_gpu_is_lockup,  		}  	},  	.irq = { @@ -652,7 +652,6 @@ static struct radeon_asic rs690_asic = {  	.suspend = &rs690_suspend,  	.resume = &rs690_resume,  	.vga_set_state = &r100_vga_set_state, -	.gpu_is_lockup = &r300_gpu_is_lockup,  	.asic_reset = &rs600_asic_reset,  	.ioctl_wait_idle = NULL,  	.gui_idle = &r100_gui_idle, @@ -670,6 +669,7 @@ static struct radeon_asic rs690_asic = {  			.ring_start = &r300_ring_start,  			.ring_test = &r100_ring_test,  			.ib_test = &r100_ib_test, +			.is_lockup = &r100_gpu_is_lockup,  		}  	},  	.irq = { @@ -726,7 +726,6 @@ static struct radeon_asic rv515_asic = {  	.suspend = &rv515_suspend,  	.resume = &rv515_resume,  	.vga_set_state = &r100_vga_set_state, -	.gpu_is_lockup = &r300_gpu_is_lockup,  	.asic_reset = &rs600_asic_reset,  	.ioctl_wait_idle = NULL,  	.gui_idle = &r100_gui_idle, @@ -744,6 +743,7 @@ static struct radeon_asic rv515_asic = {  			.ring_start = &rv515_ring_start,  			.ring_test = &r100_ring_test,  			.ib_test = &r100_ib_test, +			.is_lockup = &r100_gpu_is_lockup,  		}  	},  	.irq = { @@ -800,7 +800,6 @@ static struct radeon_asic r520_asic = {  	.suspend = &rv515_suspend,  	.resume = &r520_resume,  	.vga_set_state = &r100_vga_set_state, -	.gpu_is_lockup = &r300_gpu_is_lockup,  	.asic_reset = &rs600_asic_reset,  	.ioctl_wait_idle = NULL,  	.gui_idle = &r100_gui_idle, @@ -818,6 +817,7 @@ static struct radeon_asic r520_asic = {  			.ring_start = &rv515_ring_start,  			.ring_test = &r100_ring_test,  			.ib_test = &r100_ib_test, +			.is_lockup = &r100_gpu_is_lockup,  		}  	},  	.irq = { @@ -874,7 +874,6 @@ static struct radeon_asic r600_asic = {  	.suspend = &r600_suspend,  	.resume = &r600_resume,  	.vga_set_state = &r600_vga_set_state, -	.gpu_is_lockup = &r600_gpu_is_lockup,  	.asic_reset = &r600_asic_reset,  	.ioctl_wait_idle = r600_ioctl_wait_idle,  	.gui_idle = &r600_gui_idle, @@ -891,6 +890,7 @@ static struct radeon_asic r600_asic = {  			.cs_parse = &r600_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &r600_gpu_is_lockup,  		}  	},  	.irq = { @@ -946,7 +946,6 @@ static struct radeon_asic rs780_asic = {  	.fini = &r600_fini,  	.suspend = &r600_suspend,  	.resume = &r600_resume, -	.gpu_is_lockup = &r600_gpu_is_lockup,  	.vga_set_state = &r600_vga_set_state,  	.asic_reset = &r600_asic_reset,  	.ioctl_wait_idle = r600_ioctl_wait_idle, @@ -964,6 +963,7 @@ static struct radeon_asic rs780_asic = {  			.cs_parse = &r600_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &r600_gpu_is_lockup,  		}  	},  	.irq = { @@ -1020,7 +1020,6 @@ static struct radeon_asic rv770_asic = {  	.suspend = &rv770_suspend,  	.resume = &rv770_resume,  	.asic_reset = &r600_asic_reset, -	.gpu_is_lockup = &r600_gpu_is_lockup,  	.vga_set_state = &r600_vga_set_state,  	.ioctl_wait_idle = r600_ioctl_wait_idle,  	.gui_idle = &r600_gui_idle, @@ -1037,6 +1036,7 @@ static struct radeon_asic rv770_asic = {  			.cs_parse = &r600_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &r600_gpu_is_lockup,  		}  	},  	.irq = { @@ -1092,7 +1092,6 @@ static struct radeon_asic evergreen_asic = {  	.fini = &evergreen_fini,  	.suspend = &evergreen_suspend,  	.resume = &evergreen_resume, -	.gpu_is_lockup = &evergreen_gpu_is_lockup,  	.asic_reset = &evergreen_asic_reset,  	.vga_set_state = &r600_vga_set_state,  	.ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1110,6 +1109,7 @@ static struct radeon_asic evergreen_asic = {  			.cs_parse = &evergreen_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &evergreen_gpu_is_lockup,  		}  	},  	.irq = { @@ -1165,7 +1165,6 @@ static struct radeon_asic sumo_asic = {  	.fini = &evergreen_fini,  	.suspend = &evergreen_suspend,  	.resume = &evergreen_resume, -	.gpu_is_lockup = &evergreen_gpu_is_lockup,  	.asic_reset = &evergreen_asic_reset,  	.vga_set_state = &r600_vga_set_state,  	.ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1183,6 +1182,7 @@ static struct radeon_asic sumo_asic = {  			.cs_parse = &evergreen_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &evergreen_gpu_is_lockup,  		},  	},  	.irq = { @@ -1238,7 +1238,6 @@ static struct radeon_asic btc_asic = {  	.fini = &evergreen_fini,  	.suspend = &evergreen_suspend,  	.resume = &evergreen_resume, -	.gpu_is_lockup = &evergreen_gpu_is_lockup,  	.asic_reset = &evergreen_asic_reset,  	.vga_set_state = &r600_vga_set_state,  	.ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1256,6 +1255,7 @@ static struct radeon_asic btc_asic = {  			.cs_parse = &evergreen_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &evergreen_gpu_is_lockup,  		}  	},  	.irq = { @@ -1321,7 +1321,6 @@ static struct radeon_asic cayman_asic = {  	.fini = &cayman_fini,  	.suspend = &cayman_suspend,  	.resume = &cayman_resume, -	.gpu_is_lockup = &cayman_gpu_is_lockup,  	.asic_reset = &cayman_asic_reset,  	.vga_set_state = &r600_vga_set_state,  	.ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1340,6 +1339,7 @@ static struct radeon_asic cayman_asic = {  			.cs_parse = &evergreen_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &evergreen_gpu_is_lockup,  		},  		[CAYMAN_RING_TYPE_CP1_INDEX] = {  			.ib_execute = &cayman_ring_ib_execute, @@ -1349,6 +1349,7 @@ static struct radeon_asic cayman_asic = {  			.cs_parse = &evergreen_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &evergreen_gpu_is_lockup,  		},  		[CAYMAN_RING_TYPE_CP2_INDEX] = {  			.ib_execute = &cayman_ring_ib_execute, @@ -1358,6 +1359,7 @@ static struct radeon_asic cayman_asic = {  			.cs_parse = &evergreen_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &evergreen_gpu_is_lockup,  		}  	},  	.irq = { @@ -1413,7 +1415,6 @@ static struct radeon_asic trinity_asic = {  	.fini = &cayman_fini,  	.suspend = &cayman_suspend,  	.resume = &cayman_resume, -	.gpu_is_lockup = &cayman_gpu_is_lockup,  	.asic_reset = &cayman_asic_reset,  	.vga_set_state = &r600_vga_set_state,  	.ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1432,6 +1433,7 @@ static struct radeon_asic trinity_asic = {  			.cs_parse = &evergreen_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &evergreen_gpu_is_lockup,  		},  		[CAYMAN_RING_TYPE_CP1_INDEX] = {  			.ib_execute = &cayman_ring_ib_execute, @@ -1441,6 +1443,7 @@ static struct radeon_asic trinity_asic = {  			.cs_parse = &evergreen_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &evergreen_gpu_is_lockup,  		},  		[CAYMAN_RING_TYPE_CP2_INDEX] = {  			.ib_execute = &cayman_ring_ib_execute, @@ -1450,6 +1453,7 @@ static struct radeon_asic trinity_asic = {  			.cs_parse = &evergreen_cs_parse,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &evergreen_gpu_is_lockup,  		}  	},  	.irq = { @@ -1515,7 +1519,6 @@ static struct radeon_asic si_asic = {  	.fini = &si_fini,  	.suspend = &si_suspend,  	.resume = &si_resume, -	.gpu_is_lockup = &si_gpu_is_lockup,  	.asic_reset = &si_asic_reset,  	.vga_set_state = &r600_vga_set_state,  	.ioctl_wait_idle = r600_ioctl_wait_idle, @@ -1534,6 +1537,7 @@ static struct radeon_asic si_asic = {  			.cs_parse = NULL,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &si_gpu_is_lockup,  		},  		[CAYMAN_RING_TYPE_CP1_INDEX] = {  			.ib_execute = &si_ring_ib_execute, @@ -1543,6 +1547,7 @@ static struct radeon_asic si_asic = {  			.cs_parse = NULL,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &si_gpu_is_lockup,  		},  		[CAYMAN_RING_TYPE_CP2_INDEX] = {  			.ib_execute = &si_ring_ib_execute, @@ -1552,6 +1557,7 @@ static struct radeon_asic si_asic = {  			.cs_parse = NULL,  			.ring_test = &r600_ring_test,  			.ib_test = &r600_ib_test, +			.is_lockup = &si_gpu_is_lockup,  		}  	},  	.irq = { diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index b135bec649d..78309318bd3 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -103,11 +103,6 @@ int r100_pci_gart_enable(struct radeon_device *rdev);  void r100_pci_gart_disable(struct radeon_device *rdev);  int r100_debugfs_mc_info_init(struct radeon_device *rdev);  int r100_gui_wait_for_idle(struct radeon_device *rdev); -void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, -			    struct radeon_ring *cp); -bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, -			   struct r100_gpu_lockup *lockup, -			   struct radeon_ring *cp);  void r100_ib_fini(struct radeon_device *rdev);  int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);  void r100_irq_disable(struct radeon_device *rdev); @@ -159,7 +154,6 @@ extern int r300_init(struct radeon_device *rdev);  extern void r300_fini(struct radeon_device *rdev);  extern int r300_suspend(struct radeon_device *rdev);  extern int r300_resume(struct radeon_device *rdev); -extern bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp);  extern int r300_asic_reset(struct radeon_device *rdev);  extern void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring);  extern void r300_fence_ring_emit(struct radeon_device *rdev, @@ -443,7 +437,6 @@ int cayman_init(struct radeon_device *rdev);  void cayman_fini(struct radeon_device *rdev);  int cayman_suspend(struct radeon_device *rdev);  int cayman_resume(struct radeon_device *rdev); -bool cayman_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp);  int cayman_asic_reset(struct radeon_device *rdev);  void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);  int cayman_vm_init(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 2cad9fde92f..576f4f6919f 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -1561,6 +1561,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)  			   (rdev->pdev->subsystem_device == 0x4150)) {  			/* Mac G5 tower 9600 */  			rdev->mode_info.connector_table = CT_MAC_G5_9600; +		} else if ((rdev->pdev->device == 0x4c66) && +			   (rdev->pdev->subsystem_vendor == 0x1002) && +			   (rdev->pdev->subsystem_device == 0x4c66)) { +			/* SAM440ep RV250 embedded board */ +			rdev->mode_info.connector_table = CT_SAM440EP;  		} else  #endif /* CONFIG_PPC_PMAC */  #ifdef CONFIG_PPC64 @@ -2134,6 +2139,67 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)  					    CONNECTOR_OBJECT_ID_SVIDEO,  					    &hpd);  		break; +	case CT_SAM440EP: +		DRM_INFO("Connector Table: %d (SAM440ep embedded board)\n", +			 rdev->mode_info.connector_table); +		/* LVDS */ +		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_NONE_DETECTED, 0, 0); +		hpd.hpd = RADEON_HPD_NONE; +		radeon_add_legacy_encoder(dev, +					  radeon_get_encoder_enum(dev, +								ATOM_DEVICE_LCD1_SUPPORT, +								0), +					  ATOM_DEVICE_LCD1_SUPPORT); +		radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT, +					    DRM_MODE_CONNECTOR_LVDS, &ddc_i2c, +					    CONNECTOR_OBJECT_ID_LVDS, +					    &hpd); +		/* DVI-I - secondary dac, int tmds */ +		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); +		hpd.hpd = RADEON_HPD_1; /* ??? */ +		radeon_add_legacy_encoder(dev, +					  radeon_get_encoder_enum(dev, +								ATOM_DEVICE_DFP1_SUPPORT, +								0), +					  ATOM_DEVICE_DFP1_SUPPORT); +		radeon_add_legacy_encoder(dev, +					  radeon_get_encoder_enum(dev, +								ATOM_DEVICE_CRT2_SUPPORT, +								2), +					  ATOM_DEVICE_CRT2_SUPPORT); +		radeon_add_legacy_connector(dev, 1, +					    ATOM_DEVICE_DFP1_SUPPORT | +					    ATOM_DEVICE_CRT2_SUPPORT, +					    DRM_MODE_CONNECTOR_DVII, &ddc_i2c, +					    CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I, +					    &hpd); +		/* VGA - primary dac */ +		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); +		hpd.hpd = RADEON_HPD_NONE; +		radeon_add_legacy_encoder(dev, +					  radeon_get_encoder_enum(dev, +								ATOM_DEVICE_CRT1_SUPPORT, +								1), +					  ATOM_DEVICE_CRT1_SUPPORT); +		radeon_add_legacy_connector(dev, 2, +					    ATOM_DEVICE_CRT1_SUPPORT, +					    DRM_MODE_CONNECTOR_VGA, &ddc_i2c, +					    CONNECTOR_OBJECT_ID_VGA, +					    &hpd); +		/* TV - TV DAC */ +		ddc_i2c.valid = false; +		hpd.hpd = RADEON_HPD_NONE; +		radeon_add_legacy_encoder(dev, +					  radeon_get_encoder_enum(dev, +								ATOM_DEVICE_TV1_SUPPORT, +								2), +					  ATOM_DEVICE_TV1_SUPPORT); +		radeon_add_legacy_connector(dev, 3, ATOM_DEVICE_TV1_SUPPORT, +					    DRM_MODE_CONNECTOR_SVIDEO, +					    &ddc_i2c, +					    CONNECTOR_OBJECT_ID_SVIDEO, +					    &hpd); +		break;  	default:  		DRM_INFO("Connector table: %d (invalid)\n",  			 rdev->mode_info.connector_table); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index e7b0b5d51bc..c66beb1662b 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -118,6 +118,7 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority  static int radeon_cs_sync_rings(struct radeon_cs_parser *p)  {  	bool sync_to_ring[RADEON_NUM_RINGS] = { }; +	bool need_sync = false;  	int i, r;  	for (i = 0; i < p->nrelocs; i++) { @@ -126,36 +127,24 @@ static int radeon_cs_sync_rings(struct radeon_cs_parser *p)  		if (!(p->relocs[i].flags & RADEON_RELOC_DONT_SYNC)) {  			struct radeon_fence *fence = p->relocs[i].robj->tbo.sync_obj; -			if (!radeon_fence_signaled(fence)) { +			if (fence->ring != p->ring && !radeon_fence_signaled(fence)) {  				sync_to_ring[fence->ring] = true; +				need_sync = true;  			}  		}  	} -	for (i = 0; i < RADEON_NUM_RINGS; ++i) { -		/* no need to sync to our own or unused rings */ -		if (i == p->ring || !sync_to_ring[i] || !p->rdev->ring[i].ready) -			continue; - -		if (!p->ib->fence->semaphore) { -			r = radeon_semaphore_create(p->rdev, &p->ib->fence->semaphore); -			if (r) -				return r; -		} - -		r = radeon_ring_lock(p->rdev, &p->rdev->ring[i], 3); -		if (r) -			return r; -		radeon_semaphore_emit_signal(p->rdev, i, p->ib->fence->semaphore); -		radeon_ring_unlock_commit(p->rdev, &p->rdev->ring[i]); +	if (!need_sync) { +		return 0; +	} -		r = radeon_ring_lock(p->rdev, &p->rdev->ring[p->ring], 3); -		if (r) -			return r; -		radeon_semaphore_emit_wait(p->rdev, p->ring, p->ib->fence->semaphore); -		radeon_ring_unlock_commit(p->rdev, &p->rdev->ring[p->ring]); +	r = radeon_semaphore_create(p->rdev, &p->ib->fence->semaphore); +	if (r) { +		return r;  	} -	return 0; + +	return radeon_semaphore_sync_rings(p->rdev, p->ib->fence->semaphore, +					   sync_to_ring, p->ring);  }  int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) @@ -172,6 +161,8 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)  	/* get chunks */  	INIT_LIST_HEAD(&p->validated);  	p->idx = 0; +	p->ib = NULL; +	p->const_ib = NULL;  	p->chunk_ib_idx = -1;  	p->chunk_relocs_idx = -1;  	p->chunk_flags_idx = -1; @@ -336,6 +327,9 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)  	kfree(parser->chunks);  	kfree(parser->chunks_array);  	radeon_ib_free(parser->rdev, &parser->ib); +	if (parser->const_ib) { +		radeon_ib_free(parser->rdev, &parser->const_ib); +	}  }  static int radeon_cs_ib_chunk(struct radeon_device *rdev, @@ -507,6 +501,16 @@ out:  	return r;  } +static int radeon_cs_handle_lockup(struct radeon_device *rdev, int r) +{ +	if (r == -EDEADLK) { +		r = radeon_gpu_reset(rdev); +		if (!r) +			r = -EAGAIN; +	} +	return r; +} +  int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  {  	struct radeon_device *rdev = dev->dev_private; @@ -528,6 +532,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  	if (r) {  		DRM_ERROR("Failed to initialize parser !\n");  		radeon_cs_parser_fini(&parser, r); +		r = radeon_cs_handle_lockup(rdev, r);  		radeon_mutex_unlock(&rdev->cs_mutex);  		return r;  	} @@ -536,6 +541,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  		if (r != -ERESTARTSYS)  			DRM_ERROR("Failed to parse relocation %d!\n", r);  		radeon_cs_parser_fini(&parser, r); +		r = radeon_cs_handle_lockup(rdev, r);  		radeon_mutex_unlock(&rdev->cs_mutex);  		return r;  	} @@ -549,6 +555,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  	}  out:  	radeon_cs_parser_fini(&parser, r); +	r = radeon_cs_handle_lockup(rdev, r);  	radeon_mutex_unlock(&rdev->cs_mutex);  	return r;  } diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 76a118df04f..ff28210dede 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -714,7 +714,6 @@ int radeon_device_init(struct radeon_device *rdev,  	rdev->is_atom_bios = false;  	rdev->usec_timeout = RADEON_MAX_USEC_TIMEOUT;  	rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; -	rdev->gpu_lockup = false;  	rdev->accel_working = false;  	DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n", @@ -916,7 +915,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)  	radeon_bo_evict_vram(rdev);  	/* wait for gpu to finish processing current batch */  	for (i = 0; i < RADEON_NUM_RINGS; i++) -		radeon_fence_wait_last(rdev, i); +		radeon_fence_wait_empty(rdev, i);  	radeon_save_bios_scratch_regs(rdev); @@ -987,9 +986,6 @@ int radeon_gpu_reset(struct radeon_device *rdev)  	int r;  	int resched; -	/* Prevent CS ioctl from interfering */ -	radeon_mutex_lock(&rdev->cs_mutex); -  	radeon_save_bios_scratch_regs(rdev);  	/* block TTM */  	resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); @@ -1004,8 +1000,6 @@ int radeon_gpu_reset(struct radeon_device *rdev)  		ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);  	} -	radeon_mutex_unlock(&rdev->cs_mutex); -  	if (r) {  		/* bad news, how to tell it to userspace ? */  		dev_info(rdev->dev, "GPU reset failed\n"); diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index ef7bb3f6eca..e62e56a57ee 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -128,6 +128,7 @@ int radeon_disp_priority = 0;  int radeon_hw_i2c = 0;  int radeon_pcie_gen2 = 0;  int radeon_msi = -1; +int radeon_lockup_timeout = 10000;  MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");  module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -177,6 +178,9 @@ module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444);  MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)");  module_param_named(msi, radeon_msi, int, 0444); +MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (defaul 10000 = 10 seconds, 0 = disable)"); +module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444); +  static int radeon_suspend(struct drm_device *dev, pm_message_t state)  {  	drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 4bd36a354fb..5bb78bf547e 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -71,16 +71,13 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence)  		return 0;  	}  	fence->seq = atomic_add_return(1, &rdev->fence_drv[fence->ring].seq); -	if (!rdev->ring[fence->ring].ready) -		/* FIXME: cp is not running assume everythings is done right -		 * away -		 */ -		radeon_fence_write(rdev, fence->seq, fence->ring); -	else -		radeon_fence_ring_emit(rdev, fence->ring, fence); - +	radeon_fence_ring_emit(rdev, fence->ring, fence);  	trace_radeon_fence_emit(rdev->ddev, fence->seq);  	fence->emitted = true; +	/* are we the first fence on a previusly idle ring? */ +	if (list_empty(&rdev->fence_drv[fence->ring].emitted)) { +		rdev->fence_drv[fence->ring].last_activity = jiffies; +	}  	list_move_tail(&fence->list, &rdev->fence_drv[fence->ring].emitted);  	write_unlock_irqrestore(&rdev->fence_lock, irq_flags);  	return 0; @@ -92,34 +89,14 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev, int ring)  	struct list_head *i, *n;  	uint32_t seq;  	bool wake = false; -	unsigned long cjiffies;  	seq = radeon_fence_read(rdev, ring); -	if (seq != rdev->fence_drv[ring].last_seq) { -		rdev->fence_drv[ring].last_seq = seq; -		rdev->fence_drv[ring].last_jiffies = jiffies; -		rdev->fence_drv[ring].last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT; -	} else { -		cjiffies = jiffies; -		if (time_after(cjiffies, rdev->fence_drv[ring].last_jiffies)) { -			cjiffies -= rdev->fence_drv[ring].last_jiffies; -			if (time_after(rdev->fence_drv[ring].last_timeout, cjiffies)) { -				/* update the timeout */ -				rdev->fence_drv[ring].last_timeout -= cjiffies; -			} else { -				/* the 500ms timeout is elapsed we should test -				 * for GPU lockup -				 */ -				rdev->fence_drv[ring].last_timeout = 1; -			} -		} else { -			/* wrap around update last jiffies, we will just wait -			 * a little longer -			 */ -			rdev->fence_drv[ring].last_jiffies = cjiffies; -		} +	if (seq == rdev->fence_drv[ring].last_seq)  		return false; -	} + +	rdev->fence_drv[ring].last_seq = seq; +	rdev->fence_drv[ring].last_activity = jiffies; +  	n = NULL;  	list_for_each(i, &rdev->fence_drv[ring].emitted) {  		fence = list_entry(i, struct radeon_fence, list); @@ -162,8 +139,6 @@ int radeon_fence_create(struct radeon_device *rdev,  			struct radeon_fence **fence,  			int ring)  { -	unsigned long irq_flags; -  	*fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL);  	if ((*fence) == NULL) {  		return -ENOMEM; @@ -176,10 +151,6 @@ int radeon_fence_create(struct radeon_device *rdev,  	(*fence)->ring = ring;  	(*fence)->semaphore = NULL;  	INIT_LIST_HEAD(&(*fence)->list); - -	write_lock_irqsave(&rdev->fence_lock, irq_flags); -	list_add_tail(&(*fence)->list, &rdev->fence_drv[ring].created); -	write_unlock_irqrestore(&rdev->fence_lock, irq_flags);  	return 0;  } @@ -191,9 +162,6 @@ bool radeon_fence_signaled(struct radeon_fence *fence)  	if (!fence)  		return true; -	if (fence->rdev->gpu_lockup) -		return true; -  	write_lock_irqsave(&fence->rdev->fence_lock, irq_flags);  	signaled = fence->signaled;  	/* if we are shuting down report all fence as signaled */ @@ -217,68 +185,80 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr)  	struct radeon_device *rdev;  	unsigned long irq_flags, timeout;  	u32 seq; -	int r; +	int i, r; +	bool signaled;  	if (fence == NULL) {  		WARN(1, "Querying an invalid fence : %p !\n", fence); -		return 0; +		return -EINVAL;  	} +  	rdev = fence->rdev; -	if (radeon_fence_signaled(fence)) { -		return 0; -	} -	timeout = rdev->fence_drv[fence->ring].last_timeout; -retry: -	/* save current sequence used to check for GPU lockup */ -	seq = rdev->fence_drv[fence->ring].last_seq; -	trace_radeon_fence_wait_begin(rdev->ddev, seq); -	if (intr) { +	signaled = radeon_fence_signaled(fence); +	while (!signaled) { +		read_lock_irqsave(&rdev->fence_lock, irq_flags); +		timeout = jiffies - RADEON_FENCE_JIFFIES_TIMEOUT; +		if (time_after(rdev->fence_drv[fence->ring].last_activity, timeout)) { +			/* the normal case, timeout is somewhere before last_activity */ +			timeout = rdev->fence_drv[fence->ring].last_activity - timeout; +		} else { +			/* either jiffies wrapped around, or no fence was signaled in the last 500ms +			 * anyway we will just wait for the minimum amount and then check for a lockup */ +			timeout = 1; +		} +		/* save current sequence value used to check for GPU lockups */ +		seq = rdev->fence_drv[fence->ring].last_seq; +		read_unlock_irqrestore(&rdev->fence_lock, irq_flags); + +		trace_radeon_fence_wait_begin(rdev->ddev, seq);  		radeon_irq_kms_sw_irq_get(rdev, fence->ring); -		r = wait_event_interruptible_timeout(rdev->fence_drv[fence->ring].queue, -				radeon_fence_signaled(fence), timeout); +		if (intr) { +			r = wait_event_interruptible_timeout( +				rdev->fence_drv[fence->ring].queue, +				(signaled = radeon_fence_signaled(fence)), timeout); +		} else { +			r = wait_event_timeout( +				rdev->fence_drv[fence->ring].queue, +				(signaled = radeon_fence_signaled(fence)), timeout); +		}  		radeon_irq_kms_sw_irq_put(rdev, fence->ring);  		if (unlikely(r < 0)) {  			return r;  		} -	} else { -		radeon_irq_kms_sw_irq_get(rdev, fence->ring); -		r = wait_event_timeout(rdev->fence_drv[fence->ring].queue, -			 radeon_fence_signaled(fence), timeout); -		radeon_irq_kms_sw_irq_put(rdev, fence->ring); -	} -	trace_radeon_fence_wait_end(rdev->ddev, seq); -	if (unlikely(!radeon_fence_signaled(fence))) { -		/* we were interrupted for some reason and fence isn't -		 * isn't signaled yet, resume wait -		 */ -		if (r) { -			timeout = r; -			goto retry; -		} -		/* don't protect read access to rdev->fence_drv[t].last_seq -		 * if we experiencing a lockup the value doesn't change -		 */ -		if (seq == rdev->fence_drv[fence->ring].last_seq && -		    radeon_gpu_is_lockup(rdev, &rdev->ring[fence->ring])) { -			/* good news we believe it's a lockup */ -			printk(KERN_WARNING "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", -			     fence->seq, seq); -			/* FIXME: what should we do ? marking everyone -			 * as signaled for now -			 */ -			rdev->gpu_lockup = true; -			r = radeon_gpu_reset(rdev); -			if (r) -				return r; -			radeon_fence_write(rdev, fence->seq, fence->ring); -			rdev->gpu_lockup = false; +		trace_radeon_fence_wait_end(rdev->ddev, seq); + +		if (unlikely(!signaled)) { +			/* we were interrupted for some reason and fence +			 * isn't signaled yet, resume waiting */ +			if (r) { +				continue; +			} + +			write_lock_irqsave(&rdev->fence_lock, irq_flags); +			/* check if sequence value has changed since last_activity */ +			if (seq != rdev->fence_drv[fence->ring].last_seq) { +				write_unlock_irqrestore(&rdev->fence_lock, irq_flags); +				continue; +			} + +			/* change sequence value on all rings, so nobody else things there is a lockup */ +			for (i = 0; i < RADEON_NUM_RINGS; ++i) +				rdev->fence_drv[i].last_seq -= 0x10000; + +			rdev->fence_drv[fence->ring].last_activity = jiffies; +			write_unlock_irqrestore(&rdev->fence_lock, irq_flags); + +			if (radeon_ring_is_lockup(rdev, fence->ring, &rdev->ring[fence->ring])) { + +				/* good news we believe it's a lockup */ +				printk(KERN_WARNING "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", +				     fence->seq, seq); + +				/* mark the ring as not ready any more */ +				rdev->ring[fence->ring].ready = false; +				return -EDEADLK; +			}  		} -		timeout = RADEON_FENCE_JIFFIES_TIMEOUT; -		write_lock_irqsave(&rdev->fence_lock, irq_flags); -		rdev->fence_drv[fence->ring].last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT; -		rdev->fence_drv[fence->ring].last_jiffies = jiffies; -		write_unlock_irqrestore(&rdev->fence_lock, irq_flags); -		goto retry;  	}  	return 0;  } @@ -289,13 +269,14 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring)  	struct radeon_fence *fence;  	int r; -	if (rdev->gpu_lockup) { -		return 0; -	}  	write_lock_irqsave(&rdev->fence_lock, irq_flags); +	if (!rdev->ring[ring].ready) { +		write_unlock_irqrestore(&rdev->fence_lock, irq_flags); +		return -EBUSY; +	}  	if (list_empty(&rdev->fence_drv[ring].emitted)) {  		write_unlock_irqrestore(&rdev->fence_lock, irq_flags); -		return 0; +		return -ENOENT;  	}  	fence = list_entry(rdev->fence_drv[ring].emitted.next,  			   struct radeon_fence, list); @@ -306,16 +287,17 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring)  	return r;  } -int radeon_fence_wait_last(struct radeon_device *rdev, int ring) +int radeon_fence_wait_empty(struct radeon_device *rdev, int ring)  {  	unsigned long irq_flags;  	struct radeon_fence *fence;  	int r; -	if (rdev->gpu_lockup) { -		return 0; -	}  	write_lock_irqsave(&rdev->fence_lock, irq_flags); +	if (!rdev->ring[ring].ready) { +		write_unlock_irqrestore(&rdev->fence_lock, irq_flags); +		return -EBUSY; +	}  	if (list_empty(&rdev->fence_drv[ring].emitted)) {  		write_unlock_irqrestore(&rdev->fence_lock, irq_flags);  		return 0; @@ -419,7 +401,6 @@ static void radeon_fence_driver_init_ring(struct radeon_device *rdev, int ring)  	rdev->fence_drv[ring].cpu_addr = NULL;  	rdev->fence_drv[ring].gpu_addr = 0;  	atomic_set(&rdev->fence_drv[ring].seq, 0); -	INIT_LIST_HEAD(&rdev->fence_drv[ring].created);  	INIT_LIST_HEAD(&rdev->fence_drv[ring].emitted);  	INIT_LIST_HEAD(&rdev->fence_drv[ring].signaled);  	init_waitqueue_head(&rdev->fence_drv[ring].queue); @@ -450,7 +431,7 @@ void radeon_fence_driver_fini(struct radeon_device *rdev)  	for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {  		if (!rdev->fence_drv[ring].initialized)  			continue; -		radeon_fence_wait_last(rdev, ring); +		radeon_fence_wait_empty(rdev, ring);  		wake_up_all(&rdev->fence_drv[ring].queue);  		write_lock_irqsave(&rdev->fence_lock, irq_flags);  		radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index c7008b5210f..e15cb1fe2c3 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -154,6 +154,17 @@ void radeon_gem_object_close(struct drm_gem_object *obj,  	radeon_bo_unreserve(rbo);  } +static int radeon_gem_handle_lockup(struct radeon_device *rdev, int r) +{ +	if (r == -EDEADLK) { +		radeon_mutex_lock(&rdev->cs_mutex); +		r = radeon_gpu_reset(rdev); +		if (!r) +			r = -EAGAIN; +		radeon_mutex_unlock(&rdev->cs_mutex); +	} +	return r; +}  /*   * GEM ioctls. @@ -210,12 +221,14 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data,  					args->initial_domain, false,  					false, &gobj);  	if (r) { +		r = radeon_gem_handle_lockup(rdev, r);  		return r;  	}  	r = drm_gem_handle_create(filp, gobj, &handle);  	/* drop reference from allocate - handle holds it now */  	drm_gem_object_unreference_unlocked(gobj);  	if (r) { +		r = radeon_gem_handle_lockup(rdev, r);  		return r;  	}  	args->handle = handle; @@ -245,6 +258,7 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,  	r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain);  	drm_gem_object_unreference_unlocked(gobj); +	r = radeon_gem_handle_lockup(robj->rdev, r);  	return r;  } @@ -301,6 +315,7 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,  		break;  	}  	drm_gem_object_unreference_unlocked(gobj); +	r = radeon_gem_handle_lockup(robj->rdev, r);  	return r;  } @@ -322,6 +337,7 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,  	if (robj->rdev->asic->ioctl_wait_idle)  		robj->rdev->asic->ioctl_wait_idle(robj->rdev, robj);  	drm_gem_object_unreference_unlocked(gobj); +	r = radeon_gem_handle_lockup(robj->rdev, r);  	return r;  } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 0c3cdbd614d..499a5fed8b2 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -210,6 +210,7 @@ enum radeon_connector_table {  	CT_RN50_POWER,  	CT_MAC_X800,  	CT_MAC_G5_9600, +	CT_SAM440EP  };  enum radeon_dvo_chip { diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index cc33b3d7c33..2eb4c6ed198 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -34,7 +34,7 @@  #include "atom.h"  int radeon_debugfs_ib_init(struct radeon_device *rdev); -int radeon_debugfs_ring_init(struct radeon_device *rdev); +int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring);  u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx)  { @@ -237,9 +237,6 @@ int radeon_ib_pool_init(struct radeon_device *rdev)  	if (radeon_debugfs_ib_init(rdev)) {  		DRM_ERROR("Failed to register debugfs file for IB !\n");  	} -	if (radeon_debugfs_ring_init(rdev)) { -		DRM_ERROR("Failed to register debugfs file for rings !\n"); -	}  	radeon_mutex_unlock(&rdev->ib_pool.mutex);  	return 0;  } @@ -270,6 +267,36 @@ int radeon_ib_pool_suspend(struct radeon_device *rdev)  	return radeon_sa_bo_manager_suspend(rdev, &rdev->ib_pool.sa_manager);  } +int radeon_ib_ring_tests(struct radeon_device *rdev) +{ +	unsigned i; +	int r; + +	for (i = 0; i < RADEON_NUM_RINGS; ++i) { +		struct radeon_ring *ring = &rdev->ring[i]; + +		if (!ring->ready) +			continue; + +		r = radeon_ib_test(rdev, i, ring); +		if (r) { +			ring->ready = false; + +			if (i == RADEON_RING_TYPE_GFX_INDEX) { +				/* oh, oh, that's really bad */ +				DRM_ERROR("radeon: failed testing IB on GFX ring (%d).\n", r); +		                rdev->accel_working = false; +				return r; + +			} else { +				/* still not good, but we can live with it */ +				DRM_ERROR("radeon: failed testing IB on ring %d (%d).\n", i, r); +			} +		} +	} +	return 0; +} +  /*   * Ring.   */ @@ -319,7 +346,9 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi  		if (ndw < ring->ring_free_dw) {  			break;  		} +		mutex_unlock(&ring->mutex);  		r = radeon_fence_wait_next(rdev, radeon_ring_index(rdev, ring)); +		mutex_lock(&ring->mutex);  		if (r)  			return r;  	} @@ -369,6 +398,75 @@ void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *rin  	mutex_unlock(&ring->mutex);  } +void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring) +{ +	int r; + +	mutex_lock(&ring->mutex); +	radeon_ring_free_size(rdev, ring); +	if (ring->rptr == ring->wptr) { +		r = radeon_ring_alloc(rdev, ring, 1); +		if (!r) { +			radeon_ring_write(ring, ring->nop); +			radeon_ring_commit(rdev, ring); +		} +	} +	mutex_unlock(&ring->mutex); +} + +void radeon_ring_lockup_update(struct radeon_ring *ring) +{ +	ring->last_rptr = ring->rptr; +	ring->last_activity = jiffies; +} + +/** + * radeon_ring_test_lockup() - check if ring is lockedup by recording information + * @rdev:       radeon device structure + * @ring:       radeon_ring structure holding ring information + * + * We don't need to initialize the lockup tracking information as we will either + * have CP rptr to a different value of jiffies wrap around which will force + * initialization of the lockup tracking informations. + * + * A possible false positivie is if we get call after while and last_cp_rptr == + * the current CP rptr, even if it's unlikely it might happen. To avoid this + * if the elapsed time since last call is bigger than 2 second than we return + * false and update the tracking information. Due to this the caller must call + * radeon_ring_test_lockup several time in less than 2sec for lockup to be reported + * the fencing code should be cautious about that. + * + * Caller should write to the ring to force CP to do something so we don't get + * false positive when CP is just gived nothing to do. + * + **/ +bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring) +{ +	unsigned long cjiffies, elapsed; +	uint32_t rptr; + +	cjiffies = jiffies; +	if (!time_after(cjiffies, ring->last_activity)) { +		/* likely a wrap around */ +		radeon_ring_lockup_update(ring); +		return false; +	} +	rptr = RREG32(ring->rptr_reg); +	ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift; +	if (ring->rptr != ring->last_rptr) { +		/* CP is still working no lockup */ +		radeon_ring_lockup_update(ring); +		return false; +	} +	elapsed = jiffies_to_msecs(cjiffies - ring->last_activity); +	if (radeon_lockup_timeout && elapsed >= radeon_lockup_timeout) { +		dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed); +		return true; +	} +	/* give a chance to the GPU ... */ +	return false; +} +  int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ring_size,  		     unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg,  		     u32 ptr_reg_shift, u32 ptr_reg_mask, u32 nop) @@ -411,6 +509,9 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig  	}  	ring->ptr_mask = (ring->ring_size / 4) - 1;  	ring->ring_free_dw = ring->ring_size / 4; +	if (radeon_debugfs_ring_init(rdev, ring)) { +		DRM_ERROR("Failed to register debugfs file for rings !\n"); +	}  	return 0;  } @@ -501,17 +602,24 @@ static char radeon_debugfs_ib_names[RADEON_IB_POOL_SIZE][32];  static unsigned radeon_debugfs_ib_idx[RADEON_IB_POOL_SIZE];  #endif -int radeon_debugfs_ring_init(struct radeon_device *rdev) +int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring)  {  #if defined(CONFIG_DEBUG_FS) -	if (rdev->family >= CHIP_CAYMAN) -		return radeon_debugfs_add_files(rdev, radeon_debugfs_ring_info_list, -						ARRAY_SIZE(radeon_debugfs_ring_info_list)); -	else -		return radeon_debugfs_add_files(rdev, radeon_debugfs_ring_info_list, 1); -#else -	return 0; +	unsigned i; +	for (i = 0; i < ARRAY_SIZE(radeon_debugfs_ring_info_list); ++i) { +		struct drm_info_list *info = &radeon_debugfs_ring_info_list[i]; +		int ridx = *(int*)radeon_debugfs_ring_info_list[i].data; +		unsigned r; + +		if (&rdev->ring[ridx] != ring) +			continue; + +		r = radeon_debugfs_add_files(rdev, info, 1); +		if (r) +			return r; +	}  #endif +	return 0;  }  int radeon_debugfs_ib_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index 4cce47e7dc0..8fbfe69b7bc 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -150,7 +150,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev,  	offset = 0;  	list_for_each_entry(tmp, &sa_manager->sa_bo, list) {  		/* room before this object ? */ -		if ((tmp->offset - offset) >= size) { +		if (offset < tmp->offset && (tmp->offset - offset) >= size) {  			head = tmp->list.prev;  			goto out;  		} diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c index 61dd4e3c920..930a08af900 100644 --- a/drivers/gpu/drm/radeon/radeon_semaphore.c +++ b/drivers/gpu/drm/radeon/radeon_semaphore.c @@ -149,6 +149,62 @@ void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring,  	radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, true);  } +int radeon_semaphore_sync_rings(struct radeon_device *rdev, +				struct radeon_semaphore *semaphore, +				bool sync_to[RADEON_NUM_RINGS], +				int dst_ring) +{ +	int i, r; + +	for (i = 0; i < RADEON_NUM_RINGS; ++i) { +		unsigned num_ops = i == dst_ring ? RADEON_NUM_RINGS : 1; + +		/* don't lock unused rings */ +		if (!sync_to[i] && i != dst_ring) +			continue; + +		/* prevent GPU deadlocks */ +		if (!rdev->ring[i].ready) { +			dev_err(rdev->dev, "Trying to sync to a disabled ring!"); +			r = -EINVAL; +			goto error; +		} + +                r = radeon_ring_lock(rdev, &rdev->ring[i], num_ops * 8); +                if (r) +			goto error; +	} + +	for (i = 0; i < RADEON_NUM_RINGS; ++i) { +		/* no need to sync to our own or unused rings */ +		if (!sync_to[i] || i == dst_ring) +                        continue; + +		radeon_semaphore_emit_signal(rdev, i, semaphore); +		radeon_semaphore_emit_wait(rdev, dst_ring, semaphore); +	} + +	for (i = 0; i < RADEON_NUM_RINGS; ++i) { + +		/* don't unlock unused rings */ +		if (!sync_to[i] && i != dst_ring) +			continue; + +		radeon_ring_unlock_commit(rdev, &rdev->ring[i]); +	} + +	return 0; + +error: +	/* unlock all locks taken so far */ +	for (--i; i >= 0; --i) { +		if (sync_to[i] || i == dst_ring) { +			radeon_ring_unlock_undo(rdev, &rdev->ring[i]); +		} +	} +	return r; +} +  void radeon_semaphore_free(struct radeon_device *rdev,  			   struct radeon_semaphore *semaphore)  { diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index f493c6403af..5e3d54ded1b 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -222,8 +222,8 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,  {  	struct radeon_device *rdev;  	uint64_t old_start, new_start; -	struct radeon_fence *fence; -	int r, i; +	struct radeon_fence *fence, *old_fence; +	int r;  	rdev = radeon_get_rdev(bo->bdev);  	r = radeon_fence_create(rdev, &fence, radeon_copy_ring_index(rdev)); @@ -242,6 +242,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,  		break;  	default:  		DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); +		radeon_fence_unref(&fence);  		return -EINVAL;  	}  	switch (new_mem->mem_type) { @@ -253,42 +254,35 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,  		break;  	default:  		DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); +		radeon_fence_unref(&fence);  		return -EINVAL;  	}  	if (!rdev->ring[radeon_copy_ring_index(rdev)].ready) {  		DRM_ERROR("Trying to move memory with ring turned off.\n"); +		radeon_fence_unref(&fence);  		return -EINVAL;  	}  	BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0);  	/* sync other rings */ -	if (rdev->family >= CHIP_R600) { -		for (i = 0; i < RADEON_NUM_RINGS; ++i) { -			/* no need to sync to our own or unused rings */ -			if (i == radeon_copy_ring_index(rdev) || !rdev->ring[i].ready) -				continue; - -			if (!fence->semaphore) { -				r = radeon_semaphore_create(rdev, &fence->semaphore); -				/* FIXME: handle semaphore error */ -				if (r) -					continue; -			} +	old_fence = bo->sync_obj; +	if (old_fence && old_fence->ring != fence->ring +	    && !radeon_fence_signaled(old_fence)) { +		bool sync_to_ring[RADEON_NUM_RINGS] = { }; +		sync_to_ring[old_fence->ring] = true; -			r = radeon_ring_lock(rdev, &rdev->ring[i], 3); -			/* FIXME: handle ring lock error */ -			if (r) -				continue; -			radeon_semaphore_emit_signal(rdev, i, fence->semaphore); -			radeon_ring_unlock_commit(rdev, &rdev->ring[i]); +		r = radeon_semaphore_create(rdev, &fence->semaphore); +		if (r) { +			radeon_fence_unref(&fence); +			return r; +		} -			r = radeon_ring_lock(rdev, &rdev->ring[radeon_copy_ring_index(rdev)], 3); -			/* FIXME: handle ring lock error */ -			if (r) -				continue; -			radeon_semaphore_emit_wait(rdev, radeon_copy_ring_index(rdev), fence->semaphore); -			radeon_ring_unlock_commit(rdev, &rdev->ring[radeon_copy_ring_index(rdev)]); +		r = radeon_semaphore_sync_rings(rdev, fence->semaphore, +						sync_to_ring, fence->ring); +		if (r) { +			radeon_fence_unref(&fence); +			return r;  		}  	} diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 4cf381b3a6d..a464eb5e2df 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -430,12 +430,9 @@ static int rs400_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		dev_err(rdev->dev, "failed testing IB (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	}  	return 0;  } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 10706c66b84..25f9eef12c4 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -396,7 +396,6 @@ int rs600_asic_reset(struct radeon_device *rdev)  	/* Check if GPU is idle */  	if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {  		dev_err(rdev->dev, "failed to reset GPU\n"); -		rdev->gpu_lockup = true;  		ret = -1;  	} else  		dev_info(rdev->dev, "GPU reset succeed\n"); @@ -919,12 +918,9 @@ static int rs600_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		dev_err(rdev->dev, "failed testing IB (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	}  	return 0;  } diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index f2c3b9d75f1..3277ddecfe9 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -647,12 +647,9 @@ static int rs690_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		dev_err(rdev->dev, "failed testing IB (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	}  	return 0;  } diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index d8d78fe1794..7f08cedb533 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -412,12 +412,10 @@ static int rv515_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		dev_err(rdev->dev, "failed testing IB (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	} +  	return 0;  } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index cdab1aeaed6..a8b001641e4 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1114,12 +1114,9 @@ static int rv770_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); -	if (r) { -		dev_err(rdev->dev, "IB test failed (%d).\n", r); -		rdev->accel_working = false; +	r = radeon_ib_ring_tests(rdev); +	if (r)  		return r; -	}  	return 0;  } diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 9727a16c040..779f0b604fa 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2217,8 +2217,6 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  	u32 srbm_status;  	u32 grbm_status, grbm_status2;  	u32 grbm_status_se0, grbm_status_se1; -	struct r100_gpu_lockup *lockup = &rdev->config.si.lockup; -	int r;  	srbm_status = RREG32(SRBM_STATUS);  	grbm_status = RREG32(GRBM_STATUS); @@ -2226,20 +2224,12 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  	grbm_status_se0 = RREG32(GRBM_STATUS_SE0);  	grbm_status_se1 = RREG32(GRBM_STATUS_SE1);  	if (!(grbm_status & GUI_ACTIVE)) { -		r100_gpu_lockup_update(lockup, ring); +		radeon_ring_lockup_update(ring);  		return false;  	}  	/* force CP activities */ -	r = radeon_ring_lock(rdev, ring, 2); -	if (!r) { -		/* PACKET2 NOP */ -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_write(ring, 0x80000000); -		radeon_ring_unlock_commit(rdev, ring); -	} -	/* XXX deal with CP0,1,2 */ -	ring->rptr = RREG32(ring->rptr_reg); -	return r100_gpu_cp_is_lockup(rdev, lockup, ring); +	radeon_ring_force_activity(rdev, ring); +	return radeon_ring_test_lockup(rdev, ring);  }  static int si_gpu_soft_reset(struct radeon_device *rdev) diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h index 367ab18dccf..0ee42d9acdc 100644 --- a/include/linux/vgaarb.h +++ b/include/linux/vgaarb.h @@ -183,8 +183,13 @@ extern void vga_put(struct pci_dev *pdev, unsigned int rsrc);   */  #ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE +#ifdef CONFIG_VGA_ARB  extern struct pci_dev *vga_default_device(void);  extern void vga_set_default_device(struct pci_dev *pdev); +#else +static inline struct pci_dev *vga_default_device(void) { return NULL; }; +static inline void vga_set_default_device(struct pci_dev *pdev) { }; +#endif  #endif  /**  |