diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_irq_kms.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_irq_kms.c | 108 |
1 files changed, 63 insertions, 45 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index afaa1727abd..16807afab36 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -25,30 +25,36 @@ * Alex Deucher * Jerome Glisse */ -#include "drmP.h" -#include "drm_crtc_helper.h" -#include "radeon_drm.h" +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/radeon_drm.h> #include "radeon_reg.h" #include "radeon.h" #include "atom.h" +#include <linux/pm_runtime.h> + #define RADEON_WAIT_IDLE_TIMEOUT 200 /** * radeon_driver_irq_handler_kms - irq handler for KMS * - * @DRM_IRQ_ARGS: args + * @int irq, void *arg: args * * This is the irq handler for the radeon KMS driver (all asics). * radeon_irq_process is a macro that points to the per-asic * irq handler callback. */ -irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS) +irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; struct radeon_device *rdev = dev->dev_private; + irqreturn_t ret; - return radeon_irq_process(rdev); + ret = radeon_irq_process(rdev); + if (ret == IRQ_HANDLED) + pm_runtime_mark_last_busy(dev->dev); + return ret; } /* @@ -82,6 +88,23 @@ static void radeon_hotplug_work_func(struct work_struct *work) } /** + * radeon_irq_reset_work_func - execute gpu reset + * + * @work: work struct + * + * Execute scheduled gpu reset (cayman+). + * This function is called when the irq handler + * thinks we need a gpu reset. + */ +static void radeon_irq_reset_work_func(struct work_struct *work) +{ + struct radeon_device *rdev = container_of(work, struct radeon_device, + reset_work); + + radeon_gpu_reset(rdev); +} + +/** * radeon_driver_irq_preinstall_kms - drm irq preinstall callback * * @dev: drm dev pointer @@ -99,7 +122,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ for (i = 0; i < RADEON_NUM_RINGS; i++) atomic_set(&rdev->irq.ring_int[i], 0); - rdev->irq.gui_idle = false; + rdev->irq.dpm_thermal = false; for (i = 0; i < RADEON_MAX_HPD_PINS; i++) rdev->irq.hpd[i] = false; for (i = 0; i < RADEON_MAX_CRTCS; i++) { @@ -147,7 +170,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ for (i = 0; i < RADEON_NUM_RINGS; i++) atomic_set(&rdev->irq.ring_int[i], 0); - rdev->irq.gui_idle = false; + rdev->irq.dpm_thermal = false; for (i = 0; i < RADEON_MAX_HPD_PINS; i++) rdev->irq.hpd[i] = false; for (i = 0; i < RADEON_MAX_CRTCS; i++) { @@ -204,6 +227,16 @@ static bool radeon_msi_ok(struct radeon_device *rdev) (rdev->pdev->subsystem_device == 0x01fd)) return true; + /* Gateway RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x107b) && + (rdev->pdev->subsystem_device == 0x0185)) + return true; + + /* try and enable MSIs by default on all RS690s */ + if (rdev->family == CHIP_RS690) + return true; + /* RV515 seems to have MSI issues where it loses * MSI rearms occasionally. This leads to lockups and freezes. * disable it by default. @@ -233,9 +266,6 @@ int radeon_irq_kms_init(struct radeon_device *rdev) { int r = 0; - INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); - INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi); - spin_lock_init(&rdev->irq.lock); r = drm_vblank_init(rdev->ddev, rdev->num_crtc); if (r) { @@ -251,18 +281,25 @@ int radeon_irq_kms_init(struct radeon_device *rdev) dev_info(rdev->dev, "radeon: using MSI.\n"); } } + + INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); + INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi); + INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func); + rdev->irq.installed = true; - r = drm_irq_install(rdev->ddev); + r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq); if (r) { rdev->irq.installed = false; + flush_work(&rdev->hotplug_work); return r; } + DRM_INFO("radeon: irq initialized.\n"); return 0; } /** - * radeon_irq_kms_fini - tear down driver interrrupt info + * radeon_irq_kms_fini - tear down driver interrupt info * * @rdev: radeon device pointer * @@ -276,8 +313,8 @@ void radeon_irq_kms_fini(struct radeon_device *rdev) rdev->irq.installed = false; if (rdev->msi_enabled) pci_disable_msi(rdev->pdev); + flush_work(&rdev->hotplug_work); } - flush_work_sync(&rdev->hotplug_work); } /** @@ -392,6 +429,9 @@ void radeon_irq_kms_enable_afmt(struct radeon_device *rdev, int block) { unsigned long irqflags; + if (!rdev->ddev->irq_enabled) + return; + spin_lock_irqsave(&rdev->irq.lock, irqflags); rdev->irq.afmt[block] = true; radeon_irq_set(rdev); @@ -411,6 +451,9 @@ void radeon_irq_kms_disable_afmt(struct radeon_device *rdev, int block) { unsigned long irqflags; + if (!rdev->ddev->irq_enabled) + return; + spin_lock_irqsave(&rdev->irq.lock, irqflags); rdev->irq.afmt[block] = false; radeon_irq_set(rdev); @@ -430,6 +473,9 @@ void radeon_irq_kms_enable_hpd(struct radeon_device *rdev, unsigned hpd_mask) unsigned long irqflags; int i; + if (!rdev->ddev->irq_enabled) + return; + spin_lock_irqsave(&rdev->irq.lock, irqflags); for (i = 0; i < RADEON_MAX_HPD_PINS; ++i) rdev->irq.hpd[i] |= !!(hpd_mask & (1 << i)); @@ -450,6 +496,9 @@ void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, unsigned hpd_mask) unsigned long irqflags; int i; + if (!rdev->ddev->irq_enabled) + return; + spin_lock_irqsave(&rdev->irq.lock, irqflags); for (i = 0; i < RADEON_MAX_HPD_PINS; ++i) rdev->irq.hpd[i] &= !(hpd_mask & (1 << i)); @@ -457,34 +506,3 @@ void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, unsigned hpd_mask) spin_unlock_irqrestore(&rdev->irq.lock, irqflags); } -/** - * radeon_irq_kms_wait_gui_idle - waits for drawing engine to be idle - * - * @rdev: radeon device pointer - * - * Enabled the GUI idle interrupt and waits for it to fire (r6xx+). - * This is currently used to make sure the 3D engine is idle for power - * management, but should be replaces with proper fence waits. - * GUI idle interrupts don't work very well on pre-r6xx hw and it also - * does not take into account other aspects of the chip that may be busy. - * DO NOT USE GOING FORWARD. - */ -int radeon_irq_kms_wait_gui_idle(struct radeon_device *rdev) -{ - unsigned long irqflags; - int r; - - spin_lock_irqsave(&rdev->irq.lock, irqflags); - rdev->irq.gui_idle = true; - radeon_irq_set(rdev); - spin_unlock_irqrestore(&rdev->irq.lock, irqflags); - - r = wait_event_timeout(rdev->irq.idle_queue, radeon_gui_idle(rdev), - msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); - - spin_lock_irqsave(&rdev->irq.lock, irqflags); - rdev->irq.gui_idle = false; - radeon_irq_set(rdev); - spin_unlock_irqrestore(&rdev->irq.lock, irqflags); - return r; -} |
