diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/evergreen.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/evergreen.c | 270 | 
1 files changed, 206 insertions, 64 deletions
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 7fb3d2e0434..e585a3b947e 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -99,6 +99,14 @@ void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)  	}  } +/** + * dce4_wait_for_vblank - vblank wait asic callback. + * + * @rdev: radeon_device pointer + * @crtc: crtc to wait for vblank on + * + * Wait for vblank on the requested crtc (evergreen+). + */  void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc)  {  	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; @@ -118,18 +126,49 @@ void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc)  	}  } +/** + * radeon_irq_kms_pflip_irq_get - pre-pageflip callback. + * + * @rdev: radeon_device pointer + * @crtc: crtc to prepare for pageflip on + * + * Pre-pageflip callback (evergreen+). + * Enables the pageflip irq (vblank irq). + */  void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc)  {  	/* enable the pflip int */  	radeon_irq_kms_pflip_irq_get(rdev, crtc);  } +/** + * evergreen_post_page_flip - pos-pageflip callback. + * + * @rdev: radeon_device pointer + * @crtc: crtc to cleanup pageflip on + * + * Post-pageflip callback (evergreen+). + * Disables the pageflip irq (vblank irq). + */  void evergreen_post_page_flip(struct radeon_device *rdev, int crtc)  {  	/* disable the pflip int */  	radeon_irq_kms_pflip_irq_put(rdev, crtc);  } +/** + * evergreen_page_flip - pageflip callback. + * + * @rdev: radeon_device pointer + * @crtc_id: crtc to cleanup pageflip on + * @crtc_base: new address of the crtc (GPU MC address) + * + * Does the actual pageflip (evergreen+). + * During vblank we take the crtc lock and wait for the update_pending + * bit to go high, when it does, we release the lock, and allow the + * double buffered update to take place. + * Returns the current update pending status. + */  u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)  {  	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; @@ -214,6 +253,15 @@ int sumo_get_temp(struct radeon_device *rdev)  	return actual_temp * 1000;  } +/** + * sumo_pm_init_profile - Initialize power profiles callback. + * + * @rdev: radeon_device pointer + * + * Initialize the power states used in profile mode + * (sumo, trinity, SI). + * Used for profile mode only. + */  void sumo_pm_init_profile(struct radeon_device *rdev)  {  	int idx; @@ -265,6 +313,14 @@ void sumo_pm_init_profile(struct radeon_device *rdev)  		rdev->pm.power_state[idx].num_clock_modes - 1;  } +/** + * evergreen_pm_misc - set additional pm hw parameters callback. + * + * @rdev: radeon_device pointer + * + * Set non-clock parameters associated with a power state + * (voltage, etc.) (evergreen+). + */  void evergreen_pm_misc(struct radeon_device *rdev)  {  	int req_ps_idx = rdev->pm.requested_power_state_index; @@ -292,6 +348,13 @@ void evergreen_pm_misc(struct radeon_device *rdev)  	}  } +/** + * evergreen_pm_prepare - pre-power state change callback. + * + * @rdev: radeon_device pointer + * + * Prepare for a power state change (evergreen+). + */  void evergreen_pm_prepare(struct radeon_device *rdev)  {  	struct drm_device *ddev = rdev->ddev; @@ -310,6 +373,13 @@ void evergreen_pm_prepare(struct radeon_device *rdev)  	}  } +/** + * evergreen_pm_finish - post-power state change callback. + * + * @rdev: radeon_device pointer + * + * Clean up after a power state change (evergreen+). + */  void evergreen_pm_finish(struct radeon_device *rdev)  {  	struct drm_device *ddev = rdev->ddev; @@ -328,6 +398,15 @@ void evergreen_pm_finish(struct radeon_device *rdev)  	}  } +/** + * evergreen_hpd_sense - hpd sense callback. + * + * @rdev: radeon_device pointer + * @hpd: hpd (hotplug detect) pin + * + * Checks if a digital monitor is connected (evergreen+). + * Returns true if connected, false if not connected. + */  bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)  {  	bool connected = false; @@ -364,6 +443,14 @@ bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)  	return connected;  } +/** + * evergreen_hpd_set_polarity - hpd set polarity callback. + * + * @rdev: radeon_device pointer + * @hpd: hpd (hotplug detect) pin + * + * Set the polarity of the hpd pin (evergreen+). + */  void evergreen_hpd_set_polarity(struct radeon_device *rdev,  				enum radeon_hpd_id hpd)  { @@ -424,10 +511,19 @@ void evergreen_hpd_set_polarity(struct radeon_device *rdev,  	}  } +/** + * evergreen_hpd_init - hpd setup callback. + * + * @rdev: radeon_device pointer + * + * Setup the hpd pins used by the card (evergreen+). + * Enable the pin, set the polarity, and enable the hpd interrupts. + */  void evergreen_hpd_init(struct radeon_device *rdev)  {  	struct drm_device *dev = rdev->ddev;  	struct drm_connector *connector; +	unsigned enabled = 0;  	u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) |  		DC_HPDx_RX_INT_TIMER(0xfa) | DC_HPDx_EN; @@ -436,73 +532,72 @@ void evergreen_hpd_init(struct radeon_device *rdev)  		switch (radeon_connector->hpd.hpd) {  		case RADEON_HPD_1:  			WREG32(DC_HPD1_CONTROL, tmp); -			rdev->irq.hpd[0] = true;  			break;  		case RADEON_HPD_2:  			WREG32(DC_HPD2_CONTROL, tmp); -			rdev->irq.hpd[1] = true;  			break;  		case RADEON_HPD_3:  			WREG32(DC_HPD3_CONTROL, tmp); -			rdev->irq.hpd[2] = true;  			break;  		case RADEON_HPD_4:  			WREG32(DC_HPD4_CONTROL, tmp); -			rdev->irq.hpd[3] = true;  			break;  		case RADEON_HPD_5:  			WREG32(DC_HPD5_CONTROL, tmp); -			rdev->irq.hpd[4] = true;  			break;  		case RADEON_HPD_6:  			WREG32(DC_HPD6_CONTROL, tmp); -			rdev->irq.hpd[5] = true;  			break;  		default:  			break;  		}  		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); +		enabled |= 1 << radeon_connector->hpd.hpd;  	} -	if (rdev->irq.installed) -		evergreen_irq_set(rdev); +	radeon_irq_kms_enable_hpd(rdev, enabled);  } +/** + * evergreen_hpd_fini - hpd tear down callback. + * + * @rdev: radeon_device pointer + * + * Tear down the hpd pins used by the card (evergreen+). + * Disable the hpd interrupts. + */  void evergreen_hpd_fini(struct radeon_device *rdev)  {  	struct drm_device *dev = rdev->ddev;  	struct drm_connector *connector; +	unsigned disabled = 0;  	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {  		struct radeon_connector *radeon_connector = to_radeon_connector(connector);  		switch (radeon_connector->hpd.hpd) {  		case RADEON_HPD_1:  			WREG32(DC_HPD1_CONTROL, 0); -			rdev->irq.hpd[0] = false;  			break;  		case RADEON_HPD_2:  			WREG32(DC_HPD2_CONTROL, 0); -			rdev->irq.hpd[1] = false;  			break;  		case RADEON_HPD_3:  			WREG32(DC_HPD3_CONTROL, 0); -			rdev->irq.hpd[2] = false;  			break;  		case RADEON_HPD_4:  			WREG32(DC_HPD4_CONTROL, 0); -			rdev->irq.hpd[3] = false;  			break;  		case RADEON_HPD_5:  			WREG32(DC_HPD5_CONTROL, 0); -			rdev->irq.hpd[4] = false;  			break;  		case RADEON_HPD_6:  			WREG32(DC_HPD6_CONTROL, 0); -			rdev->irq.hpd[5] = false;  			break;  		default:  			break;  		} +		disabled |= 1 << radeon_connector->hpd.hpd;  	} +	radeon_irq_kms_disable_hpd(rdev, disabled);  }  /* watermark setup */ @@ -933,6 +1028,14 @@ static void evergreen_program_watermarks(struct radeon_device *rdev,  } +/** + * evergreen_bandwidth_update - update display watermarks callback. + * + * @rdev: radeon_device pointer + * + * Update the display watermarks based on the requested mode(s) + * (evergreen+). + */  void evergreen_bandwidth_update(struct radeon_device *rdev)  {  	struct drm_display_mode *mode0 = NULL; @@ -956,6 +1059,15 @@ void evergreen_bandwidth_update(struct radeon_device *rdev)  	}  } +/** + * evergreen_mc_wait_for_idle - wait for MC idle callback. + * + * @rdev: radeon_device pointer + * + * Wait for the MC (memory controller) to be idle. + * (evergreen+). + * Returns 0 if the MC is idle, -1 if not. + */  int evergreen_mc_wait_for_idle(struct radeon_device *rdev)  {  	unsigned i; @@ -1371,12 +1483,28 @@ void evergreen_mc_program(struct radeon_device *rdev)   */  void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)  { -	struct radeon_ring *ring = &rdev->ring[ib->fence->ring]; +	struct radeon_ring *ring = &rdev->ring[ib->ring]; +	u32 next_rptr;  	/* set to DX10/11 mode */  	radeon_ring_write(ring, PACKET3(PACKET3_MODE_CONTROL, 0));  	radeon_ring_write(ring, 1); -	/* FIXME: implement */ + +	if (ring->rptr_save_reg) { +		next_rptr = ring->wptr + 3 + 4; +		radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); +		radeon_ring_write(ring, ((ring->rptr_save_reg -  +					  PACKET3_SET_CONFIG_REG_START) >> 2)); +		radeon_ring_write(ring, next_rptr); +	} else if (rdev->wb.enabled) { +		next_rptr = ring->wptr + 5 + 4; +		radeon_ring_write(ring, PACKET3(PACKET3_MEM_WRITE, 3)); +		radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc); +		radeon_ring_write(ring, (upper_32_bits(ring->next_rptr_gpu_addr) & 0xff) | (1 << 18)); +		radeon_ring_write(ring, next_rptr); +		radeon_ring_write(ring, 0); +	} +  	radeon_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));  	radeon_ring_write(ring,  #ifdef __BIG_ENDIAN @@ -2188,6 +2316,14 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev)  		RREG32(GRBM_STATUS_SE1));  	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",  		RREG32(SRBM_STATUS)); +	dev_info(rdev->dev, "  R_008674_CP_STALLED_STAT1 = 0x%08X\n", +		RREG32(CP_STALLED_STAT1)); +	dev_info(rdev->dev, "  R_008678_CP_STALLED_STAT2 = 0x%08X\n", +		RREG32(CP_STALLED_STAT2)); +	dev_info(rdev->dev, "  R_00867C_CP_BUSY_STAT     = 0x%08X\n", +		RREG32(CP_BUSY_STAT)); +	dev_info(rdev->dev, "  R_008680_CP_STAT          = 0x%08X\n", +		RREG32(CP_STAT));  	evergreen_mc_stop(rdev, &save);  	if (evergreen_mc_wait_for_idle(rdev)) {  		dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); @@ -2225,6 +2361,14 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev)  		RREG32(GRBM_STATUS_SE1));  	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",  		RREG32(SRBM_STATUS)); +	dev_info(rdev->dev, "  R_008674_CP_STALLED_STAT1 = 0x%08X\n", +		RREG32(CP_STALLED_STAT1)); +	dev_info(rdev->dev, "  R_008678_CP_STALLED_STAT2 = 0x%08X\n", +		RREG32(CP_STALLED_STAT2)); +	dev_info(rdev->dev, "  R_00867C_CP_BUSY_STAT     = 0x%08X\n", +		RREG32(CP_BUSY_STAT)); +	dev_info(rdev->dev, "  R_008680_CP_STAT          = 0x%08X\n", +		RREG32(CP_STAT));  	evergreen_mc_resume(rdev, &save);  	return 0;  } @@ -2348,20 +2492,20 @@ int evergreen_irq_set(struct radeon_device *rdev)  	if (rdev->family >= CHIP_CAYMAN) {  		/* enable CP interrupts on all rings */ -		if (rdev->irq.sw_int[RADEON_RING_TYPE_GFX_INDEX]) { +		if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {  			DRM_DEBUG("evergreen_irq_set: sw int gfx\n");  			cp_int_cntl |= TIME_STAMP_INT_ENABLE;  		} -		if (rdev->irq.sw_int[CAYMAN_RING_TYPE_CP1_INDEX]) { +		if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_CP1_INDEX])) {  			DRM_DEBUG("evergreen_irq_set: sw int cp1\n");  			cp_int_cntl1 |= TIME_STAMP_INT_ENABLE;  		} -		if (rdev->irq.sw_int[CAYMAN_RING_TYPE_CP2_INDEX]) { +		if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_CP2_INDEX])) {  			DRM_DEBUG("evergreen_irq_set: sw int cp2\n");  			cp_int_cntl2 |= TIME_STAMP_INT_ENABLE;  		}  	} else { -		if (rdev->irq.sw_int[RADEON_RING_TYPE_GFX_INDEX]) { +		if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {  			DRM_DEBUG("evergreen_irq_set: sw int gfx\n");  			cp_int_cntl |= RB_INT_ENABLE;  			cp_int_cntl |= TIME_STAMP_INT_ENABLE; @@ -2369,32 +2513,32 @@ int evergreen_irq_set(struct radeon_device *rdev)  	}  	if (rdev->irq.crtc_vblank_int[0] || -	    rdev->irq.pflip[0]) { +	    atomic_read(&rdev->irq.pflip[0])) {  		DRM_DEBUG("evergreen_irq_set: vblank 0\n");  		crtc1 |= VBLANK_INT_MASK;  	}  	if (rdev->irq.crtc_vblank_int[1] || -	    rdev->irq.pflip[1]) { +	    atomic_read(&rdev->irq.pflip[1])) {  		DRM_DEBUG("evergreen_irq_set: vblank 1\n");  		crtc2 |= VBLANK_INT_MASK;  	}  	if (rdev->irq.crtc_vblank_int[2] || -	    rdev->irq.pflip[2]) { +	    atomic_read(&rdev->irq.pflip[2])) {  		DRM_DEBUG("evergreen_irq_set: vblank 2\n");  		crtc3 |= VBLANK_INT_MASK;  	}  	if (rdev->irq.crtc_vblank_int[3] || -	    rdev->irq.pflip[3]) { +	    atomic_read(&rdev->irq.pflip[3])) {  		DRM_DEBUG("evergreen_irq_set: vblank 3\n");  		crtc4 |= VBLANK_INT_MASK;  	}  	if (rdev->irq.crtc_vblank_int[4] || -	    rdev->irq.pflip[4]) { +	    atomic_read(&rdev->irq.pflip[4])) {  		DRM_DEBUG("evergreen_irq_set: vblank 4\n");  		crtc5 |= VBLANK_INT_MASK;  	}  	if (rdev->irq.crtc_vblank_int[5] || -	    rdev->irq.pflip[5]) { +	    atomic_read(&rdev->irq.pflip[5])) {  		DRM_DEBUG("evergreen_irq_set: vblank 5\n");  		crtc6 |= VBLANK_INT_MASK;  	} @@ -2676,7 +2820,6 @@ int evergreen_irq_process(struct radeon_device *rdev)  	u32 rptr;  	u32 src_id, src_data;  	u32 ring_index; -	unsigned long flags;  	bool queue_hotplug = false;  	bool queue_hdmi = false; @@ -2684,22 +2827,21 @@ int evergreen_irq_process(struct radeon_device *rdev)  		return IRQ_NONE;  	wptr = evergreen_get_ih_wptr(rdev); + +restart_ih: +	/* is somebody else already processing irqs? */ +	if (atomic_xchg(&rdev->ih.lock, 1)) +		return IRQ_NONE; +  	rptr = rdev->ih.rptr;  	DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); -	spin_lock_irqsave(&rdev->ih.lock, flags); -	if (rptr == wptr) { -		spin_unlock_irqrestore(&rdev->ih.lock, flags); -		return IRQ_NONE; -	} -restart_ih:  	/* Order reading of wptr vs. reading of IH ring data */  	rmb();  	/* display interrupts */  	evergreen_irq_ack(rdev); -	rdev->ih.wptr = wptr;  	while (rptr != wptr) {  		/* wptr/rptr are in bytes! */  		ring_index = rptr / 4; @@ -2716,7 +2858,7 @@ restart_ih:  						rdev->pm.vblank_sync = true;  						wake_up(&rdev->irq.vblank_queue);  					} -					if (rdev->irq.pflip[0]) +					if (atomic_read(&rdev->irq.pflip[0]))  						radeon_crtc_handle_flip(rdev, 0);  					rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D1 vblank\n"); @@ -2742,7 +2884,7 @@ restart_ih:  						rdev->pm.vblank_sync = true;  						wake_up(&rdev->irq.vblank_queue);  					} -					if (rdev->irq.pflip[1]) +					if (atomic_read(&rdev->irq.pflip[1]))  						radeon_crtc_handle_flip(rdev, 1);  					rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D2 vblank\n"); @@ -2768,7 +2910,7 @@ restart_ih:  						rdev->pm.vblank_sync = true;  						wake_up(&rdev->irq.vblank_queue);  					} -					if (rdev->irq.pflip[2]) +					if (atomic_read(&rdev->irq.pflip[2]))  						radeon_crtc_handle_flip(rdev, 2);  					rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D3 vblank\n"); @@ -2794,7 +2936,7 @@ restart_ih:  						rdev->pm.vblank_sync = true;  						wake_up(&rdev->irq.vblank_queue);  					} -					if (rdev->irq.pflip[3]) +					if (atomic_read(&rdev->irq.pflip[3]))  						radeon_crtc_handle_flip(rdev, 3);  					rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D4 vblank\n"); @@ -2820,7 +2962,7 @@ restart_ih:  						rdev->pm.vblank_sync = true;  						wake_up(&rdev->irq.vblank_queue);  					} -					if (rdev->irq.pflip[4]) +					if (atomic_read(&rdev->irq.pflip[4]))  						radeon_crtc_handle_flip(rdev, 4);  					rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D5 vblank\n"); @@ -2846,7 +2988,7 @@ restart_ih:  						rdev->pm.vblank_sync = true;  						wake_up(&rdev->irq.vblank_queue);  					} -					if (rdev->irq.pflip[5]) +					if (atomic_read(&rdev->irq.pflip[5]))  						radeon_crtc_handle_flip(rdev, 5);  					rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D6 vblank\n"); @@ -2986,7 +3128,6 @@ restart_ih:  			break;  		case 233: /* GUI IDLE */  			DRM_DEBUG("IH: GUI idle\n"); -			rdev->pm.gui_idle = true;  			wake_up(&rdev->irq.idle_queue);  			break;  		default: @@ -2998,17 +3139,19 @@ restart_ih:  		rptr += 16;  		rptr &= rdev->ih.ptr_mask;  	} -	/* make sure wptr hasn't changed while processing */ -	wptr = evergreen_get_ih_wptr(rdev); -	if (wptr != rdev->ih.wptr) -		goto restart_ih;  	if (queue_hotplug)  		schedule_work(&rdev->hotplug_work);  	if (queue_hdmi)  		schedule_work(&rdev->audio_work);  	rdev->ih.rptr = rptr;  	WREG32(IH_RB_RPTR, rdev->ih.rptr); -	spin_unlock_irqrestore(&rdev->ih.lock, flags); +	atomic_set(&rdev->ih.lock, 0); + +	/* make sure wptr hasn't changed while processing */ +	wptr = evergreen_get_ih_wptr(rdev); +	if (wptr != rptr) +		goto restart_ih; +  	return IRQ_HANDLED;  } @@ -3096,13 +3239,11 @@ static int evergreen_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_pool_start(rdev); -	if (r) -		return r; - -	r = radeon_ib_ring_tests(rdev); -	if (r) +	r = radeon_ib_pool_init(rdev); +	if (r) { +		dev_err(rdev->dev, "IB initialization failed (%d).\n", r);  		return r; +	}  	r = r600_audio_init(rdev);  	if (r) { @@ -3146,9 +3287,6 @@ int evergreen_suspend(struct radeon_device *rdev)  	struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];  	r600_audio_fini(rdev); -	/* FIXME: we should wait for ring to be empty */ -	radeon_ib_pool_suspend(rdev); -	r600_blit_suspend(rdev);  	r700_cp_stop(rdev);  	ring->ready = false;  	evergreen_irq_suspend(rdev); @@ -3234,20 +3372,14 @@ int evergreen_init(struct radeon_device *rdev)  	if (r)  		return r; -	r = radeon_ib_pool_init(rdev);  	rdev->accel_working = true; -	if (r) { -		dev_err(rdev->dev, "IB initialization failed (%d).\n", r); -		rdev->accel_working = false; -	} -  	r = evergreen_startup(rdev);  	if (r) {  		dev_err(rdev->dev, "disabling GPU acceleration\n");  		r700_cp_fini(rdev);  		r600_irq_fini(rdev);  		radeon_wb_fini(rdev); -		r100_ib_fini(rdev); +		radeon_ib_pool_fini(rdev);  		radeon_irq_kms_fini(rdev);  		evergreen_pcie_gart_fini(rdev);  		rdev->accel_working = false; @@ -3274,7 +3406,7 @@ void evergreen_fini(struct radeon_device *rdev)  	r700_cp_fini(rdev);  	r600_irq_fini(rdev);  	radeon_wb_fini(rdev); -	r100_ib_fini(rdev); +	radeon_ib_pool_fini(rdev);  	radeon_irq_kms_fini(rdev);  	evergreen_pcie_gart_fini(rdev);  	r600_vram_scratch_fini(rdev); @@ -3289,7 +3421,8 @@ void evergreen_fini(struct radeon_device *rdev)  void evergreen_pcie_gen2_enable(struct radeon_device *rdev)  { -	u32 link_width_cntl, speed_cntl; +	u32 link_width_cntl, speed_cntl, mask; +	int ret;  	if (radeon_pcie_gen2 == 0)  		return; @@ -3304,6 +3437,15 @@ void evergreen_pcie_gen2_enable(struct radeon_device *rdev)  	if (ASIC_IS_X2(rdev))  		return; +	ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); +	if (ret != 0) +		return; + +	if (!(mask & DRM_PCIE_SPEED_50)) +		return; + +	DRM_INFO("enabling PCIE gen 2 link speeds, disable with radeon.pcie_gen2=0\n"); +  	speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);  	if ((speed_cntl & LC_OTHER_SIDE_EVER_SENT_GEN2) ||  	    (speed_cntl & LC_OTHER_SIDE_SUPPORTS_GEN2)) {  |