mirror of https://gitee.com/openkylin/linux.git
Merge branch 'drm-fixes-4.5' of git://people.freedesktop.org/~agd5f/linux into drm-fixes
A few radeon and amdgpu fixes for 4.5. A few further fixes for the vblank regressions in 4.4 and a couple of other minor fixes. * 'drm-fixes-4.5' of git://people.freedesktop.org/~agd5f/linux: drm/amdgpu: disable direct VM updates when vm_debug is set amdgpu: fix NULL pointer dereference at tonga_check_states_equal drm/radeon/pm: adjust display configuration after powerstate drm/amdgpu/pm: adjust display configuration after powerstate drm/amdgpu/pm: add some checks for PX drm/amdgpu: fix locking in force performance level drm/amdgpu/gfx8: fix priv reg interrupt enable drm/amdgpu: Don't hang in amdgpu_flip_work_func on disabled crtc. drm/radeon: Don't hang in radeon_flip_work_func on disabled crtc. (v2)
This commit is contained in:
commit
ad00a57ad7
|
@ -72,8 +72,8 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
|
||||||
|
|
||||||
struct drm_crtc *crtc = &amdgpuCrtc->base;
|
struct drm_crtc *crtc = &amdgpuCrtc->base;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned i;
|
unsigned i, repcnt = 4;
|
||||||
int vpos, hpos, stat, min_udelay;
|
int vpos, hpos, stat, min_udelay = 0;
|
||||||
struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
|
struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
|
||||||
|
|
||||||
amdgpu_flip_wait_fence(adev, &work->excl);
|
amdgpu_flip_wait_fence(adev, &work->excl);
|
||||||
|
@ -96,7 +96,7 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
|
||||||
* In practice this won't execute very often unless on very fast
|
* In practice this won't execute very often unless on very fast
|
||||||
* machines because the time window for this to happen is very small.
|
* machines because the time window for this to happen is very small.
|
||||||
*/
|
*/
|
||||||
for (;;) {
|
while (amdgpuCrtc->enabled && repcnt--) {
|
||||||
/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
|
/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
|
||||||
* start in hpos, and to the "fudged earlier" vblank start in
|
* start in hpos, and to the "fudged earlier" vblank start in
|
||||||
* vpos.
|
* vpos.
|
||||||
|
@ -114,10 +114,22 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
|
||||||
/* Sleep at least until estimated real start of hw vblank */
|
/* Sleep at least until estimated real start of hw vblank */
|
||||||
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
||||||
min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
|
min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
|
||||||
|
if (min_udelay > vblank->framedur_ns / 2000) {
|
||||||
|
/* Don't wait ridiculously long - something is wrong */
|
||||||
|
repcnt = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
usleep_range(min_udelay, 2 * min_udelay);
|
usleep_range(min_udelay, 2 * min_udelay);
|
||||||
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!repcnt)
|
||||||
|
DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
|
||||||
|
"framedur %d, linedur %d, stat %d, vpos %d, "
|
||||||
|
"hpos %d\n", work->crtc_id, min_udelay,
|
||||||
|
vblank->framedur_ns / 1000,
|
||||||
|
vblank->linedur_ns / 1000, stat, vpos, hpos);
|
||||||
|
|
||||||
/* do the flip (mmio) */
|
/* do the flip (mmio) */
|
||||||
adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);
|
adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);
|
||||||
/* set the flip status */
|
/* set the flip status */
|
||||||
|
|
|
@ -596,7 +596,8 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ttm_eu_backoff_reservation(&ticket, &list);
|
ttm_eu_backoff_reservation(&ticket, &list);
|
||||||
if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE))
|
if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) &&
|
||||||
|
!amdgpu_vm_debug)
|
||||||
amdgpu_gem_va_update_vm(adev, bo_va, args->operation);
|
amdgpu_gem_va_update_vm(adev, bo_va, args->operation);
|
||||||
|
|
||||||
drm_gem_object_unreference_unlocked(gobj);
|
drm_gem_object_unreference_unlocked(gobj);
|
||||||
|
|
|
@ -113,6 +113,10 @@ static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev,
|
||||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||||
struct amdgpu_device *adev = ddev->dev_private;
|
struct amdgpu_device *adev = ddev->dev_private;
|
||||||
|
|
||||||
|
if ((adev->flags & AMD_IS_PX) &&
|
||||||
|
(ddev->switch_power_state != DRM_SWITCH_POWER_ON))
|
||||||
|
return snprintf(buf, PAGE_SIZE, "off\n");
|
||||||
|
|
||||||
if (adev->pp_enabled) {
|
if (adev->pp_enabled) {
|
||||||
enum amd_dpm_forced_level level;
|
enum amd_dpm_forced_level level;
|
||||||
|
|
||||||
|
@ -140,6 +144,11 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
|
||||||
enum amdgpu_dpm_forced_level level;
|
enum amdgpu_dpm_forced_level level;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Can't force performance level when the card is off */
|
||||||
|
if ((adev->flags & AMD_IS_PX) &&
|
||||||
|
(ddev->switch_power_state != DRM_SWITCH_POWER_ON))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (strncmp("low", buf, strlen("low")) == 0) {
|
if (strncmp("low", buf, strlen("low")) == 0) {
|
||||||
level = AMDGPU_DPM_FORCED_LEVEL_LOW;
|
level = AMDGPU_DPM_FORCED_LEVEL_LOW;
|
||||||
} else if (strncmp("high", buf, strlen("high")) == 0) {
|
} else if (strncmp("high", buf, strlen("high")) == 0) {
|
||||||
|
@ -157,6 +166,7 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
|
||||||
mutex_lock(&adev->pm.mutex);
|
mutex_lock(&adev->pm.mutex);
|
||||||
if (adev->pm.dpm.thermal_active) {
|
if (adev->pm.dpm.thermal_active) {
|
||||||
count = -EINVAL;
|
count = -EINVAL;
|
||||||
|
mutex_unlock(&adev->pm.mutex);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
ret = amdgpu_dpm_force_performance_level(adev, level);
|
ret = amdgpu_dpm_force_performance_level(adev, level);
|
||||||
|
@ -167,8 +177,6 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
|
||||||
mutex_unlock(&adev->pm.mutex);
|
mutex_unlock(&adev->pm.mutex);
|
||||||
}
|
}
|
||||||
fail:
|
fail:
|
||||||
mutex_unlock(&adev->pm.mutex);
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,8 +190,14 @@ static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct amdgpu_device *adev = dev_get_drvdata(dev);
|
struct amdgpu_device *adev = dev_get_drvdata(dev);
|
||||||
|
struct drm_device *ddev = adev->ddev;
|
||||||
int temp;
|
int temp;
|
||||||
|
|
||||||
|
/* Can't get temperature when the card is off */
|
||||||
|
if ((adev->flags & AMD_IS_PX) &&
|
||||||
|
(ddev->switch_power_state != DRM_SWITCH_POWER_ON))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (!adev->pp_enabled && !adev->pm.funcs->get_temperature)
|
if (!adev->pp_enabled && !adev->pm.funcs->get_temperature)
|
||||||
temp = 0;
|
temp = 0;
|
||||||
else
|
else
|
||||||
|
@ -634,8 +648,6 @@ static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
|
||||||
|
|
||||||
/* update display watermarks based on new power state */
|
/* update display watermarks based on new power state */
|
||||||
amdgpu_display_bandwidth_update(adev);
|
amdgpu_display_bandwidth_update(adev);
|
||||||
/* update displays */
|
|
||||||
amdgpu_dpm_display_configuration_changed(adev);
|
|
||||||
|
|
||||||
adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
|
adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
|
||||||
adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
|
adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
|
||||||
|
@ -655,6 +667,9 @@ static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
|
||||||
|
|
||||||
amdgpu_dpm_post_set_power_state(adev);
|
amdgpu_dpm_post_set_power_state(adev);
|
||||||
|
|
||||||
|
/* update displays */
|
||||||
|
amdgpu_dpm_display_configuration_changed(adev);
|
||||||
|
|
||||||
if (adev->pm.funcs->force_performance_level) {
|
if (adev->pm.funcs->force_performance_level) {
|
||||||
if (adev->pm.dpm.thermal_active) {
|
if (adev->pm.dpm.thermal_active) {
|
||||||
enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level;
|
enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level;
|
||||||
|
@ -847,12 +862,16 @@ static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
|
||||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||||
struct drm_device *dev = node->minor->dev;
|
struct drm_device *dev = node->minor->dev;
|
||||||
struct amdgpu_device *adev = dev->dev_private;
|
struct amdgpu_device *adev = dev->dev_private;
|
||||||
|
struct drm_device *ddev = adev->ddev;
|
||||||
|
|
||||||
if (!adev->pm.dpm_enabled) {
|
if (!adev->pm.dpm_enabled) {
|
||||||
seq_printf(m, "dpm not enabled\n");
|
seq_printf(m, "dpm not enabled\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (adev->pp_enabled) {
|
if ((adev->flags & AMD_IS_PX) &&
|
||||||
|
(ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
|
||||||
|
seq_printf(m, "PX asic powered off\n");
|
||||||
|
} else if (adev->pp_enabled) {
|
||||||
amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
|
amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
|
||||||
} else {
|
} else {
|
||||||
mutex_lock(&adev->pm.mutex);
|
mutex_lock(&adev->pm.mutex);
|
||||||
|
|
|
@ -4995,7 +4995,7 @@ static int gfx_v8_0_set_priv_reg_fault_state(struct amdgpu_device *adev,
|
||||||
case AMDGPU_IRQ_STATE_ENABLE:
|
case AMDGPU_IRQ_STATE_ENABLE:
|
||||||
cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0);
|
cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0);
|
||||||
cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0,
|
cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0,
|
||||||
PRIV_REG_INT_ENABLE, 0);
|
PRIV_REG_INT_ENABLE, 1);
|
||||||
WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl);
|
WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
static int pem_init(struct pp_eventmgr *eventmgr)
|
static int pem_init(struct pp_eventmgr *eventmgr)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
struct pem_event_data event_data;
|
struct pem_event_data event_data = { {0} };
|
||||||
|
|
||||||
/* Initialize PowerPlay feature info */
|
/* Initialize PowerPlay feature info */
|
||||||
pem_init_feature_info(eventmgr);
|
pem_init_feature_info(eventmgr);
|
||||||
|
@ -52,7 +52,7 @@ static int pem_init(struct pp_eventmgr *eventmgr)
|
||||||
|
|
||||||
static void pem_fini(struct pp_eventmgr *eventmgr)
|
static void pem_fini(struct pp_eventmgr *eventmgr)
|
||||||
{
|
{
|
||||||
struct pem_event_data event_data;
|
struct pem_event_data event_data = { {0} };
|
||||||
|
|
||||||
pem_uninit_featureInfo(eventmgr);
|
pem_uninit_featureInfo(eventmgr);
|
||||||
pem_unregister_interrupts(eventmgr);
|
pem_unregister_interrupts(eventmgr);
|
||||||
|
|
|
@ -403,7 +403,8 @@ static void radeon_flip_work_func(struct work_struct *__work)
|
||||||
struct drm_crtc *crtc = &radeon_crtc->base;
|
struct drm_crtc *crtc = &radeon_crtc->base;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int r;
|
int r;
|
||||||
int vpos, hpos, stat, min_udelay;
|
int vpos, hpos, stat, min_udelay = 0;
|
||||||
|
unsigned repcnt = 4;
|
||||||
struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
|
struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
|
||||||
|
|
||||||
down_read(&rdev->exclusive_lock);
|
down_read(&rdev->exclusive_lock);
|
||||||
|
@ -454,7 +455,7 @@ static void radeon_flip_work_func(struct work_struct *__work)
|
||||||
* In practice this won't execute very often unless on very fast
|
* In practice this won't execute very often unless on very fast
|
||||||
* machines because the time window for this to happen is very small.
|
* machines because the time window for this to happen is very small.
|
||||||
*/
|
*/
|
||||||
for (;;) {
|
while (radeon_crtc->enabled && repcnt--) {
|
||||||
/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
|
/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
|
||||||
* start in hpos, and to the "fudged earlier" vblank start in
|
* start in hpos, and to the "fudged earlier" vblank start in
|
||||||
* vpos.
|
* vpos.
|
||||||
|
@ -472,10 +473,22 @@ static void radeon_flip_work_func(struct work_struct *__work)
|
||||||
/* Sleep at least until estimated real start of hw vblank */
|
/* Sleep at least until estimated real start of hw vblank */
|
||||||
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
||||||
min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
|
min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
|
||||||
|
if (min_udelay > vblank->framedur_ns / 2000) {
|
||||||
|
/* Don't wait ridiculously long - something is wrong */
|
||||||
|
repcnt = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
usleep_range(min_udelay, 2 * min_udelay);
|
usleep_range(min_udelay, 2 * min_udelay);
|
||||||
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!repcnt)
|
||||||
|
DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
|
||||||
|
"framedur %d, linedur %d, stat %d, vpos %d, "
|
||||||
|
"hpos %d\n", work->crtc_id, min_udelay,
|
||||||
|
vblank->framedur_ns / 1000,
|
||||||
|
vblank->linedur_ns / 1000, stat, vpos, hpos);
|
||||||
|
|
||||||
/* do the flip (mmio) */
|
/* do the flip (mmio) */
|
||||||
radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base);
|
radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base);
|
||||||
|
|
||||||
|
|
|
@ -1079,8 +1079,6 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
|
||||||
|
|
||||||
/* update display watermarks based on new power state */
|
/* update display watermarks based on new power state */
|
||||||
radeon_bandwidth_update(rdev);
|
radeon_bandwidth_update(rdev);
|
||||||
/* update displays */
|
|
||||||
radeon_dpm_display_configuration_changed(rdev);
|
|
||||||
|
|
||||||
rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
|
rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
|
||||||
rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
|
rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
|
||||||
|
@ -1101,6 +1099,9 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
|
||||||
|
|
||||||
radeon_dpm_post_set_power_state(rdev);
|
radeon_dpm_post_set_power_state(rdev);
|
||||||
|
|
||||||
|
/* update displays */
|
||||||
|
radeon_dpm_display_configuration_changed(rdev);
|
||||||
|
|
||||||
if (rdev->asic->dpm.force_performance_level) {
|
if (rdev->asic->dpm.force_performance_level) {
|
||||||
if (rdev->pm.dpm.thermal_active) {
|
if (rdev->pm.dpm.thermal_active) {
|
||||||
enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
|
enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
|
||||||
|
|
Loading…
Reference in New Issue