summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/radeon/radeon_irq_kms.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_irq_kms.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c98
1 files changed, 69 insertions, 29 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 7aacb44df201..9961251b44ba 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -25,27 +25,32 @@
* Alex Deucher
* Jerome Glisse
*/
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
+
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
#include <drm/radeon_drm.h>
-#include "radeon_reg.h"
-#include "radeon.h"
+
#include "atom.h"
+#include "radeon.h"
+#include "radeon_kms.h"
+#include "radeon_reg.h"
-#include <linux/pm_runtime.h>
#define RADEON_WAIT_IDLE_TIMEOUT 200
-/**
+/*
* radeon_driver_irq_handler_kms - irq handler for KMS
*
- * @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(int irq, void *arg)
+static 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;
@@ -75,7 +80,7 @@ static void radeon_hotplug_work_func(struct work_struct *work)
{
struct radeon_device *rdev = container_of(work, struct radeon_device,
hotplug_work.work);
- struct drm_device *dev = rdev->ddev;
+ struct drm_device *dev = rdev_to_drm(rdev);
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
@@ -96,14 +101,16 @@ static void radeon_dp_work_func(struct work_struct *work)
{
struct radeon_device *rdev = container_of(work, struct radeon_device,
dp_work);
- struct drm_device *dev = rdev->ddev;
+ struct drm_device *dev = rdev_to_drm(rdev);
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
- /* this should take a mutex */
+ mutex_lock(&mode_config->mutex);
list_for_each_entry(connector, &mode_config->connector_list, head)
radeon_connector_hotplug(connector);
+ mutex_unlock(&mode_config->mutex);
}
+
/**
* radeon_driver_irq_preinstall_kms - drm irq preinstall callback
*
@@ -112,7 +119,7 @@ static void radeon_dp_work_func(struct work_struct *work)
* Gets the hw ready to enable irqs (all asics).
* This function disables all interrupt sources on the GPU.
*/
-void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
+static void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
unsigned long irqflags;
@@ -144,7 +151,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
* Handles stuff to be done after enabling irqs (all asics).
* Returns 0 on success.
*/
-int radeon_driver_irq_postinstall_kms(struct drm_device *dev)
+static int radeon_driver_irq_postinstall_kms(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
@@ -163,7 +170,7 @@ int radeon_driver_irq_postinstall_kms(struct drm_device *dev)
*
* This function disables all interrupt sources on the GPU (all asics).
*/
-void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
+static void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
unsigned long irqflags;
@@ -188,6 +195,36 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
}
+static int radeon_irq_install(struct radeon_device *rdev, int irq)
+{
+ struct drm_device *dev = rdev_to_drm(rdev);
+ int ret;
+
+ if (irq == IRQ_NOTCONNECTED)
+ return -ENOTCONN;
+
+ radeon_driver_irq_preinstall_kms(dev);
+
+ /* PCI devices require shared interrupts. */
+ ret = request_irq(irq, radeon_driver_irq_handler_kms,
+ IRQF_SHARED, dev->driver->name, dev);
+ if (ret)
+ return ret;
+
+ radeon_driver_irq_postinstall_kms(dev);
+
+ return 0;
+}
+
+static void radeon_irq_uninstall(struct radeon_device *rdev)
+{
+ struct drm_device *dev = rdev_to_drm(rdev);
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+ radeon_driver_irq_uninstall_kms(dev);
+ free_irq(pdev->irq, dev);
+}
+
/**
* radeon_msi_ok - asic specific msi checks
*
@@ -283,7 +320,11 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
int r = 0;
spin_lock_init(&rdev->irq.lock);
- r = drm_vblank_init(rdev->ddev, rdev->num_crtc);
+
+ /* Disable vblank irqs aggressively for power-saving */
+ rdev_to_drm(rdev)->vblank_disable_immediate = true;
+
+ r = drm_vblank_init(rdev_to_drm(rdev), rdev->num_crtc);
if (r) {
return r;
}
@@ -304,7 +345,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
rdev->irq.installed = true;
- r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq);
+ r = radeon_irq_install(rdev, rdev->pdev->irq);
if (r) {
rdev->irq.installed = false;
flush_delayed_work(&rdev->hotplug_work);
@@ -324,9 +365,8 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
*/
void radeon_irq_kms_fini(struct radeon_device *rdev)
{
- drm_vblank_cleanup(rdev->ddev);
if (rdev->irq.installed) {
- drm_irq_uninstall(rdev->ddev);
+ radeon_irq_uninstall(rdev);
rdev->irq.installed = false;
if (rdev->msi_enabled)
pci_disable_msi(rdev->pdev);
@@ -348,7 +388,7 @@ void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring)
{
unsigned long irqflags;
- if (!rdev->ddev->irq_enabled)
+ if (!rdev->irq.installed)
return;
if (atomic_inc_return(&rdev->irq.ring_int[ring]) == 1) {
@@ -387,7 +427,7 @@ void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev, int ring)
{
unsigned long irqflags;
- if (!rdev->ddev->irq_enabled)
+ if (!rdev->irq.installed)
return;
if (atomic_dec_and_test(&rdev->irq.ring_int[ring])) {
@@ -413,7 +453,7 @@ void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc)
if (crtc < 0 || crtc >= rdev->num_crtc)
return;
- if (!rdev->ddev->irq_enabled)
+ if (!rdev->irq.installed)
return;
if (atomic_inc_return(&rdev->irq.pflip[crtc]) == 1) {
@@ -439,7 +479,7 @@ void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc)
if (crtc < 0 || crtc >= rdev->num_crtc)
return;
- if (!rdev->ddev->irq_enabled)
+ if (!rdev->irq.installed)
return;
if (atomic_dec_and_test(&rdev->irq.pflip[crtc])) {
@@ -461,7 +501,7 @@ void radeon_irq_kms_enable_afmt(struct radeon_device *rdev, int block)
{
unsigned long irqflags;
- if (!rdev->ddev->irq_enabled)
+ if (!rdev->irq.installed)
return;
spin_lock_irqsave(&rdev->irq.lock, irqflags);
@@ -483,7 +523,7 @@ void radeon_irq_kms_disable_afmt(struct radeon_device *rdev, int block)
{
unsigned long irqflags;
- if (!rdev->ddev->irq_enabled)
+ if (!rdev->irq.installed)
return;
spin_lock_irqsave(&rdev->irq.lock, irqflags);
@@ -505,7 +545,7 @@ void radeon_irq_kms_enable_hpd(struct radeon_device *rdev, unsigned hpd_mask)
unsigned long irqflags;
int i;
- if (!rdev->ddev->irq_enabled)
+ if (!rdev->irq.installed)
return;
spin_lock_irqsave(&rdev->irq.lock, irqflags);
@@ -528,7 +568,7 @@ void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, unsigned hpd_mask)
unsigned long irqflags;
int i;
- if (!rdev->ddev->irq_enabled)
+ if (!rdev->irq.installed)
return;
spin_lock_irqsave(&rdev->irq.lock, irqflags);
@@ -539,14 +579,14 @@ void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, unsigned hpd_mask)
}
/**
- * radeon_irq_kms_update_int_n - helper for updating interrupt enable registers
+ * radeon_irq_kms_set_irq_n_enabled - helper for updating interrupt enable registers
*
* @rdev: radeon device pointer
* @reg: the register to write to enable/disable interrupts
* @mask: the mask that enables the interrupts
* @enable: whether to enable or disable the interrupt register
* @name: the name of the interrupt register to print to the kernel log
- * @num: the number of the interrupt register to print to the kernel log
+ * @n: the number of the interrupt register to print to the kernel log
*
* Helper for updating the enable state of interrupt registers. Checks whether
* or not the interrupt matches the enable state we want. If it doesn't, then