Skip to content

Commit

Permalink
drm/radeon/kms: use wait queue (events) for VBLANK sync
Browse files Browse the repository at this point in the history
This already simplifies code significally and makes it maintaible
in case of adding memory reclocking plus voltage changing in future.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Rafał Miłecki authored and Dave Airlie committed Feb 8, 2010
1 parent 20d6c34 commit 73a6d3f
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 74 deletions.
6 changes: 2 additions & 4 deletions drivers/gpu/drm/radeon/r100.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,13 +312,11 @@ int r100_irq_process(struct radeon_device *rdev)
/* Vertical blank interrupts */
if (status & RADEON_CRTC_VBLANK_STAT) {
drm_handle_vblank(rdev->ddev, 0);
if (rdev->pm.vblank_callback)
queue_work(rdev->wq, &rdev->pm.reclock_work);
wake_up(&rdev->irq.vblank_queue);
}
if (status & RADEON_CRTC2_VBLANK_STAT) {
drm_handle_vblank(rdev->ddev, 1);
if (rdev->pm.vblank_callback)
queue_work(rdev->wq, &rdev->pm.reclock_work);
wake_up(&rdev->irq.vblank_queue);
}
if (status & RADEON_FP_DETECT_STAT) {
queue_hotplug = true;
Expand Down
6 changes: 2 additions & 4 deletions drivers/gpu/drm/radeon/r600.c
Original file line number Diff line number Diff line change
Expand Up @@ -2744,8 +2744,7 @@ int r600_irq_process(struct radeon_device *rdev)
case 0: /* D1 vblank */
if (disp_int & LB_D1_VBLANK_INTERRUPT) {
drm_handle_vblank(rdev->ddev, 0);
if (rdev->pm.vblank_callback)
queue_work(rdev->wq, &rdev->pm.reclock_work);
wake_up(&rdev->irq.vblank_queue);
disp_int &= ~LB_D1_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D1 vblank\n");
}
Expand All @@ -2766,8 +2765,7 @@ int r600_irq_process(struct radeon_device *rdev)
case 0: /* D2 vblank */
if (disp_int & LB_D2_VBLANK_INTERRUPT) {
drm_handle_vblank(rdev->ddev, 1);
if (rdev->pm.vblank_callback)
queue_work(rdev->wq, &rdev->pm.reclock_work);
wake_up(&rdev->irq.vblank_queue);
disp_int &= ~LB_D2_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D2 vblank\n");
}
Expand Down
3 changes: 1 addition & 2 deletions drivers/gpu/drm/radeon/radeon.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ struct radeon_irq {
bool sw_int;
/* FIXME: use a define max crtc rather than hardcode it */
bool crtc_vblank_int[2];
wait_queue_head_t vblank_queue;
/* FIXME: use defines for max hpd/dacs */
bool hpd[6];
spinlock_t sw_lock;
Expand Down Expand Up @@ -657,13 +658,11 @@ struct radeon_power_state {

struct radeon_pm {
struct mutex mutex;
struct work_struct reclock_work;
struct delayed_work idle_work;
enum radeon_pm_state state;
enum radeon_pm_action planned_action;
unsigned long action_timeout;
bool downclocked;
bool vblank_callback;
int active_crtcs;
int req_vblank;
fixed20_12 max_bandwidth;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/radeon/radeon_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,7 @@ int radeon_device_init(struct radeon_device *rdev,
mutex_init(&rdev->pm.mutex);
rwlock_init(&rdev->fence_drv.lock);
INIT_LIST_HEAD(&rdev->gem.objects);
init_waitqueue_head(&rdev->irq.vblank_queue);

/* setup workqueue */
rdev->wq = create_workqueue("radeon");
Expand Down
93 changes: 33 additions & 60 deletions drivers/gpu/drm/radeon/radeon_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@

#define RADEON_IDLE_LOOP_MS 100
#define RADEON_RECLOCK_DELAY_MS 200
#define RADEON_WAIT_VBLANK_TIMEOUT 200

static void radeon_pm_set_clocks_locked(struct radeon_device *rdev);
static void radeon_pm_set_clocks(struct radeon_device *rdev);
static void radeon_pm_reclock_work_handler(struct work_struct *work);
static void radeon_pm_idle_work_handler(struct work_struct *work);
static int radeon_debugfs_pm_init(struct radeon_device *rdev);

Expand Down Expand Up @@ -214,7 +214,6 @@ int radeon_pm_init(struct radeon_device *rdev)
rdev->pm.state = PM_STATE_DISABLED;
rdev->pm.planned_action = PM_ACTION_NONE;
rdev->pm.downclocked = false;
rdev->pm.vblank_callback = false;

if (rdev->bios) {
if (rdev->is_atom_bios)
Expand All @@ -228,7 +227,6 @@ int radeon_pm_init(struct radeon_device *rdev)
DRM_ERROR("Failed to register debugfs file for PM!\n");
}

INIT_WORK(&rdev->pm.reclock_work, radeon_pm_reclock_work_handler);
INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler);

if (radeon_dynpm != -1 && radeon_dynpm) {
Expand Down Expand Up @@ -266,35 +264,22 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)

if (count > 1) {
if (rdev->pm.state == PM_STATE_ACTIVE) {
wait_queue_head_t wait;
init_waitqueue_head(&wait);

cancel_delayed_work(&rdev->pm.idle_work);

rdev->pm.state = PM_STATE_PAUSED;
rdev->pm.planned_action = PM_ACTION_UPCLOCK;
radeon_get_power_state(rdev, rdev->pm.planned_action);
rdev->pm.vblank_callback = true;

mutex_unlock(&rdev->pm.mutex);

wait_event_timeout(wait, !rdev->pm.downclocked,
msecs_to_jiffies(300));
if (!rdev->pm.downclocked)
if (rdev->pm.downclocked)
radeon_pm_set_clocks(rdev);

DRM_DEBUG("radeon: dynamic power management deactivated\n");
} else {
mutex_unlock(&rdev->pm.mutex);
}
} else if (count == 1) {
/* TODO: Increase clocks if needed for current mode */

if (rdev->pm.state == PM_STATE_MINIMUM) {
rdev->pm.state = PM_STATE_ACTIVE;
rdev->pm.planned_action = PM_ACTION_UPCLOCK;
radeon_get_power_state(rdev, rdev->pm.planned_action);
radeon_pm_set_clocks_locked(rdev);
radeon_pm_set_clocks(rdev);

queue_delayed_work(rdev->wq, &rdev->pm.idle_work,
msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
Expand All @@ -305,21 +290,18 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
DRM_DEBUG("radeon: dynamic power management activated\n");
}

mutex_unlock(&rdev->pm.mutex);
}
else { /* count == 0 */
if (rdev->pm.state != PM_STATE_MINIMUM) {
cancel_delayed_work(&rdev->pm.idle_work);

rdev->pm.state = PM_STATE_MINIMUM;
rdev->pm.planned_action = PM_ACTION_MINIMUM;
radeon_get_power_state(rdev, rdev->pm.planned_action);
radeon_pm_set_clocks_locked(rdev);
radeon_pm_set_clocks(rdev);
}

mutex_unlock(&rdev->pm.mutex);
}

mutex_unlock(&rdev->pm.mutex);
}

static void radeon_pm_set_clocks_locked(struct radeon_device *rdev)
Expand All @@ -344,31 +326,32 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev)

static void radeon_pm_set_clocks(struct radeon_device *rdev)
{
mutex_lock(&rdev->pm.mutex);
/* new VBLANK irq may come before handling previous one */
if (rdev->pm.vblank_callback) {
mutex_lock(&rdev->cp.mutex);
if (rdev->pm.req_vblank & (1 << 0)) {
rdev->pm.req_vblank &= ~(1 << 0);
drm_vblank_put(rdev->ddev, 0);
}
if (rdev->pm.req_vblank & (1 << 1)) {
rdev->pm.req_vblank &= ~(1 << 1);
drm_vblank_put(rdev->ddev, 1);
}
rdev->pm.vblank_callback = false;
radeon_pm_set_clocks_locked(rdev);
mutex_unlock(&rdev->cp.mutex);
radeon_get_power_state(rdev, rdev->pm.planned_action);
mutex_lock(&rdev->cp.mutex);

if (rdev->pm.active_crtcs & (1 << 0)) {
rdev->pm.req_vblank |= (1 << 0);
drm_vblank_get(rdev->ddev, 0);
}
if (rdev->pm.active_crtcs & (1 << 1)) {
rdev->pm.req_vblank |= (1 << 1);
drm_vblank_get(rdev->ddev, 1);
}
if (rdev->pm.active_crtcs)
wait_event_interruptible_timeout(
rdev->irq.vblank_queue, 0,
msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT));
if (rdev->pm.req_vblank & (1 << 0)) {
rdev->pm.req_vblank &= ~(1 << 0);
drm_vblank_put(rdev->ddev, 0);
}
if (rdev->pm.req_vblank & (1 << 1)) {
rdev->pm.req_vblank &= ~(1 << 1);
drm_vblank_put(rdev->ddev, 1);
}
mutex_unlock(&rdev->pm.mutex);
}

static void radeon_pm_reclock_work_handler(struct work_struct *work)
{
struct radeon_device *rdev;
rdev = container_of(work, struct radeon_device,
pm.reclock_work);
radeon_pm_set_clocks(rdev);
radeon_pm_set_clocks_locked(rdev);
mutex_unlock(&rdev->cp.mutex);
}

static void radeon_pm_idle_work_handler(struct work_struct *work)
Expand All @@ -378,8 +361,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work)
pm.idle_work.work);

mutex_lock(&rdev->pm.mutex);
if (rdev->pm.state == PM_STATE_ACTIVE &&
!rdev->pm.vblank_callback) {
if (rdev->pm.state == PM_STATE_ACTIVE) {
unsigned long irq_flags;
int not_processed = 0;

Expand Down Expand Up @@ -417,17 +399,8 @@ static void radeon_pm_idle_work_handler(struct work_struct *work)
}

if (rdev->pm.planned_action != PM_ACTION_NONE &&
jiffies > rdev->pm.action_timeout) {
if (rdev->pm.active_crtcs & (1 << 0)) {
rdev->pm.req_vblank |= (1 << 0);
drm_vblank_get(rdev->ddev, 0);
}
if (rdev->pm.active_crtcs & (1 << 1)) {
rdev->pm.req_vblank |= (1 << 1);
drm_vblank_get(rdev->ddev, 1);
}
radeon_get_power_state(rdev, rdev->pm.planned_action);
rdev->pm.vblank_callback = true;
jiffies > rdev->pm.action_timeout) {
radeon_pm_set_clocks(rdev);
}
}
mutex_unlock(&rdev->pm.mutex);
Expand Down
6 changes: 2 additions & 4 deletions drivers/gpu/drm/radeon/rs600.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,13 +408,11 @@ int rs600_irq_process(struct radeon_device *rdev)
/* Vertical blank interrupts */
if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) {
drm_handle_vblank(rdev->ddev, 0);
if (rdev->pm.vblank_callback)
queue_work(rdev->wq, &rdev->pm.reclock_work);
wake_up(&rdev->irq.vblank_queue);
}
if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) {
drm_handle_vblank(rdev->ddev, 1);
if (rdev->pm.vblank_callback)
queue_work(rdev->wq, &rdev->pm.reclock_work);
wake_up(&rdev->irq.vblank_queue);
}
if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) {
queue_hotplug = true;
Expand Down

0 comments on commit 73a6d3f

Please sign in to comment.