Commit 0a3e67a4 authored by Jesse Barnes's avatar Jesse Barnes Committed by Dave Airlie

drm: Rework vblank-wait handling to allow interrupt reduction.

Previously, drivers supporting vblank interrupt waits would run the interrupt
all the time, or all the time that any 3d client was running, preventing the
CPU from sleeping for long when the system was otherwise idle.  Now, interrupts
are disabled any time that no client is waiting on a vblank event. The new
method uses vblank counters on the chipsets when the interrupts are turned
off, rather than counting interrupts, so that we can continue to present
accurate vblank numbers.

Co-author: Michel Dänzer <michel@tungstengraphics.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 2df68b43
...@@ -116,6 +116,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { ...@@ -116,6 +116,8 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
}; };
......
This diff is collapsed.
...@@ -673,7 +673,7 @@ static int i915_getparam(struct drm_device *dev, void *data, ...@@ -673,7 +673,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
switch (param->param) { switch (param->param) {
case I915_PARAM_IRQ_ACTIVE: case I915_PARAM_IRQ_ACTIVE:
value = dev->irq_enabled; value = dev->pdev->irq ? 1 : 0;
break; break;
case I915_PARAM_ALLOW_BATCHBUFFER: case I915_PARAM_ALLOW_BATCHBUFFER:
value = dev_priv->allow_batchbuffer ? 1 : 0; value = dev_priv->allow_batchbuffer ? 1 : 0;
...@@ -808,7 +808,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -808,7 +808,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
* and the registers being closely associated. * and the registers being closely associated.
*/ */
if (!IS_I945G(dev) && !IS_I945GM(dev)) if (!IS_I945G(dev) && !IS_I945GM(dev))
pci_enable_msi(dev->pdev); if (pci_enable_msi(dev->pdev))
DRM_ERROR("failed to enable MSI\n");
intel_opregion_init(dev); intel_opregion_init(dev);
......
...@@ -85,10 +85,8 @@ static struct drm_driver driver = { ...@@ -85,10 +85,8 @@ static struct drm_driver driver = {
/* don't use mtrr's here, the Xserver or user space app should /* don't use mtrr's here, the Xserver or user space app should
* deal with them for intel hardware. * deal with them for intel hardware.
*/ */
.driver_features = .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP |
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
DRIVER_IRQ_VBL2,
.load = i915_driver_load, .load = i915_driver_load,
.unload = i915_driver_unload, .unload = i915_driver_unload,
.lastclose = i915_driver_lastclose, .lastclose = i915_driver_lastclose,
...@@ -96,8 +94,9 @@ static struct drm_driver driver = { ...@@ -96,8 +94,9 @@ static struct drm_driver driver = {
.suspend = i915_suspend, .suspend = i915_suspend,
.resume = i915_resume, .resume = i915_resume,
.device_is_agp = i915_driver_device_is_agp, .device_is_agp = i915_driver_device_is_agp,
.vblank_wait = i915_driver_vblank_wait, .get_vblank_counter = i915_get_vblank_counter,
.vblank_wait2 = i915_driver_vblank_wait2, .enable_vblank = i915_enable_vblank,
.disable_vblank = i915_disable_vblank,
.irq_preinstall = i915_driver_irq_preinstall, .irq_preinstall = i915_driver_irq_preinstall,
.irq_postinstall = i915_driver_irq_postinstall, .irq_postinstall = i915_driver_irq_postinstall,
.irq_uninstall = i915_driver_irq_uninstall, .irq_uninstall = i915_driver_irq_uninstall,
......
...@@ -83,10 +83,15 @@ struct mem_block { ...@@ -83,10 +83,15 @@ struct mem_block {
typedef struct _drm_i915_vbl_swap { typedef struct _drm_i915_vbl_swap {
struct list_head head; struct list_head head;
drm_drawable_t drw_id; drm_drawable_t drw_id;
unsigned int pipe; unsigned int plane;
unsigned int sequence; unsigned int sequence;
} drm_i915_vbl_swap_t; } drm_i915_vbl_swap_t;
struct opregion_header;
struct opregion_acpi;
struct opregion_swsci;
struct opregion_asle;
struct intel_opregion { struct intel_opregion {
struct opregion_header *header; struct opregion_header *header;
struct opregion_acpi *acpi; struct opregion_acpi *acpi;
...@@ -105,7 +110,7 @@ typedef struct drm_i915_private { ...@@ -105,7 +110,7 @@ typedef struct drm_i915_private {
drm_dma_handle_t *status_page_dmah; drm_dma_handle_t *status_page_dmah;
void *hw_status_page; void *hw_status_page;
dma_addr_t dma_status_page; dma_addr_t dma_status_page;
unsigned long counter; uint32_t counter;
unsigned int status_gfx_addr; unsigned int status_gfx_addr;
drm_local_map_t hws_map; drm_local_map_t hws_map;
...@@ -247,16 +252,17 @@ extern int i915_irq_emit(struct drm_device *dev, void *data, ...@@ -247,16 +252,17 @@ extern int i915_irq_emit(struct drm_device *dev, void *data,
extern int i915_irq_wait(struct drm_device *dev, void *data, extern int i915_irq_wait(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence);
extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(struct drm_device * dev); extern void i915_driver_irq_preinstall(struct drm_device * dev);
extern void i915_driver_irq_postinstall(struct drm_device * dev); extern int i915_driver_irq_postinstall(struct drm_device *dev);
extern void i915_driver_irq_uninstall(struct drm_device * dev); extern void i915_driver_irq_uninstall(struct drm_device * dev);
extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern int i915_enable_vblank(struct drm_device *dev, int crtc);
extern void i915_disable_vblank(struct drm_device *dev, int crtc);
extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
extern int i915_vblank_swap(struct drm_device *dev, void *data, extern int i915_vblank_swap(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask); extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask);
...@@ -278,6 +284,10 @@ extern void i915_mem_release(struct drm_device * dev, ...@@ -278,6 +284,10 @@ extern void i915_mem_release(struct drm_device * dev,
extern int i915_save_state(struct drm_device *dev); extern int i915_save_state(struct drm_device *dev);
extern int i915_restore_state(struct drm_device *dev); extern int i915_restore_state(struct drm_device *dev);
/* i915_suspend.c */
extern int i915_save_state(struct drm_device *dev);
extern int i915_restore_state(struct drm_device *dev);
/* i915_opregion.c */ /* i915_opregion.c */
extern int intel_opregion_init(struct drm_device *dev); extern int intel_opregion_init(struct drm_device *dev);
extern void intel_opregion_free(struct drm_device *dev); extern void intel_opregion_free(struct drm_device *dev);
......
This diff is collapsed.
...@@ -45,15 +45,16 @@ static struct pci_device_id pciidlist[] = { ...@@ -45,15 +45,16 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = { static struct drm_driver driver = {
.driver_features = .driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
DRIVER_IRQ_VBL,
.dev_priv_size = sizeof(drm_mga_buf_priv_t), .dev_priv_size = sizeof(drm_mga_buf_priv_t),
.load = mga_driver_load, .load = mga_driver_load,
.unload = mga_driver_unload, .unload = mga_driver_unload,
.lastclose = mga_driver_lastclose, .lastclose = mga_driver_lastclose,
.dma_quiescent = mga_driver_dma_quiescent, .dma_quiescent = mga_driver_dma_quiescent,
.device_is_agp = mga_driver_device_is_agp, .device_is_agp = mga_driver_device_is_agp,
.vblank_wait = mga_driver_vblank_wait, .get_vblank_counter = mga_get_vblank_counter,
.enable_vblank = mga_enable_vblank,
.disable_vblank = mga_disable_vblank,
.irq_preinstall = mga_driver_irq_preinstall, .irq_preinstall = mga_driver_irq_preinstall,
.irq_postinstall = mga_driver_irq_postinstall, .irq_postinstall = mga_driver_irq_postinstall,
.irq_uninstall = mga_driver_irq_uninstall, .irq_uninstall = mga_driver_irq_uninstall,
......
...@@ -120,6 +120,7 @@ typedef struct drm_mga_private { ...@@ -120,6 +120,7 @@ typedef struct drm_mga_private {
u32 clear_cmd; u32 clear_cmd;
u32 maccess; u32 maccess;
atomic_t vbl_received; /**< Number of vblanks received. */
wait_queue_head_t fence_queue; wait_queue_head_t fence_queue;
atomic_t last_fence_retired; atomic_t last_fence_retired;
u32 next_fence_to_post; u32 next_fence_to_post;
...@@ -181,11 +182,14 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv); ...@@ -181,11 +182,14 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
extern int mga_warp_init(drm_mga_private_t * dev_priv); extern int mga_warp_init(drm_mga_private_t * dev_priv);
/* mga_irq.c */ /* mga_irq.c */
extern int mga_enable_vblank(struct drm_device *dev, int crtc);
extern void mga_disable_vblank(struct drm_device *dev, int crtc);
extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc);
extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence); extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence);
extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
extern void mga_driver_irq_preinstall(struct drm_device * dev); extern void mga_driver_irq_preinstall(struct drm_device * dev);
extern void mga_driver_irq_postinstall(struct drm_device * dev); extern int mga_driver_irq_postinstall(struct drm_device *dev);
extern void mga_driver_irq_uninstall(struct drm_device * dev); extern void mga_driver_irq_uninstall(struct drm_device * dev);
extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg); unsigned long arg);
......
/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*- /* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
* */
/*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
* *
* The Weather Channel (TM) funded Tungsten Graphics to develop the * The Weather Channel (TM) funded Tungsten Graphics to develop the
...@@ -35,6 +36,18 @@ ...@@ -35,6 +36,18 @@
#include "mga_drm.h" #include "mga_drm.h"
#include "mga_drv.h" #include "mga_drv.h"
u32 mga_get_vblank_counter(struct drm_device *dev, int crtc)
{
const drm_mga_private_t *const dev_priv =
(drm_mga_private_t *) dev->dev_private;
if (crtc != 0)
return 0;
return atomic_read(&dev_priv->vbl_received);
}
irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
{ {
struct drm_device *dev = (struct drm_device *) arg; struct drm_device *dev = (struct drm_device *) arg;
...@@ -47,9 +60,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -47,9 +60,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
/* VBLANK interrupt */ /* VBLANK interrupt */
if (status & MGA_VLINEPEN) { if (status & MGA_VLINEPEN) {
MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
atomic_inc(&dev->vbl_received); atomic_inc(&dev_priv->vbl_received);
DRM_WAKEUP(&dev->vbl_queue); drm_handle_vblank(dev, 0);
drm_vbl_send_signals(dev);
handled = 1; handled = 1;
} }
...@@ -58,6 +70,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -58,6 +70,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
const u32 prim_end = MGA_READ(MGA_PRIMEND); const u32 prim_end = MGA_READ(MGA_PRIMEND);
MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
/* In addition to clearing the interrupt-pending bit, we /* In addition to clearing the interrupt-pending bit, we
...@@ -72,28 +85,39 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -72,28 +85,39 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
handled = 1; handled = 1;
} }
if (handled) { if (handled)
return IRQ_HANDLED; return IRQ_HANDLED;
}
return IRQ_NONE; return IRQ_NONE;
} }
int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) int mga_enable_vblank(struct drm_device *dev, int crtc)
{ {
unsigned int cur_vblank; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
int ret = 0;
/* Assume that the user has missed the current sequence number if (crtc != 0) {
* by about a day rather than she wants to wait for years DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
* using vertical blanks... crtc);
*/ return 0;
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, }
(((cur_vblank = atomic_read(&dev->vbl_received))
- *sequence) <= (1 << 23)));
*sequence = cur_vblank; MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
return 0;
}
return ret;
void mga_disable_vblank(struct drm_device *dev, int crtc)
{
if (crtc != 0) {
DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
crtc);
}
/* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have
* a nice hardware counter that tracks the number of refreshes when
* the interrupt is disabled, and the kernel doesn't know the refresh
* rate to calculate an estimate.
*/
/* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
} }
int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
...@@ -125,14 +149,22 @@ void mga_driver_irq_preinstall(struct drm_device * dev) ...@@ -125,14 +149,22 @@ void mga_driver_irq_preinstall(struct drm_device * dev)
MGA_WRITE(MGA_ICLEAR, ~0); MGA_WRITE(MGA_ICLEAR, ~0);
} }
void mga_driver_irq_postinstall(struct drm_device * dev) int mga_driver_irq_postinstall(struct drm_device *dev)
{ {
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
int ret;
ret = drm_vblank_init(dev, 1);
if (ret)
return ret;
DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
/* Turn on vertical blank interrupt and soft trap interrupt. */ /* Turn on soft trap interrupt. Vertical blank interrupts are enabled
MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); * in mga_enable_vblank.
*/
MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
return 0;
} }
void mga_driver_irq_uninstall(struct drm_device * dev) void mga_driver_irq_uninstall(struct drm_device * dev)
......
...@@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = { ...@@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = { static struct drm_driver driver = {
.driver_features = .driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
DRIVER_IRQ_VBL,
.dev_priv_size = sizeof(drm_r128_buf_priv_t), .dev_priv_size = sizeof(drm_r128_buf_priv_t),
.preclose = r128_driver_preclose, .preclose = r128_driver_preclose,
.lastclose = r128_driver_lastclose, .lastclose = r128_driver_lastclose,
.vblank_wait = r128_driver_vblank_wait, .get_vblank_counter = r128_get_vblank_counter,
.enable_vblank = r128_enable_vblank,
.disable_vblank = r128_disable_vblank,
.irq_preinstall = r128_driver_irq_preinstall, .irq_preinstall = r128_driver_irq_preinstall,
.irq_postinstall = r128_driver_irq_postinstall, .irq_postinstall = r128_driver_irq_postinstall,
.irq_uninstall = r128_driver_irq_uninstall, .irq_uninstall = r128_driver_irq_uninstall,
...@@ -70,7 +71,6 @@ static struct drm_driver driver = { ...@@ -70,7 +71,6 @@ static struct drm_driver driver = {
.compat_ioctl = r128_compat_ioctl, .compat_ioctl = r128_compat_ioctl,
#endif #endif
}, },
.pci_driver = { .pci_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = pciidlist, .id_table = pciidlist,
...@@ -87,6 +87,7 @@ static struct drm_driver driver = { ...@@ -87,6 +87,7 @@ static struct drm_driver driver = {
static int __init r128_init(void) static int __init r128_init(void)
{ {
driver.num_ioctls = r128_max_ioctl; driver.num_ioctls = r128_max_ioctl;
return drm_init(&driver); return drm_init(&driver);
} }
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
* Rickard E. (Rik) Faith <faith@valinux.com> * Rickard E. (Rik) Faith <faith@valinux.com>
* Kevin E. Martin <martin@valinux.com> * Kevin E. Martin <martin@valinux.com>
* Gareth Hughes <gareth@valinux.com> * Gareth Hughes <gareth@valinux.com>
* Michel Dänzer <daenzerm@student.ethz.ch> * Michel Dzer <daenzerm@student.ethz.ch>
*/ */
#ifndef __R128_DRV_H__ #ifndef __R128_DRV_H__
...@@ -97,6 +97,8 @@ typedef struct drm_r128_private { ...@@ -97,6 +97,8 @@ typedef struct drm_r128_private {
u32 crtc_offset; u32 crtc_offset;
u32 crtc_offset_cntl; u32 crtc_offset_cntl;
atomic_t vbl_received;
u32 color_fmt; u32 color_fmt;
unsigned int front_offset; unsigned int front_offset;
unsigned int front_pitch; unsigned int front_pitch;
...@@ -149,11 +151,12 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n); ...@@ -149,11 +151,12 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n);
extern int r128_do_cce_idle(drm_r128_private_t * dev_priv); extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
extern int r128_do_cleanup_cce(struct drm_device * dev); extern int r128_do_cleanup_cce(struct drm_device * dev);
extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); extern int r128_enable_vblank(struct drm_device *dev, int crtc);
extern void r128_disable_vblank(struct drm_device *dev, int crtc);
extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
extern void r128_driver_irq_preinstall(struct drm_device * dev); extern void r128_driver_irq_preinstall(struct drm_device * dev);
extern void r128_driver_irq_postinstall(struct drm_device * dev); extern int r128_driver_irq_postinstall(struct drm_device *dev);
extern void r128_driver_irq_uninstall(struct drm_device * dev); extern void r128_driver_irq_uninstall(struct drm_device * dev);
extern void r128_driver_lastclose(struct drm_device * dev); extern void r128_driver_lastclose(struct drm_device * dev);
extern void r128_driver_preclose(struct drm_device * dev, extern void r128_driver_preclose(struct drm_device * dev,
......
...@@ -35,6 +35,16 @@ ...@@ -35,6 +35,16 @@
#include "r128_drm.h" #include "r128_drm.h"
#include "r128_drv.h" #include "r128_drv.h"
u32 r128_get_vblank_counter(struct drm_device *dev, int crtc)
{
const drm_r128_private_t *dev_priv = dev->dev_private;
if (crtc != 0)
return 0;
return atomic_read(&dev_priv->vbl_received);
}
irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
{ {
struct drm_device *dev = (struct drm_device *) arg; struct drm_device *dev = (struct drm_device *) arg;
...@@ -46,30 +56,38 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -46,30 +56,38 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
/* VBLANK interrupt */ /* VBLANK interrupt */
if (status & R128_CRTC_VBLANK_INT) { if (status & R128_CRTC_VBLANK_INT) {
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
atomic_inc(&dev->vbl_received); atomic_inc(&dev_priv->vbl_received);
DRM_WAKEUP(&dev->vbl_queue); drm_handle_vblank(dev, 0);
drm_vbl_send_signals(dev);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
return IRQ_NONE; return IRQ_NONE;
} }
int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) int r128_enable_vblank(struct drm_device *dev, int crtc)
{ {
unsigned int cur_vblank; drm_r128_private_t *dev_priv = dev->dev_private;
int ret = 0;
/* Assume that the user has missed the current sequence number if (crtc != 0) {
* by about a day rather than she wants to wait for years DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
* using vertical blanks... return -EINVAL;
*/ }
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
(((cur_vblank = atomic_read(&dev->vbl_received)) R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
- *sequence) <= (1 << 23))); return 0;
}
*sequence = cur_vblank; void r128_disable_vblank(struct drm_device *dev, int crtc)
{
if (crtc != 0)
DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
return ret; /*
* FIXME: implement proper interrupt disable by using the vblank
* counter register (if available)
*
* R128_WRITE(R128_GEN_INT_CNTL,
* R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN);
*/
} }
void r128_driver_irq_preinstall(struct drm_device * dev) void r128_driver_irq_preinstall(struct drm_device * dev)
...@@ -82,12 +100,9 @@ void r128_driver_irq_preinstall(struct drm_device * dev) ...@@ -82,12 +100,9 @@ void r128_driver_irq_preinstall(struct drm_device * dev)
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
} }
void r128_driver_irq_postinstall(struct drm_device * dev) int r128_driver_irq_postinstall(struct drm_device *dev)
{ {
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private; return drm_vblank_init(dev, 1);
/* Turn on VBL interrupt */
R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
} }
void r128_driver_irq_uninstall(struct drm_device * dev) void r128_driver_irq_uninstall(struct drm_device * dev)
......
...@@ -1287,7 +1287,7 @@ static int radeon_do_resume_cp(struct drm_device * dev) ...@@ -1287,7 +1287,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
radeon_cp_init_ring_buffer(dev, dev_priv); radeon_cp_init_ring_buffer(dev, dev_priv);
radeon_do_engine_reset(dev); radeon_do_engine_reset(dev);
radeon_enable_interrupt(dev); radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
DRM_DEBUG("radeon_do_resume_cp() complete\n"); DRM_DEBUG("radeon_do_resume_cp() complete\n");
......
...@@ -52,6 +52,28 @@ static int dri_library_name(struct drm_device *dev, char *buf) ...@@ -52,6 +52,28 @@ static int dri_library_name(struct drm_device *dev, char *buf)
"r300")); "r300"));
} }
static int radeon_suspend(struct drm_device *dev, pm_message_t state)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
/* Disable *all* interrupts */
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
return 0;
}
static int radeon_resume(struct drm_device *dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
/* Restore interrupt registers */
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
return 0;
}
static struct pci_device_id pciidlist[] = { static struct pci_device_id pciidlist[] = {
radeon_PCI_IDS radeon_PCI_IDS
}; };
...@@ -59,8 +81,7 @@ static struct pci_device_id pciidlist[] = { ...@@ -59,8 +81,7 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = { static struct drm_driver driver = {
.driver_features = .driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,
DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2,
.dev_priv_size = sizeof(drm_radeon_buf_priv_t), .dev_priv_size = sizeof(drm_radeon_buf_priv_t),
.load = radeon_driver_load, .load = radeon_driver_load,
.firstopen = radeon_driver_firstopen, .firstopen = radeon_driver_firstopen,
...@@ -69,8 +90,11 @@ static struct drm_driver driver = { ...@@ -69,8 +90,11 @@ static struct drm_driver driver = {
.postclose = radeon_driver_postclose, .postclose = radeon_driver_postclose,
.lastclose = radeon_driver_lastclose, .lastclose = radeon_driver_lastclose,
.unload = radeon_driver_unload, .unload = radeon_driver_unload,
.vblank_wait = radeon_driver_vblank_wait, .suspend = radeon_suspend,
.vblank_wait2 = radeon_driver_vblank_wait2, .resume = radeon_resume,
.get_vblank_counter = radeon_get_vblank_counter,
.enable_vblank = radeon_enable_vblank,
.disable_vblank = radeon_disable_vblank,
.dri_library_name = dri_library_name, .dri_library_name = dri_library_name,
.irq_preinstall = radeon_driver_irq_preinstall, .irq_preinstall = radeon_driver_irq_preinstall,
.irq_postinstall = radeon_driver_irq_postinstall, .irq_postinstall = radeon_driver_irq_postinstall,
......
...@@ -378,17 +378,17 @@ extern void radeon_mem_release(struct drm_file *file_priv, ...@@ -378,17 +378,17 @@ extern void radeon_mem_release(struct drm_file *file_priv,
struct mem_block *heap); struct mem_block *heap);
/* radeon_irq.c */ /* radeon_irq.c */
extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state);
extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void radeon_do_release(struct drm_device * dev); extern void radeon_do_release(struct drm_device * dev);
extern int radeon_driver_vblank_wait(struct drm_device * dev, extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc);
unsigned int *sequence); extern int radeon_enable_vblank(struct drm_device *dev, int crtc);
extern int radeon_driver_vblank_wait2(struct drm_device * dev, extern void radeon_disable_vblank(struct drm_device *dev, int crtc);
unsigned int *sequence);
extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS); extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
extern void radeon_driver_irq_preinstall(struct drm_device * dev); extern void radeon_driver_irq_preinstall(struct drm_device * dev);
extern void radeon_driver_irq_postinstall(struct drm_device * dev); extern int radeon_driver_irq_postinstall(struct drm_device *dev);
extern void radeon_driver_irq_uninstall(struct drm_device * dev); extern void radeon_driver_irq_uninstall(struct drm_device * dev);
extern void radeon_enable_interrupt(struct drm_device *dev); extern void radeon_enable_interrupt(struct drm_device *dev);
extern int radeon_vblank_crtc_get(struct drm_device *dev); extern int radeon_vblank_crtc_get(struct drm_device *dev);
...@@ -397,19 +397,22 @@ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value); ...@@ -397,19 +397,22 @@ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
extern int radeon_driver_load(struct drm_device *dev, unsigned long flags); extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
extern int radeon_driver_unload(struct drm_device *dev); extern int radeon_driver_unload(struct drm_device *dev);
extern int radeon_driver_firstopen(struct drm_device *dev); extern int radeon_driver_firstopen(struct drm_device *dev);
extern void radeon_driver_preclose(struct drm_device * dev, struct drm_file *file_priv); extern void radeon_driver_preclose(struct drm_device *dev,
extern void radeon_driver_postclose(struct drm_device * dev, struct drm_file * filp); struct drm_file *file_priv);
extern void radeon_driver_postclose(struct drm_device *dev,
struct drm_file *file_priv);
extern void radeon_driver_lastclose(struct drm_device * dev); extern void radeon_driver_lastclose(struct drm_device * dev);
extern int radeon_driver_open(struct drm_device * dev, struct drm_file * filp_priv); extern int radeon_driver_open(struct drm_device *dev,
struct drm_file *file_priv);
extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd, extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg); unsigned long arg);
/* r300_cmdbuf.c */ /* r300_cmdbuf.c */
extern void r300_init_reg_flags(struct drm_device *dev); extern void r300_init_reg_flags(struct drm_device *dev);
extern int r300_do_cp_cmdbuf(struct drm_device * dev, extern int r300_do_cp_cmdbuf(struct drm_device *dev,
struct drm_file *file_priv, struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t * cmdbuf); drm_radeon_kcmd_buffer_t *cmdbuf);
/* Flags for stats.boxes /* Flags for stats.boxes
*/ */
...@@ -623,6 +626,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev, ...@@ -623,6 +626,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
# define RADEON_SW_INT_TEST (1 << 25) # define RADEON_SW_INT_TEST (1 << 25)
# define RADEON_SW_INT_TEST_ACK (1 << 25) # define RADEON_SW_INT_TEST_ACK (1 << 25)
# define RADEON_SW_INT_FIRE (1 << 26) # define RADEON_SW_INT_FIRE (1 << 26)
# define R500_DISPLAY_INT_STATUS (1 << 0)
#define RADEON_HOST_PATH_CNTL 0x0130 #define RADEON_HOST_PATH_CNTL 0x0130
# define RADEON_HDP_SOFT_RESET (1 << 26) # define RADEON_HDP_SOFT_RESET (1 << 26)
...@@ -1116,6 +1120,9 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev, ...@@ -1116,6 +1120,9 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
#define R200_VAP_PVS_CNTL_1 0x22D0 #define R200_VAP_PVS_CNTL_1 0x22D0
#define RADEON_CRTC_CRNT_FRAME 0x0214
#define RADEON_CRTC2_CRNT_FRAME 0x0314
#define R500_D1CRTC_STATUS 0x609c #define R500_D1CRTC_STATUS 0x609c
#define R500_D2CRTC_STATUS 0x689c #define R500_D2CRTC_STATUS 0x689c
#define R500_CRTC_V_BLANK (1<<0) #define R500_CRTC_V_BLANK (1<<0)
......
This diff is collapsed.
...@@ -40,11 +40,13 @@ static struct pci_device_id pciidlist[] = { ...@@ -40,11 +40,13 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = { static struct drm_driver driver = {
.driver_features = .driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, DRIVER_IRQ_SHARED,
.load = via_driver_load, .load = via_driver_load,
.unload = via_driver_unload, .unload = via_driver_unload,
.context_dtor = via_final_context, .context_dtor = via_final_context,
.vblank_wait = via_driver_vblank_wait, .get_vblank_counter = via_get_vblank_counter,
.enable_vblank = via_enable_vblank,
.disable_vblank = via_disable_vblank,
.irq_preinstall = via_driver_irq_preinstall, .irq_preinstall = via_driver_irq_preinstall,
.irq_postinstall = via_driver_irq_postinstall, .irq_postinstall = via_driver_irq_postinstall,
.irq_uninstall = via_driver_irq_uninstall, .irq_uninstall = via_driver_irq_uninstall,
......
...@@ -75,6 +75,7 @@ typedef struct drm_via_private { ...@@ -75,6 +75,7 @@ typedef struct drm_via_private {
struct timeval last_vblank; struct timeval last_vblank;
int last_vblank_valid; int last_vblank_valid;
unsigned usec_per_vblank; unsigned usec_per_vblank;
atomic_t vbl_received;
drm_via_state_t hc_state; drm_via_state_t hc_state;
char pci_buf[VIA_PCI_BUF_SIZE]; char pci_buf[VIA_PCI_BUF_SIZE];
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
...@@ -130,21 +131,24 @@ extern int via_init_context(struct drm_device * dev, int context); ...@@ -130,21 +131,24 @@ extern int via_init_context(struct drm_device * dev, int context);
extern int via_final_context(struct drm_device * dev, int context); extern int via_final_context(struct drm_device * dev, int context);
extern int via_do_cleanup_map(struct drm_device * dev); extern int via_do_cleanup_map(struct drm_device * dev);
extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc);
extern int via_enable_vblank(struct drm_device *dev, int crtc);
extern void via_disable_vblank(struct drm_device *dev, int crtc);
extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
extern void via_driver_irq_preinstall(struct drm_device * dev); extern void via_driver_irq_preinstall(struct drm_device * dev);
extern void via_driver_irq_postinstall(struct drm_device * dev); extern int via_driver_irq_postinstall(struct drm_device *dev);
extern void via_driver_irq_uninstall(struct drm_device * dev); extern void via_driver_irq_uninstall(struct drm_device * dev);
extern int via_dma_cleanup(struct drm_device * dev); extern int via_dma_cleanup(struct drm_device * dev);
extern void via_init_command_verifier(void); extern void via_init_command_verifier(void);
extern int via_driver_dma_quiescent(struct drm_device * dev); extern int via_driver_dma_quiescent(struct drm_device * dev);
extern void via_init_futex(drm_via_private_t * dev_priv); extern void via_init_futex(drm_via_private_t *dev_priv);
extern void via_cleanup_futex(drm_via_private_t * dev_priv); extern void via_cleanup_futex(drm_via_private_t *dev_priv);
extern void via_release_futex(drm_via_private_t * dev_priv, int context); extern void via_release_futex(drm_via_private_t *dev_priv, int context);
extern void via_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv); extern void via_reclaim_buffers_locked(struct drm_device *dev,
struct drm_file *file_priv);
extern void via_lastclose(struct drm_device *dev); extern void via_lastclose(struct drm_device *dev);
extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq); extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
......
...@@ -68,16 +68,15 @@ ...@@ -68,16 +68,15 @@
static maskarray_t via_pro_group_a_irqs[] = { static maskarray_t via_pro_group_a_irqs[] = {
{VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
0x00000000}, 0x00000000 },
{VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
0x00000000}, 0x00000000 },
{VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
}; };
static int via_num_pro_group_a = static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs);
sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t);
static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3}; static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
static maskarray_t via_unichrome_irqs[] = { static maskarray_t via_unichrome_irqs[] = {
...@@ -86,9 +85,10 @@ static maskarray_t via_unichrome_irqs[] = { ...@@ -86,9 +85,10 @@ static maskarray_t via_unichrome_irqs[] = {
{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008} VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
}; };
static int via_num_unichrome = sizeof(via_unichrome_irqs) / sizeof(maskarray_t); static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs);
static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
static unsigned time_diff(struct timeval *now, struct timeval *then) static unsigned time_diff(struct timeval *now, struct timeval *then)
{ {
return (now->tv_usec >= then->tv_usec) ? return (now->tv_usec >= then->tv_usec) ?
...@@ -96,6 +96,15 @@ static unsigned time_diff(struct timeval *now, struct timeval *then) ...@@ -96,6 +96,15 @@ static unsigned time_diff(struct timeval *now, struct timeval *then)
1000000 - (then->tv_usec - now->tv_usec); 1000000 - (then->tv_usec - now->tv_usec);
} }
u32 via_get_vblank_counter(struct drm_device *dev, int crtc)
{
drm_via_private_t *dev_priv = dev->dev_private;
if (crtc != 0)
return 0;
return atomic_read(&dev_priv->vbl_received);
}
irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
{ {
struct drm_device *dev = (struct drm_device *) arg; struct drm_device *dev = (struct drm_device *) arg;
...@@ -108,8 +117,8 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -108,8 +117,8 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
status = VIA_READ(VIA_REG_INTERRUPT); status = VIA_READ(VIA_REG_INTERRUPT);
if (status & VIA_IRQ_VBLANK_PENDING) { if (status & VIA_IRQ_VBLANK_PENDING) {
atomic_inc(&dev->vbl_received); atomic_inc(&dev_priv->vbl_received);
if (!(atomic_read(&dev->vbl_received) & 0x0F)) { if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
do_gettimeofday(&cur_vblank); do_gettimeofday(&cur_vblank);
if (dev_priv->last_vblank_valid) { if (dev_priv->last_vblank_valid) {
dev_priv->usec_per_vblank = dev_priv->usec_per_vblank =
...@@ -119,12 +128,11 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -119,12 +128,11 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
dev_priv->last_vblank = cur_vblank; dev_priv->last_vblank = cur_vblank;
dev_priv->last_vblank_valid = 1; dev_priv->last_vblank_valid = 1;
} }
if (!(atomic_read(&dev->vbl_received) & 0xFF)) { if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
DRM_DEBUG("US per vblank is: %u\n", DRM_DEBUG("US per vblank is: %u\n",
dev_priv->usec_per_vblank); dev_priv->usec_per_vblank);
} }
DRM_WAKEUP(&dev->vbl_queue); drm_handle_vblank(dev, 0);
drm_vbl_send_signals(dev);
handled = 1; handled = 1;
} }
...@@ -145,6 +153,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -145,6 +153,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
/* Acknowlege interrupts */ /* Acknowlege interrupts */
VIA_WRITE(VIA_REG_INTERRUPT, status); VIA_WRITE(VIA_REG_INTERRUPT, status);
if (handled) if (handled)
return IRQ_HANDLED; return IRQ_HANDLED;
else else
...@@ -163,31 +172,34 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv) ...@@ -163,31 +172,34 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
} }
} }
int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) int via_enable_vblank(struct drm_device *dev, int crtc)
{ {
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; drm_via_private_t *dev_priv = dev->dev_private;
unsigned int cur_vblank; u32 status;
int ret = 0;
DRM_DEBUG("\n"); if (crtc != 0) {
if (!dev_priv) { DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
DRM_ERROR("called with no initialization\n");
return -EINVAL; return -EINVAL;
} }
viadrv_acknowledge_irqs(dev_priv); status = VIA_READ(VIA_REG_INTERRUPT);
VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
/* Assume that the user has missed the current sequence number VIA_WRITE8(0x83d4, 0x11);
* by about a day rather than she wants to wait for years VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
* using vertical blanks...
*/
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, return 0;
(((cur_vblank = atomic_read(&dev->vbl_received)) - }
*sequence) <= (1 << 23)));
*sequence = cur_vblank; void via_disable_vblank(struct drm_device *dev, int crtc)
return ret; {
drm_via_private_t *dev_priv = dev->dev_private;
VIA_WRITE8(0x83d4, 0x11);
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
if (crtc != 0)
DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
} }
static int static int
...@@ -239,6 +251,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc ...@@ -239,6 +251,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
return ret; return ret;
} }
/* /*
* drm_dma.h hooks * drm_dma.h hooks
*/ */
...@@ -292,23 +305,25 @@ void via_driver_irq_preinstall(struct drm_device * dev) ...@@ -292,23 +305,25 @@ void via_driver_irq_preinstall(struct drm_device * dev)
} }
} }
void via_driver_irq_postinstall(struct drm_device * dev) int via_driver_irq_postinstall(struct drm_device *dev)
{ {
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
u32 status; u32 status;
DRM_DEBUG("\n"); DRM_DEBUG("via_driver_irq_postinstall\n");
if (dev_priv) { if (!dev_priv)
return -EINVAL;
drm_vblank_init(dev, 1);
status = VIA_READ(VIA_REG_INTERRUPT); status = VIA_READ(VIA_REG_INTERRUPT);
VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
| dev_priv->irq_enable_mask); | dev_priv->irq_enable_mask);
/* Some magic, oh for some data sheets ! */ /* Some magic, oh for some data sheets ! */
VIA_WRITE8(0x83d4, 0x11); VIA_WRITE8(0x83d4, 0x11);
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
} return 0;
} }
void via_driver_irq_uninstall(struct drm_device * dev) void via_driver_irq_uninstall(struct drm_device * dev)
...@@ -352,7 +367,8 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -352,7 +367,8 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) { switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
case VIA_IRQ_RELATIVE: case VIA_IRQ_RELATIVE:
irqwait->request.sequence += atomic_read(&cur_irq->irq_received); irqwait->request.sequence +=
atomic_read(&cur_irq->irq_received);
irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
case VIA_IRQ_ABSOLUTE: case VIA_IRQ_ABSOLUTE:
break; break;
......
...@@ -454,6 +454,7 @@ struct drm_irq_busid { ...@@ -454,6 +454,7 @@ struct drm_irq_busid {
enum drm_vblank_seq_type { enum drm_vblank_seq_type {
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
_DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */
_DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
_DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
_DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
...@@ -486,6 +487,19 @@ union drm_wait_vblank { ...@@ -486,6 +487,19 @@ union drm_wait_vblank {
struct drm_wait_vblank_reply reply; struct drm_wait_vblank_reply reply;
}; };
#define _DRM_PRE_MODESET 1
#define _DRM_POST_MODESET 2
/**
* DRM_IOCTL_MODESET_CTL ioctl argument type
*
* \sa drmModesetCtl().
*/
struct drm_modeset_ctl {
uint32_t crtc;
uint32_t cmd;
};
/** /**
* DRM_IOCTL_AGP_ENABLE ioctl argument type. * DRM_IOCTL_AGP_ENABLE ioctl argument type.
* *
...@@ -570,6 +584,7 @@ struct drm_set_version { ...@@ -570,6 +584,7 @@ struct drm_set_version {
#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client)
#define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats)
#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version)
#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl)
#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique)
#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth)
......
...@@ -580,10 +580,53 @@ struct drm_driver { ...@@ -580,10 +580,53 @@ struct drm_driver {
int (*kernel_context_switch) (struct drm_device *dev, int old, int (*kernel_context_switch) (struct drm_device *dev, int old,
int new); int new);
void (*kernel_context_switch_unlock) (struct drm_device *dev); void (*kernel_context_switch_unlock) (struct drm_device *dev);
int (*vblank_wait) (struct drm_device *dev, unsigned int *sequence);
int (*vblank_wait2) (struct drm_device *dev, unsigned int *sequence);
int (*dri_library_name) (struct drm_device *dev, char *buf); int (*dri_library_name) (struct drm_device *dev, char *buf);
/**
* get_vblank_counter - get raw hardware vblank counter
* @dev: DRM device
* @crtc: counter to fetch
*
* Driver callback for fetching a raw hardware vblank counter
* for @crtc. If a device doesn't have a hardware counter, the
* driver can simply return the value of drm_vblank_count and
* make the enable_vblank() and disable_vblank() hooks into no-ops,
* leaving interrupts enabled at all times.
*
* Wraparound handling and loss of events due to modesetting is dealt
* with in the DRM core code.
*
* RETURNS
* Raw vblank counter value.
*/
u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);
/**
* enable_vblank - enable vblank interrupt events
* @dev: DRM device
* @crtc: which irq to enable
*
* Enable vblank interrupts for @crtc. If the device doesn't have
* a hardware vblank counter, this routine should be a no-op, since
* interrupts will have to stay on to keep the count accurate.
*
* RETURNS
* Zero on success, appropriate errno if the given @crtc's vblank
* interrupt cannot be enabled.
*/
int (*enable_vblank) (struct drm_device *dev, int crtc);
/**
* disable_vblank - disable vblank interrupt events
* @dev: DRM device
* @crtc: which irq to enable
*
* Disable vblank interrupts for @crtc. If the device doesn't have
* a hardware vblank counter, this routine should be a no-op, since
* interrupts will have to stay on to keep the count accurate.
*/
void (*disable_vblank) (struct drm_device *dev, int crtc);
/** /**
* Called by \c drm_device_is_agp. Typically used to determine if a * Called by \c drm_device_is_agp. Typically used to determine if a
* card is really attached to AGP or not. * card is really attached to AGP or not.
...@@ -601,7 +644,7 @@ struct drm_driver { ...@@ -601,7 +644,7 @@ struct drm_driver {
irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); irqreturn_t(*irq_handler) (DRM_IRQ_ARGS);
void (*irq_preinstall) (struct drm_device *dev); void (*irq_preinstall) (struct drm_device *dev);
void (*irq_postinstall) (struct drm_device *dev); int (*irq_postinstall) (struct drm_device *dev);
void (*irq_uninstall) (struct drm_device *dev); void (*irq_uninstall) (struct drm_device *dev);
void (*reclaim_buffers) (struct drm_device *dev, void (*reclaim_buffers) (struct drm_device *dev,
struct drm_file * file_priv); struct drm_file * file_priv);
...@@ -730,13 +773,28 @@ struct drm_device { ...@@ -730,13 +773,28 @@ struct drm_device {
/** \name VBLANK IRQ support */ /** \name VBLANK IRQ support */
/*@{ */ /*@{ */
wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ /*
atomic_t vbl_received; * At load time, disabling the vblank interrupt won't be allowed since
atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */ * old clients may not call the modeset ioctl and therefore misbehave.
* Once the modeset ioctl *has* been called though, we can safely
* disable them when unused.
*/
int vblank_disable_allowed;
wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */
atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */
spinlock_t vbl_lock; spinlock_t vbl_lock;
struct list_head vbl_sigs; /**< signal list to send on VBLANK */ struct list_head *vbl_sigs; /**< signal list to send on VBLANK */
struct list_head vbl_sigs2; /**< signals to send on secondary VBLANK */ atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/
unsigned int vbl_pending; atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */
u32 *last_vblank; /* protected by dev->vbl_lock, used */
/* for wraparound handling */
int *vblank_enabled; /* so we don't call enable more than
once per disable */
int *vblank_inmodeset; /* Display driver is setting mode */
struct timer_list vblank_disable_timer;
u32 max_vblank_count; /**< size of vblank counter register */
spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ spinlock_t tasklet_lock; /**< For drm_locked_tasklet */
void (*locked_tasklet_func)(struct drm_device *dev); void (*locked_tasklet_func)(struct drm_device *dev);
...@@ -757,6 +815,7 @@ struct drm_device { ...@@ -757,6 +815,7 @@ struct drm_device {
struct pci_controller *hose; struct pci_controller *hose;
#endif #endif
struct drm_sg_mem *sg; /**< Scatter gather memory */ struct drm_sg_mem *sg; /**< Scatter gather memory */
int num_crtcs; /**< Number of CRTCs on this device */
void *dev_private; /**< device private data */ void *dev_private; /**< device private data */
struct drm_sigdata sigdata; /**< For block_all_signals */ struct drm_sigdata sigdata; /**< For block_all_signals */
sigset_t sigmask; sigset_t sigmask;
...@@ -990,10 +1049,19 @@ extern void drm_driver_irq_preinstall(struct drm_device *dev); ...@@ -990,10 +1049,19 @@ extern void drm_driver_irq_preinstall(struct drm_device *dev);
extern void drm_driver_irq_postinstall(struct drm_device *dev); extern void drm_driver_irq_postinstall(struct drm_device *dev);
extern void drm_driver_irq_uninstall(struct drm_device *dev); extern void drm_driver_irq_uninstall(struct drm_device *dev);
extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
extern int drm_wait_vblank(struct drm_device *dev, void *data, extern int drm_wait_vblank(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *filp);
extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
extern void drm_vbl_send_signals(struct drm_device *dev); extern void drm_locked_tasklet(struct drm_device *dev,
void(*func)(struct drm_device *));
extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
extern void drm_handle_vblank(struct drm_device *dev, int crtc);
extern int drm_vblank_get(struct drm_device *dev, int crtc);
extern void drm_vblank_put(struct drm_device *dev, int crtc);
/* Modesetting support */
extern int drm_modeset_ctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*));
/* AGP/GART support (drm_agpsupport.h) */ /* AGP/GART support (drm_agpsupport.h) */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment