summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormiao chen - Sun Microsystems - Beijing China <Miao.Chen@Sun.COM>2009-02-17 16:22:10 +0800
committermiao chen - Sun Microsystems - Beijing China <Miao.Chen@Sun.COM>2009-02-17 16:22:10 +0800
commitd02310705313ee2fcefee164a4b26d1fa85e9d22 (patch)
tree00eee2f6127e0c3b06b8ada57322f99073d66268
parent6532b9600e063234d62bca681503353c01abad20 (diff)
downloadillumos-gate-d02310705313ee2fcefee164a4b26d1fa85e9d22.tar.gz
6773943 i915 should be updated to 1.5.x to support Xorg 1.5/Mesa 7.2
6794701 radeon driver does not work with Xorg 1.5
-rw-r--r--usr/src/pkgdefs/SUNWdrmr/postinstall5
-rw-r--r--usr/src/uts/common/io/drm/drm.h9
-rw-r--r--usr/src/uts/common/io/drm/drmP.h53
-rw-r--r--usr/src/uts/common/io/drm/drm_atomic.h6
-rw-r--r--usr/src/uts/common/io/drm/drm_bufs.c10
-rw-r--r--usr/src/uts/common/io/drm/drm_drawable.c12
-rw-r--r--usr/src/uts/common/io/drm/drm_drv.c16
-rw-r--r--usr/src/uts/common/io/drm/drm_io32.h14
-rw-r--r--usr/src/uts/common/io/drm/drm_irq.c288
-rw-r--r--usr/src/uts/common/io/drm/drm_lock.c39
-rw-r--r--usr/src/uts/common/sys/agp/agpdefs.h4
-rw-r--r--usr/src/uts/intel/io/agpgart/agptarget.c4
-rw-r--r--usr/src/uts/intel/io/agpmaster/agpmaster.c6
-rw-r--r--usr/src/uts/intel/io/drm/drm_pciids.h3
-rw-r--r--usr/src/uts/intel/io/drm/i915_dma.c514
-rw-r--r--usr/src/uts/intel/io/drm/i915_drm.h47
-rw-r--r--usr/src/uts/intel/io/drm/i915_drv.c19
-rw-r--r--usr/src/uts/intel/io/drm/i915_drv.h194
-rw-r--r--usr/src/uts/intel/io/drm/i915_irq.c854
19 files changed, 1546 insertions, 551 deletions
diff --git a/usr/src/pkgdefs/SUNWdrmr/postinstall b/usr/src/pkgdefs/SUNWdrmr/postinstall
index 8bda640545..2bb7740f2f 100644
--- a/usr/src/pkgdefs/SUNWdrmr/postinstall
+++ b/usr/src/pkgdefs/SUNWdrmr/postinstall
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# SUNWdrmr postinstall script
@@ -150,7 +150,6 @@ else
ADD_DRV="check_add_drv -b ${BASEDIR}"
fi
-${ADD_DRV} -m "${DRVPERM}" -i "${IGFX_ALIAS}" i915 && \
-${ADD_DRV} -m "${DRVPERM}" -i "${RADEON_ALIAS}" radeon || EXIT=1
+${ADD_DRV} -m "${DRVPERM}" -i "${IGFX_ALIAS}" i915 || EXIT=1
exit ${EXIT}
diff --git a/usr/src/uts/common/io/drm/drm.h b/usr/src/uts/common/io/drm/drm.h
index 1b56718d9c..13e8bcf33c 100644
--- a/usr/src/uts/common/io/drm/drm.h
+++ b/usr/src/uts/common/io/drm/drm.h
@@ -58,15 +58,13 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DRM_H_
#define _DRM_H_
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types32.h>
#ifndef __user
@@ -357,7 +355,8 @@ typedef enum drm_map_flags {
_DRM_KERNEL = 0x08, /**< kernel requires access */
_DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */
_DRM_CONTAINS_LOCK = 0x20, /**< SHM page that contains lock */
- _DRM_REMOVABLE = 0x40 /**< Removable mapping */
+ _DRM_REMOVABLE = 0x40, /**< Removable mapping */
+ _DRM_DRIVER = 0x80 /**< Managed by driver */
} drm_map_flags_t;
typedef struct drm_ctx_priv_map {
@@ -633,6 +632,7 @@ typedef struct drm_irq_busid {
typedef enum {
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
_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_SECONDARY = 0x20000000, /**< Secondary display controller */
_DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
@@ -802,6 +802,7 @@ typedef struct drm_set_version {
#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
+#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t)
/*@}*/
/**
diff --git a/usr/src/uts/common/io/drm/drmP.h b/usr/src/uts/common/io/drm/drmP.h
index 5a6745c4e3..a02604296f 100644
--- a/usr/src/uts/common/io/drm/drmP.h
+++ b/usr/src/uts/common/io/drm/drmP.h
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -454,7 +454,6 @@ typedef struct drm_dma_handle {
uint_t cookie_num;
uintptr_t vaddr; /* virtual addr */
uintptr_t paddr; /* physical addr */
- size_t req_sz; /* required size of memory */
size_t real_sz; /* real size of memory */
} drm_dma_handle_t;
@@ -518,8 +517,6 @@ typedef struct ati_pcigart_info {
drm_local_map_t mapping;
} drm_ati_pcigart_info;
-
-
/* DRM device structure */
struct drm_device;
struct drm_driver_info {
@@ -554,6 +551,10 @@ struct drm_driver_info {
uint_t (*irq_handler)(DRM_IRQ_ARGS);
int (*vblank_wait)(struct drm_device *, unsigned int *);
int (*vblank_wait2)(struct drm_device *, unsigned int *);
+ /* added for intel minimized vblank */
+ u32 (*get_vblank_counter)(struct drm_device *dev, int crtc);
+ int (*enable_vblank)(struct drm_device *dev, int crtc);
+ void (*disable_vblank)(struct drm_device *dev, int crtc);
drm_ioctl_desc_t *driver_ioctls;
int max_driver_ioctl;
@@ -578,7 +579,6 @@ struct drm_driver_info {
unsigned use_mtrr :1;
};
-
/*
* hardware-specific code needs to initialize mutexes which
* can be used in interrupt context, so they need to know
@@ -607,6 +607,7 @@ struct drm_device {
int flags; /* Flags to open(2) */
/* Locks */
+ kmutex_t vbl_lock; /* protects vblank operations */
kmutex_t dma_lock; /* protects dev->dma */
kmutex_t irq_lock; /* protects irq condition checks */
kmutex_t dev_lock; /* protects everything else */
@@ -644,12 +645,38 @@ struct drm_device {
atomic_t context_flag; /* Context swapping flag */
int last_context; /* Last current context */
+ /* Only used for Radeon */
atomic_t vbl_received;
atomic_t vbl_received2;
+
drm_vbl_sig_list_t vbl_sig_list;
drm_vbl_sig_list_t vbl_sig_list2;
- wait_queue_head_t vbl_queue; /* vbl wait channel */
+ wait_queue_head_t vbl_queue; /* vbl wait channel */
+ /* vbl wait channel array */
+ wait_queue_head_t *vbl_queues;
+
+ /* number of VBLANK interrupts */
+ /* (driver must alloc the right number of counters) */
+ atomic_t *_vblank_count;
+ /* signal list to send on VBLANK */
+ struct drm_vbl_sig_list *vbl_sigs;
+
+ /* number of signals pending on all crtcs */
+ atomic_t vbl_signal_pending;
+ /* number of users of vblank interrupts per crtc */
+ atomic_t *vblank_refcount;
+ /* protected by dev->vbl_lock, used for wraparound handling */
+ u32 *last_vblank;
+ /* so we don't call enable more than */
+ atomic_t *vblank_enabled;
+ /* for compensation of spurious wraparounds */
+ u32 *vblank_premodeset;
+ /* Don't wait while crtc is likely disabled */
+ int *vblank_suspend;
+ /* size of vblank counter register */
+ u32 max_vblank_count;
+ int num_crtcs;
kmutex_t tasklet_lock;
void (*locked_tasklet_func)(struct drm_device *dev);
@@ -669,7 +696,6 @@ struct drm_device {
u32 *drw_bitfield;
unsigned int drw_info_length;
drm_drawable_info_t **drw_info;
-
/*
* Saving S3 context
*/
@@ -704,7 +730,7 @@ int drm_ctxbitmap_next(drm_device_t *);
/* Locking IOCTL support (drm_lock.c) */
int drm_lock_take(drm_lock_data_t *, unsigned int);
int drm_lock_transfer(drm_device_t *,
- volatile unsigned int *, unsigned int);
+ drm_lock_data_t *, unsigned int);
int drm_lock_free(drm_device_t *,
volatile unsigned int *, unsigned int);
@@ -734,6 +760,11 @@ void drm_driver_irq_postinstall(drm_device_t *);
void drm_driver_irq_uninstall(drm_device_t *);
int drm_vblank_wait(drm_device_t *, unsigned int *);
void drm_vbl_send_signals(drm_device_t *);
+void drm_handle_vblank(struct drm_device *dev, int crtc);
+u32 drm_vblank_count(struct drm_device *dev, int crtc);
+int drm_vblank_get(struct drm_device *dev, int crtc);
+void drm_vblank_put(struct drm_device *dev, int crtc);
+int drm_vblank_init(struct drm_device *dev, int num_crtcs);
void drm_locked_tasklet(drm_device_t *, void(*func)(drm_device_t *));
/* AGP/GART support (drm_agpsupport.c) */
@@ -787,6 +818,7 @@ int drm_getsareactx(DRM_IOCTL_ARGS);
/* Drawable IOCTL support (drm_drawable.c) */
int drm_adddraw(DRM_IOCTL_ARGS);
int drm_rmdraw(DRM_IOCTL_ARGS);
+int drm_update_draw(DRM_IOCTL_ARGS);
/* Authentication IOCTL support (drm_auth.c) */
int drm_getmagic(DRM_IOCTL_ARGS);
@@ -862,9 +894,8 @@ extern int pci_get_irq(drm_device_t *);
extern int pci_get_vendor(drm_device_t *);
extern int pci_get_device(drm_device_t *);
-extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *,
- drm_drawable_t);
-
+extern struct drm_drawable_info *drm_get_drawable_info(drm_device_t *,
+ drm_drawable_t);
/* File Operations helpers (drm_fops.c) */
extern drm_file_t *drm_find_file_by_proc(drm_device_t *, cred_t *);
extern drm_cminor_t *drm_find_file_by_minor(drm_device_t *, int);
diff --git a/usr/src/uts/common/io/drm/drm_atomic.h b/usr/src/uts/common/io/drm/drm_atomic.h
index 3958f4c920..002b974933 100644
--- a/usr/src/uts/common/io/drm/drm_atomic.h
+++ b/usr/src/uts/common/io/drm/drm_atomic.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
@@ -40,8 +40,6 @@
#ifndef _SYS_DRM_ATOMIC_H_
#define _SYS_DRM_ATOMIC_H_
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -57,7 +55,7 @@ typedef uint32_t atomic_t;
#define atomic_set(p, v) (*(p) = (v))
#define atomic_read(p) (*(p))
#define atomic_inc(p) atomic_add_int(p, 1)
-#define atomic_dec(p) atomic_dec_uint(p, 1)
+#define atomic_dec(p) atomic_dec_uint(p)
#define atomic_add(n, p) atomic_add_int(p, n)
#define atomic_sub(n, p) atomic_dec_uint(p, n)
#define atomic_set_int(p, bits) atomic_or_uint(p, bits)
diff --git a/usr/src/uts/common/io/drm/drm_bufs.c b/usr/src/uts/common/io/drm/drm_bufs.c
index 8f8757b2b9..ad1254072a 100644
--- a/usr/src/uts/common/io/drm/drm_bufs.c
+++ b/usr/src/uts/common/io/drm/drm_bufs.c
@@ -33,12 +33,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "drmP.h"
#include <gfx_private.h>
#include "drm_io32.h"
@@ -88,9 +86,6 @@ int drm_addmap(drm_device_t *dev, unsigned long offset,
caddr_t kva;
int retval;
- if (!(dev->flags & (FREAD|FWRITE)))
- return (EACCES); /* Require read/write */
-
/*
* Only allow shared memory to be removable since we only keep
* enough book keeping information about shared memory to allow
@@ -213,9 +208,6 @@ drm_addmap_ioctl(DRM_IOCTL_ARGS)
int err;
DRM_DEVICE;
- if (!(dev->flags & (FREAD|FWRITE)))
- return (EACCES); /* Require read/write */
-
#ifdef _MULTI_DATAMODEL
if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
drm_map_32_t request32;
diff --git a/usr/src/uts/common/io/drm/drm_drawable.c b/usr/src/uts/common/io/drm/drm_drawable.c
index 0a6f05034f..3ccc443944 100644
--- a/usr/src/uts/common/io/drm/drm_drawable.c
+++ b/usr/src/uts/common/io/drm/drm_drawable.c
@@ -32,12 +32,10 @@
*
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "drmP.h"
/*ARGSUSED*/
@@ -66,3 +64,11 @@ drm_drawable_info_t *
drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) {
return (NULL);
}
+
+/*ARGSUSED*/
+int
+drm_update_draw(DRM_IOCTL_ARGS)
+{
+ DRM_DEBUG("drm_update_draw\n");
+ return (0);
+}
diff --git a/usr/src/uts/common/io/drm/drm_drv.c b/usr/src/uts/common/io/drm/drm_drv.c
index 587c076332..253c158ff9 100644
--- a/usr/src/uts/common/io/drm/drm_drv.c
+++ b/usr/src/uts/common/io/drm/drm_drv.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -137,6 +137,8 @@ drm_ioctl_desc_t drm_ioctls[DRIVER_IOCTL_COUNT] = {
{drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] =
{drm_wait_vblank, 0},
+ [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] =
+ {drm_update_draw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
};
const char *
@@ -308,9 +310,13 @@ drm_load(drm_device_t *dev)
cv_init(&(dev->lock.lock_cv), NULL, CV_DRIVER, NULL);
mutex_init(&(dev->lock.lock_mutex), NULL, MUTEX_DRIVER, NULL);
- mutex_init(&(dev->dev_lock), NULL, MUTEX_DRIVER, NULL);
- mutex_init(&dev->drw_lock, NULL, MUTEX_DRIVER, NULL);
+ mutex_init(&(dev->dev_lock), "drmdev", MUTEX_DRIVER, NULL);
+ mutex_init(&dev->irq_lock, "drmirq", MUTEX_DRIVER,
+ (void *)dev->intr_block);
+ mutex_init(&dev->drw_lock, "drmdrw", MUTEX_DRIVER, NULL);
+ mutex_init(&dev->tasklet_lock, "drmtsk", MUTEX_DRIVER, NULL);
+ dev->irq = pci_get_irq(dev);
dev->pci_vendor = pci_get_vendor(dev);
dev->pci_device = pci_get_device(dev);
@@ -351,8 +357,10 @@ error:
DRM_UNLOCK();
cv_destroy(&(dev->lock.lock_cv));
mutex_destroy(&(dev->lock.lock_mutex));
+ mutex_destroy(&dev->irq_lock);
mutex_destroy(&(dev->dev_lock));
mutex_destroy(&dev->drw_lock);
+ mutex_destroy(&dev->tasklet_lock);
return (retcode);
}
@@ -379,8 +387,10 @@ drm_unload(drm_device_t *dev)
drm_mem_uninit();
cv_destroy(&dev->lock.lock_cv);
mutex_destroy(&dev->lock.lock_mutex);
+ mutex_destroy(&dev->irq_lock);
mutex_destroy(&dev->dev_lock);
mutex_destroy(&dev->drw_lock);
+ mutex_destroy(&dev->tasklet_lock);
}
diff --git a/usr/src/uts/common/io/drm/drm_io32.h b/usr/src/uts/common/io/drm/drm_io32.h
index ca0a7843e7..e710697f98 100644
--- a/usr/src/uts/common/io/drm/drm_io32.h
+++ b/usr/src/uts/common/io/drm/drm_io32.h
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifndef _DRM_IO32_H_
#define _DRM_IO32_H_
@@ -163,14 +161,14 @@ typedef struct drm_ctx_res_32 {
struct drm_wait_vblank_request_32 {
drm_vblank_seq_type_t type;
- unsigned int sequence;
- unsigned long signal;
+ uint32_t sequence;
+ uint32_t signal;
};
struct drm_wait_vblank_reply_32 {
drm_vblank_seq_type_t type;
- unsigned int sequence;
- long tval_sec;
- long tval_usec;
+ uint32_t sequence;
+ int32_t tval_sec;
+ int32_t tval_usec;
};
/*
diff --git a/usr/src/uts/common/io/drm/drm_irq.c b/usr/src/uts/common/io/drm/drm_irq.c
index 783d32be6c..a91a461333 100644
--- a/usr/src/uts/common/io/drm/drm_irq.c
+++ b/usr/src/uts/common/io/drm/drm_irq.c
@@ -30,12 +30,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "drmP.h"
#include "drm.h"
#include "drm_io32.h"
@@ -57,6 +55,9 @@ drm_irq_by_busid(DRM_IOCTL_ARGS)
irq.irq = dev->irq;
+ DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+ irq.busnum, irq.devnum, irq.funcnum, irq.irq);
+
DRM_COPYTO_WITH_RETURN((void *)data, &irq, sizeof (irq));
return (0);
@@ -76,6 +77,100 @@ drm_irq_handler_wrap(DRM_IRQ_ARGS)
return (ret);
}
+static void vblank_disable_fn(void *arg)
+{
+ struct drm_device *dev = (struct drm_device *)arg;
+ int i;
+
+ for (i = 0; i < dev->num_crtcs; i++) {
+ if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
+ atomic_read(&dev->vblank_enabled[i]) == 1) {
+ dev->last_vblank[i] =
+ dev->driver->get_vblank_counter(dev, i);
+ dev->driver->disable_vblank(dev, i);
+ atomic_set(&dev->vblank_enabled[i], 0);
+ DRM_DEBUG("disable vblank");
+ }
+ }
+}
+
+static void drm_vblank_cleanup(struct drm_device *dev)
+{
+ /* Bail if the driver didn't call drm_vblank_init() */
+ if (dev->num_crtcs == 0)
+ return;
+
+
+ vblank_disable_fn((void *)dev);
+
+ drm_free(dev->vbl_queues, sizeof (wait_queue_head_t) * dev->num_crtcs,
+ DRM_MEM_DRIVER);
+ drm_free(dev->vbl_sigs, sizeof (struct drm_vbl_sig) * dev->num_crtcs,
+ DRM_MEM_DRIVER);
+ drm_free(dev->_vblank_count, sizeof (atomic_t) *
+ dev->num_crtcs, DRM_MEM_DRIVER);
+ drm_free(dev->vblank_refcount, sizeof (atomic_t) *
+ dev->num_crtcs, DRM_MEM_DRIVER);
+ drm_free(dev->vblank_enabled, sizeof (int) *
+ dev->num_crtcs, DRM_MEM_DRIVER);
+ drm_free(dev->last_vblank, sizeof (u32) * dev->num_crtcs,
+ DRM_MEM_DRIVER);
+ dev->num_crtcs = 0;
+}
+
+int
+drm_vblank_init(struct drm_device *dev, int num_crtcs)
+{
+ int i, ret = ENOMEM;
+
+ atomic_set(&dev->vbl_signal_pending, 0);
+ dev->num_crtcs = num_crtcs;
+
+
+ dev->vbl_queues = drm_alloc(sizeof (wait_queue_head_t) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->vbl_queues)
+ goto err;
+
+ dev->vbl_sigs = drm_alloc(sizeof (struct drm_vbl_sig) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->vbl_sigs)
+ goto err;
+
+ dev->_vblank_count = drm_alloc(sizeof (atomic_t) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->_vblank_count)
+ goto err;
+
+ dev->vblank_refcount = drm_alloc(sizeof (atomic_t) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->vblank_refcount)
+ goto err;
+
+ dev->vblank_enabled = drm_alloc(num_crtcs * sizeof (int),
+ DRM_MEM_DRIVER);
+ if (!dev->vblank_enabled)
+ goto err;
+
+ dev->last_vblank = drm_alloc(num_crtcs * sizeof (u32), DRM_MEM_DRIVER);
+ if (!dev->last_vblank)
+ goto err;
+ /* Zero per-crtc vblank stuff */
+ for (i = 0; i < num_crtcs; i++) {
+ DRM_INIT_WAITQUEUE(&dev->vbl_queues[i], DRM_INTR_PRI(dev));
+ TAILQ_INIT(&dev->vbl_sigs[i]);
+ atomic_set(&dev->_vblank_count[i], 0);
+ atomic_set(&dev->vblank_refcount[i], 0);
+ atomic_set(&dev->vblank_enabled[i], 1);
+ }
+ vblank_disable_fn((void *)dev);
+ return (0);
+
+err:
+ DRM_ERROR("drm_vblank_init: alloc error");
+ drm_vblank_cleanup(dev);
+ return (ret);
+}
/*ARGSUSED*/
static int
@@ -100,8 +195,6 @@ drm_install_irq_handle(drm_device_t *dev)
return (DDI_FAILURE);
}
- mutex_init(&dev->irq_lock, NULL, MUTEX_DRIVER, (void *)dev->intr_block);
-
/* setup the interrupt handler */
if (ddi_add_intr(dip, 0, &dev->intr_block,
(ddi_idevice_cookie_t *)NULL, drm_irq_handler_wrap,
@@ -128,10 +221,9 @@ drm_irq_install(drm_device_t *dev)
DRM_ERROR("drm_irq_install: irq already enabled");
return (EBUSY);
}
-
+ dev->irq_enabled = 1;
+ DRM_DEBUG("drm_irq_install irq=%d\n", dev->irq);
dev->context_flag = 0;
- mutex_init(&dev->tasklet_lock, NULL, MUTEX_DRIVER, NULL);
-
/* before installing handler */
dev->driver->irq_preinstall(dev);
@@ -143,15 +235,9 @@ drm_irq_install(drm_device_t *dev)
return (ret);
}
- if (dev->driver->use_vbl_irq) {
- DRM_INIT_WAITQUEUE(&dev->vbl_queue, DRM_INTR_PRI(dev));
- }
-
/* after installing handler */
dev->driver->irq_postinstall(dev);
- dev->irq_enabled = 1;
-
return (0);
}
@@ -160,7 +246,6 @@ drm_uninstall_irq_handle(drm_device_t *dev)
{
ASSERT(dev->dip);
ddi_remove_intr(dev->dip, 0, dev->intr_block);
- mutex_destroy(&dev->irq_lock);
}
@@ -176,10 +261,9 @@ drm_irq_uninstall(drm_device_t *dev)
dev->driver->irq_uninstall(dev);
drm_uninstall_irq_handle(dev);
dev->locked_tasklet_func = NULL;
- if (dev->driver->use_vbl_irq) {
- DRM_FINI_WAITQUEUE(&dev->vbl_queue);
- }
- mutex_destroy(&dev->tasklet_lock);
+
+ drm_vblank_cleanup(dev);
+
return (DDI_SUCCESS);
}
@@ -208,19 +292,90 @@ drm_control(DRM_IOCTL_ARGS)
}
}
+u32
+drm_vblank_count(struct drm_device *dev, int crtc)
+{
+ return (atomic_read(&dev->_vblank_count[crtc]));
+}
+
+static void drm_update_vblank_count(struct drm_device *dev, int crtc)
+{
+ u32 cur_vblank, diff;
+ /*
+ * Interrupts were disabled prior to this call, so deal with counter
+ * wrap if needed.
+ * NOTE! It's possible we lost a full dev->max_vblank_count events
+ * here if the register is small or we had vblank interrupts off for
+ * a long time.
+ */
+ cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+ diff = cur_vblank - dev->last_vblank[crtc];
+ if (cur_vblank < dev->last_vblank[crtc]) {
+ diff += dev->max_vblank_count;
+ DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
+ crtc, dev->last_vblank[crtc], cur_vblank, diff);
+ }
+
+ atomic_add(diff, &dev->_vblank_count[crtc]);
+}
+
+static timeout_id_t timer_id = NULL;
+
+int
+drm_vblank_get(struct drm_device *dev, int crtc)
+{
+ int ret = 0;
+
+ DRM_SPINLOCK(&dev->vbl_lock);
+
+ if (timer_id != NULL) {
+ (void) untimeout(timer_id);
+ timer_id = NULL;
+ }
+
+ /* Going from 0->1 means we have to enable interrupts again */
+ atomic_add(1, &dev->vblank_refcount[crtc]);
+ if (dev->vblank_refcount[crtc] == 1 &&
+ atomic_read(&dev->vblank_enabled[crtc]) == 0) {
+ ret = dev->driver->enable_vblank(dev, crtc);
+ if (ret)
+ atomic_dec(&dev->vblank_refcount[crtc]);
+ else {
+ atomic_set(&dev->vblank_enabled[crtc], 1);
+ drm_update_vblank_count(dev, crtc);
+ }
+ }
+ DRM_SPINUNLOCK(&dev->vbl_lock);
+
+ return (ret);
+}
+
+void
+drm_vblank_put(struct drm_device *dev, int crtc)
+{
+ DRM_SPINLOCK(&dev->vbl_lock);
+ /* Last user schedules interrupt disable */
+ atomic_dec(&dev->vblank_refcount[crtc]);
+
+ if (dev->vblank_refcount[crtc] == 0)
+ timer_id = timeout(vblank_disable_fn, (void *) dev, 5*DRM_HZ);
+
+ DRM_SPINUNLOCK(&dev->vbl_lock);
+}
+
/*ARGSUSED*/
int
drm_wait_vblank(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_wait_vblank_t vblwait;
- struct timeval now;
- int ret, flags;
+ int ret, flags, crtc;
unsigned int sequence;
- if (!dev->irq_enabled)
+ if (!dev->irq_enabled) {
+ DRM_DEBUG("wait vblank, EINVAL");
return (EINVAL);
-
+ }
#ifdef _MULTI_DATAMODEL
if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
drm_wait_vblank_32_t vblwait32;
@@ -245,27 +400,28 @@ drm_wait_vblank(DRM_IOCTL_ARGS)
}
flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
- if (flags & _DRM_VBLANK_SECONDARY) {
- if (dev->driver->use_vbl_irq2 != 1)
- return (ENOTSUP);
- } else {
- if (dev->driver->use_vbl_irq != 1)
- return (ENOTSUP);
- }
+ crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
+ if (crtc >= dev->num_crtcs)
+ return (ENOTSUP);
- sequence = atomic_read((flags & _DRM_VBLANK_SECONDARY) ?
- &dev->vbl_received2 : &dev->vbl_received);
+ ret = drm_vblank_get(dev, crtc);
+ if (ret) {
+ DRM_DEBUG("can't get drm vblank");
+ return (ret);
+ }
+ sequence = drm_vblank_count(dev, crtc);
- if (vblwait.request.type & _DRM_VBLANK_RELATIVE) {
+ switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
+ case _DRM_VBLANK_RELATIVE:
vblwait.request.sequence += sequence;
vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
- }
-#ifdef DEBUG
- else if ((vblwait.request.type & _DRM_VBLANK_ABSOLUTE) == 0) {
- cmn_err(CE_WARN, "vblank_wait: unkown request type");
+ /*FALLTHROUGH*/
+ case _DRM_VBLANK_ABSOLUTE:
+ break;
+ default:
+ DRM_DEBUG("wait vblank return EINVAL");
return (EINVAL);
}
-#endif
if ((flags & _DRM_VBLANK_NEXTONMISS) &&
(sequence - vblwait.request.sequence) <= (1<<23)) {
@@ -276,32 +432,33 @@ drm_wait_vblank(DRM_IOCTL_ARGS)
/*
* Don't block process, send signal when vblank interrupt
*/
-
+ DRM_DEBUG("NOT SUPPORT YET, SHOULD BE ADDED");
cmn_err(CE_WARN, "NOT SUPPORT YET, SHOULD BE ADDED");
ret = EINVAL;
+ goto done;
} else {
/* block until vblank interupt */
-
- if (flags & _DRM_VBLANK_SECONDARY) {
- ret = dev->driver->vblank_wait2(dev,
- &vblwait.request.sequence);
- } else {
- ret = dev->driver->vblank_wait(dev,
- &vblwait.request.sequence);
+ /* shared code returns -errno */
+ DRM_WAIT_ON(ret, &dev->vbl_queues[crtc], 3 * DRM_HZ,
+ ((drm_vblank_count(dev, crtc)
+ - vblwait.request.sequence) <= (1 << 23)));
+ if (ret != EINTR) {
+ struct timeval now;
+ (void) uniqtime(&now);
+ vblwait.reply.tval_sec = now.tv_sec;
+ vblwait.reply.tval_usec = now.tv_usec;
+ vblwait.reply.sequence = drm_vblank_count(dev, crtc);
}
-
- (void) uniqtime(&now);
- vblwait.reply.tval_sec = now.tv_sec;
- vblwait.reply.tval_usec = now.tv_usec;
}
+done:
#ifdef _MULTI_DATAMODEL
if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
drm_wait_vblank_32_t vblwait32;
vblwait32.reply.type = vblwait.reply.type;
vblwait32.reply.sequence = vblwait.reply.sequence;
- vblwait32.reply.tval_sec = vblwait.reply.tval_sec;
- vblwait32.reply.tval_usec = vblwait.reply.tval_usec;
+ vblwait32.reply.tval_sec = (int32_t)vblwait.reply.tval_sec;
+ vblwait32.reply.tval_usec = (int32_t)vblwait.reply.tval_usec;
DRM_COPYTO_WITH_RETURN((void *)data, &vblwait32,
sizeof (vblwait32));
} else {
@@ -311,6 +468,8 @@ drm_wait_vblank(DRM_IOCTL_ARGS)
#ifdef _MULTI_DATAMODEL
}
#endif
+
+ drm_vblank_put(dev, crtc);
return (ret);
}
@@ -319,24 +478,15 @@ drm_wait_vblank(DRM_IOCTL_ARGS)
void
drm_vbl_send_signals(drm_device_t *dev)
{
- drm_vbl_sig_t *vbl_sig;
- unsigned int vbl_seq = atomic_read(&dev->vbl_received);
- proc_t *pp;
-
- vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list);
- while (vbl_sig != NULL) {
- drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link);
-
- if ((vbl_seq - vbl_sig->sequence) <= (1<<23)) {
- pp = prfind(vbl_sig->pid);
- if (pp != NULL)
- psignal(pp, vbl_sig->signo);
+ DRM_DEBUG("drm_vbl_send_signals");
+}
- TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link);
- drm_free(vbl_sig, sizeof (*vbl_sig), DRM_MEM_DRIVER);
- }
- vbl_sig = next;
- }
+void
+drm_handle_vblank(struct drm_device *dev, int crtc)
+{
+ atomic_inc(&dev->_vblank_count[crtc]);
+ DRM_WAKEUP(&dev->vbl_queues[crtc]);
+ drm_vbl_send_signals(dev);
}
/*
diff --git a/usr/src/uts/common/io/drm/drm_lock.c b/usr/src/uts/common/io/drm/drm_lock.c
index 308106ba61..69a43a7598 100644
--- a/usr/src/uts/common/io/drm/drm_lock.c
+++ b/usr/src/uts/common/io/drm/drm_lock.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -37,14 +37,12 @@
*
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "drmP.h"
int
drm_lock_take(drm_lock_data_t *lock_data, unsigned int context)
{
- unsigned int old, new, prev;
+ unsigned int old, new;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
do {
@@ -53,8 +51,7 @@ drm_lock_take(drm_lock_data_t *lock_data, unsigned int context)
new = old | _DRM_LOCK_CONT;
else
new = context | _DRM_LOCK_HELD;
- prev = atomic_cas_uint(lock, old, new);
- } while (prev != old);
+ } while (!atomic_cmpset_int(lock, old, new));
if (_DRM_LOCKING_CONTEXT(old) == context) {
if (old & _DRM_LOCK_HELD) {
@@ -65,9 +62,8 @@ drm_lock_take(drm_lock_data_t *lock_data, unsigned int context)
return (0);
}
}
- if ((_DRM_LOCKING_CONTEXT(new)) == context &&
- _DRM_LOCK_IS_HELD(new)) {
- /* Have lock */
+ if (new == (context | _DRM_LOCK_HELD)) {
+ /* Have lock */
return (1);
}
return (0);
@@ -78,17 +74,17 @@ drm_lock_take(drm_lock_data_t *lock_data, unsigned int context)
* inside *_unlock to give lock to kernel before calling *_dma_schedule.
*/
int
-drm_lock_transfer(drm_device_t *dev, volatile unsigned int *lock,
- unsigned int context)
+drm_lock_transfer(drm_device_t *dev, drm_lock_data_t *lock_data,
+ unsigned int context)
{
- unsigned int old, new, prev;
+ unsigned int old, new;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
dev->lock.filp = NULL;
do {
old = *lock;
new = context | _DRM_LOCK_HELD;
- prev = atomic_cas_uint(lock, old, new);
- } while (prev != old);
+ } while (!atomic_cmpset_int(lock, old, new));
return (1);
}
@@ -97,15 +93,14 @@ int
drm_lock_free(drm_device_t *dev, volatile unsigned int *lock,
unsigned int context)
{
- unsigned int old, new, prev;
+ unsigned int old, new;
mutex_enter(&(dev->lock.lock_mutex));
dev->lock.filp = NULL;
do {
old = *lock;
new = 0;
- prev = atomic_cas_uint(lock, old, new);
- } while (prev != old);
+ } while (!atomic_cmpset_int(lock, old, new));
if (_DRM_LOCK_IS_HELD(old) &&
(_DRM_LOCKING_CONTEXT(old) != context)) {
@@ -130,9 +125,14 @@ drm_lock(DRM_IOCTL_ARGS)
DRM_COPYFROM_WITH_RETURN(&lock, (void *)data, sizeof (lock));
if (lock.context == DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Process %d using kernel context %d\n",
+ DRM_CURRENTPID, lock.context);
return (EINVAL);
}
+ DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+ lock.context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
+ lock.flags);
if (dev->driver->use_dma_queue && lock.context < 0)
return (EINVAL);
@@ -152,6 +152,7 @@ drm_lock(DRM_IOCTL_ARGS)
}
}
mutex_exit(&(dev->lock.lock_mutex));
+ DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
if (dev->driver->dma_quiescent != NULL &&
(lock.flags & _DRM_LOCK_QUIESCENT))
@@ -169,6 +170,10 @@ drm_unlock(DRM_IOCTL_ARGS)
DRM_COPYFROM_WITH_RETURN(&lock, (void *)data, sizeof (lock));
+ DRM_DEBUG("%d (pid %d) requests unlock (0x%08x), flags = 0x%08x\n",
+ lock.context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
+ lock.flags);
+
if (lock.context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
DRM_CURRENTPID, lock.context);
diff --git a/usr/src/uts/common/sys/agp/agpdefs.h b/usr/src/uts/common/sys/agp/agpdefs.h
index c77559ea85..507953f83c 100644
--- a/usr/src/uts/common/sys/agp/agpdefs.h
+++ b/usr/src/uts/common/sys/agp/agpdefs.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -102,6 +102,7 @@ extern "C" {
#define INTEL_BR_EL 0x2e008086
#define INTEL_BR_Q45 0x2e108086
#define INTEL_BR_G45 0x2e208086
+#define INTEL_BR_G41 0x2e308086
/* AGP common register offset in pci configuration space */
#define AGP_CONF_MISC 0x51 /* one byte */
@@ -170,6 +171,7 @@ extern "C" {
#define INTEL_IGD_EL 0x2e028086
#define INTEL_IGD_Q45 0x2e128086
#define INTEL_IGD_G45 0x2e228086
+#define INTEL_IGD_G41 0x2e328086
/* register offsets in PCI config space */
#define I8XX_CONF_GMADR 0x10 /* GMADR of i8xx series */
diff --git a/usr/src/uts/intel/io/agpgart/agptarget.c b/usr/src/uts/intel/io/agpgart/agptarget.c
index f34124d342..d9b710b842 100644
--- a/usr/src/uts/intel/io/agpgart/agptarget.c
+++ b/usr/src/uts/intel/io/agpgart/agptarget.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -374,6 +374,8 @@ static gms_mode_t gms_modes[] = {
{INTEL_BR_Q45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
GMS_SIZE(gms_G4X), gms_G4X},
{INTEL_BR_G45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
+ GMS_SIZE(gms_G4X), gms_G4X},
+ {INTEL_BR_G41, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
GMS_SIZE(gms_G4X), gms_G4X}
};
static int
diff --git a/usr/src/uts/intel/io/agpmaster/agpmaster.c b/usr/src/uts/intel/io/agpmaster/agpmaster.c
index 7b4d290d23..20e48b0e8c 100644
--- a/usr/src/uts/intel/io/agpmaster/agpmaster.c
+++ b/usr/src/uts/intel/io/agpmaster/agpmaster.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -113,7 +113,8 @@ int agpm_debug = 0;
/* Intel G4X series */
#define IS_INTEL_G4X(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_EL) || \
(agpmaster->agpm_id == INTEL_IGD_Q45) || \
- (agpmaster->agpm_id == INTEL_IGD_G45))
+ (agpmaster->agpm_id == INTEL_IGD_G45) || \
+ (agpmaster->agpm_id == INTEL_IGD_G41))
static struct modlmisc modlmisc = {
&mod_miscops, "AGP master interfaces"
@@ -648,6 +649,7 @@ detect_i8xx_device(agp_master_softc_t *master_softc)
case INTEL_IGD_EL:
case INTEL_IGD_Q45:
case INTEL_IGD_G45:
+ case INTEL_IGD_G41:
master_softc->agpm_dev_type = DEVICE_IS_I830;
break;
default: /* unknown id */
diff --git a/usr/src/uts/intel/io/drm/drm_pciids.h b/usr/src/uts/intel/io/drm/drm_pciids.h
index c2a63d9f40..7d7f114392 100644
--- a/usr/src/uts/intel/io/drm/drm_pciids.h
+++ b/usr/src/uts/intel/io/drm/drm_pciids.h
@@ -3,7 +3,7 @@
* Please contact dri-devel@lists.sf.net to add new cards to this list
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -206,6 +206,7 @@ extern "C" {
{0x8086, 0x2E02, CHIP_I9XX|CHIP_I965, "Intel EL"}, \
{0x8086, 0x2E12, CHIP_I9XX|CHIP_I965, "Intel Q45"}, \
{0x8086, 0x2E22, CHIP_I9XX|CHIP_I965, "Intel G45"}, \
+ {0x8086, 0x2E32, CHIP_I9XX|CHIP_I965, "Intel G41"}, \
{0, 0, 0, NULL}
#ifdef __cplusplus
diff --git a/usr/src/uts/intel/io/drm/i915_dma.c b/usr/src/uts/intel/io/drm/i915_dma.c
index ccb7ae0cb7..c75d004442 100644
--- a/usr/src/uts/intel/io/drm/i915_dma.c
+++ b/usr/src/uts/intel/io/drm/i915_dma.c
@@ -29,7 +29,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -50,42 +50,112 @@ int i915_wait_ring(drm_device_t * dev, int n, const char *caller)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
- u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+ u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
+ u32 last_acthd = I915_READ(acthd_reg);
+ u32 acthd;
int i;
- for (i = 0; i < 10000; i++) {
- ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ for (i = 0; i < 100000; i++) {
+ ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+ acthd = I915_READ(acthd_reg);
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->Size;
if (ring->space >= n)
return 0;
- dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
-
if (ring->head != last_head)
i = 0;
+ if (acthd != last_acthd)
+ i = 0;
+
last_head = ring->head;
- DRM_UDELAY(1);
+ last_acthd = acthd;
+ DRM_UDELAY(10);
}
return (EBUSY);
}
+int i915_init_hardware_status(drm_device_t *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_dma_handle_t *dmah;
+
+ /* Program Hardware Status Page */
+ dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff,1);
+
+ if (!dmah) {
+ DRM_ERROR("Can not allocate hardware status page\n");
+ return -ENOMEM;
+ }
+
+ dev_priv->status_page_dmah = dmah;
+ dev_priv->hw_status_page = (void *)dmah->vaddr;
+ dev_priv->dma_status_page = dmah->paddr;
+
+ (void) memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+
+ I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
+ DRM_DEBUG("Enabled hardware status page\n");
+ return 0;
+}
+
+void i915_free_hardware_status(drm_device_t *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ if (!I915_NEED_GFX_HWS(dev)) {
+ if (dev_priv->status_page_dmah) {
+ drm_pci_free(dev, dev_priv->status_page_dmah);
+ dev_priv->status_page_dmah = NULL;
+ /* Need to rewrite hardware status page */
+ I915_WRITE(HWS_PGA, 0x1ffff000);
+ }
+ } else {
+ if (dev_priv->status_gfx_addr) {
+ dev_priv->status_gfx_addr = 0;
+ drm_core_ioremapfree(&dev_priv->hws_map, dev);
+ I915_WRITE(HWS_PGA, 0x1ffff000);
+ }
+ }
+}
+
+#if I915_RING_VALIDATE
+/**
+ * Validate the cached ring tail value
+ *
+ * If the X server writes to the ring and DRM doesn't
+ * reload the head and tail pointers, it will end up writing
+ * data to the wrong place in the ring, causing havoc.
+ */
+void i915_ring_validate(struct drm_device *dev, const char *func, int line)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
+ u32 tail = I915_READ(PRB0_TAIL) & HEAD_ADDR;
+ u32 head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+
+ if (tail != ring->tail) {
+ DRM_ERROR("%s:%d head sw %x, hw %x. tail sw %x hw %x\n",
+ func, line,
+ ring->head, head, ring->tail, tail);
+ }
+}
+#endif
+
void i915_kernel_lost_context(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
- ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
- ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
+ ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+ ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->Size;
- if (ring->head == ring->tail)
- dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
}
static int i915_dma_cleanup(drm_device_t * dev)
@@ -97,7 +167,7 @@ static int i915_dma_cleanup(drm_device_t * dev)
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if (dev->irq)
+ if (dev->irq_enabled)
(void) drm_irq_uninstall(dev);
if (dev_priv->ring.virtual_start) {
@@ -107,19 +177,10 @@ static int i915_dma_cleanup(drm_device_t * dev)
dev_priv->ring.map.size = 0;
}
- if (dev_priv->status_page_dmah) {
- drm_pci_free(dev, dev_priv->status_page_dmah);
- dev_priv->status_page_dmah = NULL;
+ i915_free_hardware_status(dev);
- /* Need to rewrite hardware status page */
- I915_WRITE(0x02080, 0x1ffff000);
- }
-
- if (dev_priv->status_gfx_addr) {
- dev_priv->status_gfx_addr = 0;
- drm_core_ioremapfree(&dev_priv->hws_map, dev);
- I915_WRITE(0x2080, 0x1ffff000);
- }
+ dev_priv->sarea = NULL;
+ dev_priv->sarea_priv = NULL;
return 0;
}
@@ -142,79 +203,68 @@ static int i915_initialize(drm_device_t * dev,
* mmio_map will be destoried after DMA clean up. We should not
* access mmio_map in suspend or resume process.
*/
- dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
- if (!dev_priv->mmio_map) {
- dev->dev_private = (void *)dev_priv;
- (void) i915_dma_cleanup(dev);
- DRM_ERROR("can not find mmio map!\n");
- return (EINVAL);
- }
-
- dev_priv->sarea_priv = (drm_i915_sarea_t *)(void *)
- ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
-
- dev_priv->ring.Start = init->ring_start;
- dev_priv->ring.End = init->ring_end;
- dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
- dev_priv->ring.map.offset = (u_offset_t)init->ring_start;
- dev_priv->ring.map.size = init->ring_size;
- dev_priv->ring.map.type = 0;
- dev_priv->ring.map.flags = 0;
- dev_priv->ring.map.mtrr = 0;
+ dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
- drm_core_ioremap(&dev_priv->ring.map, dev);
-
- if (dev_priv->ring.map.handle == NULL) {
- dev->dev_private = (void *)dev_priv;
- (void) i915_dma_cleanup(dev);
- DRM_ERROR("can not ioremap virtual address for"
+ if (!dev_priv->mmio_map) {
+ dev->dev_private = (void *)dev_priv;
+ (void) i915_dma_cleanup(dev);
+ DRM_ERROR("can not find mmio map!\n");
+ return (EINVAL);
+ }
+
+ if (init->sarea_priv_offset)
+ dev_priv->sarea_priv = (drm_i915_sarea_t *)
+ ((unsigned long) dev_priv->sarea->handle +
+ init->sarea_priv_offset);
+ else {
+ /* No sarea_priv for you! */
+ dev_priv->sarea_priv = NULL;
+ }
+
+ if (init->ring_size != 0) {
+ dev_priv->ring.Size = init->ring_size;
+ dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+
+ dev_priv->ring.map.offset = (u_offset_t)init->ring_start;
+ dev_priv->ring.map.size = init->ring_size;
+ dev_priv->ring.map.type = 0;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
+
+ drm_core_ioremap(&dev_priv->ring.map, dev);
+
+ if (dev_priv->ring.map.handle == NULL) {
+ (void) i915_dma_cleanup(dev);
+ DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return (ENOMEM);
- }
+ return (ENOMEM);
+ }
- dev_priv->ring.virtual_start = (u8 *)dev_priv->ring.map.dev_addr;
+ dev_priv->ring.virtual_start = (u8 *)dev_priv->ring.map.dev_addr;
+ }
dev_priv->cpp = init->cpp;
- dev_priv->back_offset = init->back_offset;
- dev_priv->front_offset = init->front_offset;
- dev_priv->current_page = 0;
- dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->pf_current_page = 0;
/* We are using separate values as placeholders for mechanisms for
* private backbuffer/depthbuffer usage.
*/
- dev_priv->use_mi_batchbuffer_start = 0;
/* Allow hardware batchbuffers unless told otherwise.
*/
dev_priv->allow_batchbuffer = 1;
-
+ /* Init HWS */
if (!I915_NEED_GFX_HWS(dev)) {
- /* Program Hardware Status Page */
- dev_priv->status_page_dmah =
- drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE,
- 0xffffffff, 1);
-
- if (!dev_priv->status_page_dmah) {
- dev->dev_private = (void *)dev_priv;
- (void) i915_dma_cleanup(dev);
- DRM_ERROR("Can not allocate hardware status page\n");
- return (ENOMEM);
- }
-
- dev_priv->hw_status_page =
- (void *)dev_priv->status_page_dmah->vaddr;
- dev_priv->dma_status_page = dev_priv->status_page_dmah->paddr;
- (void) memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
- DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
-
- I915_WRITE(0x02080, dev_priv->dma_status_page);
+ (void) i915_init_hardware_status(dev);
}
- DRM_DEBUG("Enabled hardware status page\n");
+ /* Enable vblank on pipe A for older X servers
+ */
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
#ifdef I915_HAVE_BUFFER
drm_bo_driver_init(dev);
@@ -226,18 +276,13 @@ static int i915_dma_resume(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("i915_dma_resume\n");
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
return (EINVAL);
}
- if (!dev_priv->mmio_map) {
- DRM_ERROR("can not find mmio map!\n");
- return (EINVAL);
- }
-
if (dev_priv->ring.map.handle == NULL) {
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
@@ -252,9 +297,9 @@ static int i915_dma_resume(drm_device_t * dev)
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
if (!I915_NEED_GFX_HWS(dev))
- I915_WRITE(0x02080, dev_priv->dma_status_page);
+ I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
else
- I915_WRITE(0x02080, dev_priv->status_gfx_addr);
+ I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
DRM_DEBUG("Enabled hardware status page\n");
return 0;
@@ -407,7 +452,7 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
return 0;
}
-static int i915_emit_box(drm_device_t * dev,
+int i915_emit_box(drm_device_t * dev,
drm_clip_rect_t __user * boxes,
int i, int DR1, int DR4)
{
@@ -450,29 +495,34 @@ static int i915_emit_box(drm_device_t * dev,
* emit. For now, do it in both places:
*/
-static void i915_emit_breadcrumb(drm_device_t *dev)
+void i915_emit_breadcrumb(drm_device_t *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
- dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
+ if (++dev_priv->counter > BREADCRUMB_MASK) {
+ dev_priv->counter = 1;
+ DRM_DEBUG("Breadcrumb counter wrapped around\n");
+ }
+
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
+
BEGIN_LP_RING(4);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(BREADCRUMB_OFFSET << 2);
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
OUT_RING(dev_priv->counter);
OUT_RING(0);
ADVANCE_LP_RING();
-#ifdef I915_HAVE_FENCE
- drm_fence_flush_old(dev, 0, dev_priv->counter);
-#endif
+
}
-int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush)
+void i915_emit_mi_flush(drm_device_t *dev, uint32_t flush)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t flush_cmd = CMD_MI_FLUSH;
+ uint32_t flush_cmd = MI_FLUSH;
RING_LOCALS;
flush_cmd |= flush;
@@ -485,13 +535,14 @@ int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush)
OUT_RING(0);
OUT_RING(0);
ADVANCE_LP_RING();
-
- return 0;
}
static int i915_dispatch_cmdbuffer(drm_device_t * dev,
drm_i915_cmdbuffer_t * cmd)
{
+#ifdef I915_HAVE_FENCE
+ drm_i915_private_t *dev_priv = dev->dev_private;
+#endif
int nbox = cmd->num_cliprects;
int i = 0, count, ret;
@@ -518,6 +569,10 @@ static int i915_dispatch_cmdbuffer(drm_device_t * dev,
}
i915_emit_breadcrumb( dev );
+#ifdef I915_HAVE_FENCE
+ if (unlikely((dev_priv->counter & 0xFF) == 0))
+ drm_fence_flush_old(dev, 0, dev_priv->counter);
+#endif
return 0;
}
@@ -547,18 +602,23 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev,
return ret;
}
- if (dev_priv->use_mi_batchbuffer_start) {
- BEGIN_LP_RING(2);
- OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
- OUT_RING(batch->start | MI_BATCH_NON_SECURE);
- ADVANCE_LP_RING();
- } else {
+ if (IS_I830(dev) || IS_845G(dev)) {
BEGIN_LP_RING(4);
OUT_RING(MI_BATCH_BUFFER);
OUT_RING(batch->start | MI_BATCH_NON_SECURE);
OUT_RING(batch->start + batch->used - 4);
OUT_RING(0);
ADVANCE_LP_RING();
+ } else {
+ BEGIN_LP_RING(2);
+ if (IS_I965G(dev)) {
+ OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
+ OUT_RING(batch->start);
+ } else {
+ OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
+ OUT_RING(batch->start | MI_BATCH_NON_SECURE);
+ }
+ ADVANCE_LP_RING();
}
}
@@ -567,62 +627,96 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev,
return 0;
}
-static int i915_dispatch_flip(drm_device_t * dev)
+static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 num_pages, current_page, next_page, dspbase;
+ int shift = 2 * plane, x, y;
RING_LOCALS;
- DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
- __FUNCTION__,
- dev_priv->current_page,
- dev_priv->sarea_priv->pf_current_page);
+ /* Calculate display base offset */
+ num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
+ current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3;
+ next_page = (current_page + 1) % num_pages;
- i915_kernel_lost_context(dev);
-
- BEGIN_LP_RING(2);
- OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
- OUT_RING(0);
- ADVANCE_LP_RING();
+ switch (next_page) {
+ default:
+ case 0:
+ dspbase = dev_priv->sarea_priv->front_offset;
+ break;
+ case 1:
+ dspbase = dev_priv->sarea_priv->back_offset;
+ break;
+ case 2:
+ dspbase = dev_priv->sarea_priv->third_offset;
+ break;
+ }
- BEGIN_LP_RING(6);
- OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
- OUT_RING(0);
- if (dev_priv->current_page == 0) {
- OUT_RING(dev_priv->back_offset);
- dev_priv->current_page = 1;
+ if (plane == 0) {
+ x = dev_priv->sarea_priv->planeA_x;
+ y = dev_priv->sarea_priv->planeA_y;
} else {
- OUT_RING(dev_priv->front_offset);
- dev_priv->current_page = 0;
+ x = dev_priv->sarea_priv->planeB_x;
+ y = dev_priv->sarea_priv->planeB_y;
}
- OUT_RING(0);
- ADVANCE_LP_RING();
- BEGIN_LP_RING(2);
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
- OUT_RING(0);
- ADVANCE_LP_RING();
+ dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp;
- dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+
+ DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page, dspbase);
BEGIN_LP_RING(4);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(BREADCRUMB_OFFSET << 2);
- OUT_RING(dev_priv->counter);
- OUT_RING(0);
+ OUT_RING(sync ? 0 :
+ (MI_WAIT_FOR_EVENT | (plane ? MI_WAIT_FOR_PLANE_B_FLIP :
+ MI_WAIT_FOR_PLANE_A_FLIP)));
+ OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) |
+ (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A));
+ OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp);
+ OUT_RING(dspbase);
ADVANCE_LP_RING();
+
+ dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift);
+ dev_priv->sarea_priv->pf_current_page |= next_page << shift;
+}
+
+void i915_dispatch_flip(struct drm_device * dev, int planes, int sync)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int i;
+
+ DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n",
+ planes, dev_priv->sarea_priv->pf_current_page);
+
+ i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH);
+
+ for (i = 0; i < 2; i++)
+ if (planes & (1 << i))
+ i915_do_dispatch_flip(dev, i, sync);
+
+ i915_emit_breadcrumb(dev);
#ifdef I915_HAVE_FENCE
- drm_fence_flush_old(dev, 0, dev_priv->counter);
+ if (unlikely(!sync && ((dev_priv->counter & 0xFF) == 0)))
+ drm_fence_flush_old(dev, 0, dev_priv->counter);
#endif
- dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
- return 0;
+
}
static int i915_quiescent(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
-
+ int ret;
i915_kernel_lost_context(dev);
- return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+ ret = i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+
+ if (ret)
+ {
+ i915_kernel_lost_context (dev);
+ DRM_ERROR ("not quiescent head %08x tail %08x space %08x\n",
+ dev_priv->ring.head,
+ dev_priv->ring.tail,
+ dev_priv->ring.space);
+ }
+ return ret;
}
/*ARGSUSED*/
@@ -640,7 +734,6 @@ static int i915_batchbuffer(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
drm_i915_batchbuffer_t batch;
@@ -668,21 +761,23 @@ static int i915_batchbuffer(DRM_IOCTL_ARGS)
DRM_COPYFROM_WITH_RETURN(&batch, (void *) data,
sizeof(batch));
- DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
- batch.start, batch.used, batch.num_cliprects);
- LOCK_TEST_WITH_RETURN(dev, fpriv);
- /*
+ DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d, counter %d\n",
+ batch.start, batch.used, batch.num_cliprects, dev_priv->counter);
+ LOCK_TEST_WITH_RETURN(dev, fpriv);
+
+/*
if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects,
batch.num_cliprects *
sizeof(drm_clip_rect_t)))
return (EFAULT);
- */
+*/
+
ret = i915_dispatch_batchbuffer(dev, &batch);
+ sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- sarea_priv->last_dispatch = (int)hw_status[5];
return ret;
}
@@ -691,7 +786,6 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
drm_i915_cmdbuffer_t cmdbuf;
@@ -719,8 +813,8 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects);
LOCK_TEST_WITH_RETURN(dev, fpriv);
- /*
-
+
+/*
if (cmdbuf.num_cliprects &&
DRM_VERIFYAREA_READ(cmdbuf.cliprects,
cmdbuf.num_cliprects *
@@ -728,7 +822,7 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
DRM_ERROR("Fault accessing cliprects\n");
return (EFAULT);
}
- */
+*/
ret = i915_dispatch_cmdbuffer(dev, &cmdbuf);
if (ret) {
@@ -736,31 +830,50 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
return ret;
}
- sarea_priv->last_dispatch = (int)hw_status[5];
+ sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
return 0;
}
-static int i915_do_cleanup_pageflip(drm_device_t * dev)
+static void i915_do_cleanup_pageflip(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
- DRM_DEBUG("%s\n", __FUNCTION__);
- if (dev_priv->current_page != 0)
- (void) i915_dispatch_flip(dev);
+ DRM_DEBUG("i915_do_cleanup_pageflip\n");
+
+ for (i = 0, planes = 0; i < 2; i++)
+ if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) {
+ dev_priv->sarea_priv->pf_current_page =
+ (dev_priv->sarea_priv->pf_current_page &
+ ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i));
+
+ planes |= 1 << i;
+ }
+
+ if (planes)
+ i915_dispatch_flip(dev, planes, 0);
- return 0;
}
/*ARGSUSED*/
static int i915_flip_bufs(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
+ drm_i915_flip_t param;
+ DRM_COPYFROM_WITH_RETURN(&param, (drm_i915_flip_t *) data,
+ sizeof(param));
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("i915_flip_bufs\n");
LOCK_TEST_WITH_RETURN(dev, fpriv);
-
- return i915_dispatch_flip(dev);
+ /* This is really planes */
+ if (param.pipes & ~0x3) {
+ DRM_ERROR("Invalid planes 0x%x, only <= 0x3 is valid\n",
+ param.pipes);
+ return -EINVAL;
+ }
+ i915_dispatch_flip(dev, param.pipes, 0);
+ return 0;
}
/*ARGSUSED*/
@@ -791,7 +904,7 @@ static int i915_getparam(DRM_IOCTL_ARGS)
switch (param.param) {
case I915_PARAM_IRQ_ACTIVE:
- value = dev->irq ? 1 : 0;
+ value = dev->irq_enabled ? 1 : 0;
break;
case I915_PARAM_ALLOW_BATCHBUFFER:
value = dev_priv->allow_batchbuffer ? 1 : 0;
@@ -799,6 +912,9 @@ static int i915_getparam(DRM_IOCTL_ARGS)
case I915_PARAM_LAST_DISPATCH:
value = READ_BREADCRUMB(dev_priv);
break;
+ case I915_PARAM_CHIPSET_ID:
+ value = dev->pci_device;
+ break;
default:
DRM_ERROR("Unknown parameter %d\n", param.param);
return (EINVAL);
@@ -828,7 +944,6 @@ static int i915_setparam(DRM_IOCTL_ARGS)
switch (param.param) {
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
- dev_priv->use_mi_batchbuffer_start = param.value;
break;
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
dev_priv->tex_lru_log_granularity = param.value;
@@ -867,8 +982,8 @@ static int i915_set_status_page(DRM_IOCTL_ARGS)
dev_priv->hws_map.offset =
(u_offset_t)dev->agp->agp_info.agpi_aperbase + hws.addr;
- dev_priv->hws_map.size = PAGE_SIZE; /* 4K pages */
- dev_priv->hws_map.type = _DRM_REGISTERS;
+ dev_priv->hws_map.size = 4 * 1024; /* 4K pages */
+ dev_priv->hws_map.type = 0;
dev_priv->hws_map.flags = 0;
dev_priv->hws_map.mtrr = 0;
@@ -886,7 +1001,7 @@ static int i915_set_status_page(DRM_IOCTL_ARGS)
dev_priv->hw_status_page = dev_priv->hws_map.dev_addr;
(void) memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
- I915_WRITE(0x02080, dev_priv->status_gfx_addr);
+ I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n",
dev_priv->status_gfx_addr);
DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
@@ -897,6 +1012,7 @@ static int i915_set_status_page(DRM_IOCTL_ARGS)
int i915_driver_load(drm_device_t *dev, unsigned long flags)
{
struct drm_i915_private *dev_priv;
+ int ret = 0;
/* i915 has 4 more counters */
dev->counters += 4;
@@ -911,14 +1027,27 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags)
(void) memset(dev_priv, 0, sizeof(drm_i915_private_t));
dev->dev_private = (void *)dev_priv;
+ dev_priv->dev = dev;
- return 0;
+ mutex_init(&dev_priv->swaps_lock, "swap", MUTEX_DRIVER, NULL);
+ mutex_init(&dev_priv->user_irq_lock, "userirq", MUTEX_DRIVER, NULL);
+
+ return ret;
}
int i915_driver_unload(struct drm_device *dev)
{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ i915_free_hardware_status(dev);
+
+ DRM_FINI_WAITQUEUE(&dev_priv->irq_queue);
+ mutex_destroy(&dev_priv->swaps_lock);
+ mutex_destroy(&dev_priv->user_irq_lock);
+
drm_free(dev->dev_private, sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
+ dev->dev_private = NULL;
return 0;
}
@@ -926,10 +1055,40 @@ int i915_driver_unload(struct drm_device *dev)
void i915_driver_lastclose(drm_device_t * dev)
{
- if (dev->dev_private) {
- drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ /* agp off can use this to get called before dev_priv */
+ if (!dev_priv)
+ return;
+
+#ifdef I915_HAVE_BUFFER
+ if (dev_priv->val_bufs) {
+ vfree(dev_priv->val_bufs);
+ dev_priv->val_bufs = NULL;
+ }
+#endif
+
+
+ DRM_GETSAREA();
+ if (dev_priv->sarea_priv)
+ i915_do_cleanup_pageflip(dev);
+ if (dev_priv->agp_heap)
i915_mem_takedown(&(dev_priv->agp_heap));
+#if defined(I915_HAVE_BUFFER)
+ if (dev_priv->sarea_kmap.virtual) {
+ drm_bo_kunmap(&dev_priv->sarea_kmap);
+ dev_priv->sarea_kmap.virtual = NULL;
+ dev->lock.hw_lock = NULL;
+ dev->sigdata.lock = NULL;
}
+
+ if (dev_priv->sarea_bo) {
+ mutex_lock(&dev->struct_mutex);
+ drm_bo_usage_deref_locked(&dev_priv->sarea_bo);
+ mutex_unlock(&dev->struct_mutex);
+ dev_priv->sarea_bo = NULL;
+ }
+#endif
(void) i915_dma_cleanup(dev);
}
@@ -937,9 +1096,6 @@ void i915_driver_preclose(drm_device_t * dev, drm_file_t *fpriv)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
- if (dev_priv->page_flipping) {
- (void) i915_do_cleanup_pageflip(dev);
- }
i915_mem_release(dev, fpriv, dev_priv->agp_heap);
}
}
@@ -971,6 +1127,12 @@ drm_ioctl_desc_t i915_ioctls[] = {
{i915_cmdbuffer, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] =
{i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] =
+ {i915_vblank_pipe_set, DRM_AUTH},
+ [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] =
+ {i915_vblank_pipe_get, DRM_AUTH},
+ [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] =
+ {i915_vblank_swap, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_HWS_ADDR)] =
{i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
};
@@ -993,3 +1155,13 @@ int i915_driver_device_is_agp(drm_device_t * dev)
{
return 1;
}
+
+/*ARGSUSED*/
+int i915_driver_firstopen(struct drm_device *dev)
+{
+#ifdef I915_HAVE_BUFFER
+ drm_bo_driver_init(dev);
+#endif
+ return 0;
+}
+
diff --git a/usr/src/uts/intel/io/drm/i915_drm.h b/usr/src/uts/intel/io/drm/i915_drm.h
index e56c9606ea..448e4534e6 100644
--- a/usr/src/uts/intel/io/drm/i915_drm.h
+++ b/usr/src/uts/intel/io/drm/i915_drm.h
@@ -27,15 +27,13 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _I915_DRM_H
#define _I915_DRM_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/* Please note that modifications to all structs defined here are
* subject to backwards-compatibility constraints.
*/
@@ -84,6 +82,7 @@ typedef struct _drm_i915_sarea {
int pf_current_page; /* which buffer is being displayed? */
int perf_boxes; /* performance boxes to be displayed */
int width, height; /* screen size in pixels */
+ int pad0;
drm_handle_t front_handle;
int front_offset;
@@ -114,14 +113,21 @@ typedef struct _drm_i915_sarea {
unsigned int rotated_tiled;
unsigned int rotated2_tiled;
- int pipeA_x;
- int pipeA_y;
- int pipeA_w;
- int pipeA_h;
- int pipeB_x;
- int pipeB_y;
- int pipeB_w;
- int pipeB_h;
+ int planeA_x;
+ int planeA_y;
+ int planeA_w;
+ int planeA_h;
+ int planeB_x;
+ int planeB_y;
+ int planeB_w;
+ int planeB_h;
+
+ /* Triple buffering */
+ drm_handle_t third_handle;
+ int third_offset;
+ int third_size;
+ unsigned int third_tiled;
+
} drm_i915_sarea_t;
/* Driver specific fence types and classes.
@@ -158,6 +164,9 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_INIT_HEAP 0x0a
#define DRM_I915_CMDBUFFER 0x0b
#define DRM_I915_DESTROY_HEAP 0x0c
+#define DRM_I915_SET_VBLANK_PIPE 0x0d
+#define DRM_I915_GET_VBLANK_PIPE 0x0e
+#define DRM_I915_VBLANK_SWAP 0x0f
#define DRM_I915_HWS_ADDR 0x11
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
@@ -173,6 +182,21 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t)
#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t)
#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
+#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
+#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
+#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
+
+/* Asynchronous page flipping:
+ */
+typedef struct drm_i915_flip {
+ /*
+ * This is really talking about planes, and we could rename it
+ * except for the fact that some of the duplicated i915_drm.h files
+ * out there check for HAVE_I915_FLIP and so might pick up this
+ * version.
+ */
+ int pipes;
+} drm_i915_flip_t;
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@@ -235,6 +259,7 @@ typedef struct drm_i915_irq_wait {
#define I915_PARAM_IRQ_ACTIVE 1
#define I915_PARAM_ALLOW_BATCHBUFFER 2
#define I915_PARAM_LAST_DISPATCH 3
+#define I915_PARAM_CHIPSET_ID 4
typedef struct drm_i915_getparam {
int param;
diff --git a/usr/src/uts/intel/io/drm/i915_drv.c b/usr/src/uts/intel/io/drm/i915_drv.c
index 2736423075..489d3c8e74 100644
--- a/usr/src/uts/intel/io/drm/i915_drv.c
+++ b/usr/src/uts/intel/io/drm/i915_drv.c
@@ -34,7 +34,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -641,7 +641,7 @@ i915_suspend(struct drm_device *dev)
s3_priv->saveDSPATILEOFF = S3_READ(DSPATILEOFF);
}
i915_save_palette(dev, PIPE_A);
- s3_priv->savePIPEASTAT = S3_READ(I915REG_PIPEASTAT);
+ s3_priv->savePIPEASTAT = S3_READ(PIPEASTAT);
/*
* Pipe & plane B info
@@ -671,7 +671,7 @@ i915_suspend(struct drm_device *dev)
s3_priv->saveDSPBTILEOFF = S3_READ(DSPBTILEOFF);
}
i915_save_palette(dev, PIPE_B);
- s3_priv->savePIPEBSTAT = S3_READ(I915REG_PIPEBSTAT);
+ s3_priv->savePIPEBSTAT = S3_READ(PIPEBSTAT);
/*
* CRT state
@@ -703,9 +703,9 @@ i915_suspend(struct drm_device *dev)
s3_priv->saveFBC_CONTROL = S3_READ(FBC_CONTROL);
/* Interrupt state */
- s3_priv->saveIIR = S3_READ(I915REG_INT_IDENTITY_R);
- s3_priv->saveIER = S3_READ(I915REG_INT_ENABLE_R);
- s3_priv->saveIMR = S3_READ(I915REG_INT_MASK_R);
+ s3_priv->saveIIR = S3_READ(IIR);
+ s3_priv->saveIER = S3_READ(IER);
+ s3_priv->saveIMR = S3_READ(IMR);
/* VGA state */
s3_priv->saveVCLK_DIVISOR_VGA0 = S3_READ(VCLK_DIVISOR_VGA0);
@@ -962,8 +962,9 @@ static void i915_configure(drm_driver_t *driver)
driver->preclose = i915_driver_preclose;
driver->lastclose = i915_driver_lastclose;
driver->device_is_agp = i915_driver_device_is_agp;
- driver->vblank_wait = i915_driver_vblank_wait;
- driver->vblank_wait2 = i915_driver_vblank_wait2;
+ driver->get_vblank_counter = i915_get_vblank_counter;
+ driver->enable_vblank = i915_enable_vblank;
+ driver->disable_vblank = i915_disable_vblank;
driver->irq_preinstall = i915_driver_irq_preinstall;
driver->irq_postinstall = i915_driver_irq_postinstall;
driver->irq_uninstall = i915_driver_irq_uninstall;
@@ -982,6 +983,4 @@ static void i915_configure(drm_driver_t *driver)
driver->use_agp = 1;
driver->require_agp = 1;
driver->use_irq = 1;
- driver->use_vbl_irq = 1;
- driver->use_vbl_irq2 = 1;
}
diff --git a/usr/src/uts/intel/io/drm/i915_drv.h b/usr/src/uts/intel/io/drm/i915_drv.h
index 10e7fc921b..88273a8cb2 100644
--- a/usr/src/uts/intel/io/drm/i915_drv.h
+++ b/usr/src/uts/intel/io/drm/i915_drv.h
@@ -30,7 +30,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -58,7 +58,7 @@
* 1.4: Fix cmdbuffer path, add heap destroy
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 4
+#define DRIVER_MINOR 5
#define DRIVER_PATCHLEVEL 0
#if defined(__linux__)
@@ -68,8 +68,6 @@
typedef struct _drm_i915_ring_buffer {
int tail_mask;
- unsigned long Start;
- unsigned long End;
unsigned long Size;
u8 *virtual_start;
int head;
@@ -89,8 +87,9 @@ struct mem_block {
typedef struct _drm_i915_vbl_swap {
struct list_head head;
drm_drawable_t drw_id;
- unsigned int pipe;
+ unsigned int plane;
unsigned int sequence;
+ int flip;
} drm_i915_vbl_swap_t;
typedef struct s3_i915_private {
@@ -187,6 +186,8 @@ typedef struct s3_i915_private {
} s3_i915_private_t;
typedef struct drm_i915_private {
+ struct drm_device *dev;
+
drm_local_map_t *sarea;
drm_local_map_t *mmio_map;
@@ -201,15 +202,9 @@ typedef struct drm_i915_private {
drm_local_map_t hws_map;
unsigned int cpp;
- int back_offset;
- int front_offset;
- int current_page;
- int page_flipping;
- int use_mi_batchbuffer_start;
wait_queue_head_t irq_queue;
atomic_t irq_received;
- atomic_t irq_emitted;
int tex_lru_log_granularity;
int allow_batchbuffer;
@@ -219,7 +214,7 @@ typedef struct drm_i915_private {
spinlock_t user_irq_lock;
int user_irq_refcount;
int fence_irq_on;
- uint32_t irq_enable_reg;
+ uint32_t irq_mask_reg;
int irq_enabled;
#ifdef I915_HAVE_FENCE
@@ -256,22 +251,31 @@ extern void i915_driver_preclose(drm_device_t * dev, drm_file_t *filp);
extern int i915_driver_device_is_agp(drm_device_t * dev);
extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
-extern int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush);
+extern int i915_emit_box(struct drm_device *dev,
+ struct drm_clip_rect __user *boxes,
+ int i, int DR1, int DR4);
+extern void i915_emit_breadcrumb(struct drm_device *dev);
+extern void i915_dispatch_flip(struct drm_device * dev, int pipes, int sync);
+extern void i915_emit_mi_flush(drm_device_t *dev, uint32_t flush);
/* i915_irq.c */
extern int i915_irq_emit(DRM_IOCTL_ARGS);
extern int i915_irq_wait(DRM_IOCTL_ARGS);
-extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
-extern int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence);
+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 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(drm_device_t * dev);
extern void i915_driver_irq_postinstall(drm_device_t * dev);
extern void i915_driver_irq_uninstall(drm_device_t * dev);
extern int i915_emit_irq(drm_device_t * dev);
+extern int i915_vblank_swap(DRM_IOCTL_ARGS);
extern void i915_user_irq_on(drm_i915_private_t *dev_priv);
extern void i915_user_irq_off(drm_i915_private_t *dev_priv);
+extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
+extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
/* i915_mem.c */
extern int i915_mem_alloc(DRM_IOCTL_ARGS);
@@ -321,10 +325,23 @@ extern int i915_move(drm_buffer_object_t *bo, int evict,
#define S3_WRITE(reg, val) \
*(uint32_t volatile *)((uintptr_t)s3_priv->saveAddr + (reg)) = (val)
+#define I915_VERBOSE 0
+#define I915_RING_VALIDATE 0
+
+#if I915_RING_VALIDATE
+void i915_ring_validate(struct drm_device *dev, const char *func, int line);
+#define I915_RING_DO_VALIDATE(dev) i915_ring_validate(dev, __FUNCTION__, __LINE__)
+#else
+#define I915_RING_DO_VALIDATE(dev)
+#endif
+
#define RING_LOCALS unsigned int outring, ringmask, outcount; \
volatile unsigned char *virt;
+#if I915_VERBOSE
#define BEGIN_LP_RING(n) do { \
+ DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \
+ I915_RING_DO_VALIDATE(dev); \
if (dev_priv->ring.space < (n)*4) \
(void) i915_wait_ring(dev, (n)*4, __FUNCTION__); \
outcount = 0; \
@@ -332,19 +349,51 @@ extern int i915_move(drm_buffer_object_t *bo, int evict,
ringmask = dev_priv->ring.tail_mask; \
virt = dev_priv->ring.virtual_start; \
} while (*"\0")
+#else
+#define BEGIN_LP_RING(n) do { \
+ I915_RING_DO_VALIDATE(dev); \
+ if (dev_priv->ring.space < (n)*4) \
+ (void) i915_wait_ring(dev, (n)*4, __FUNCTION__); \
+ outcount = 0; \
+ outring = dev_priv->ring.tail; \
+ ringmask = dev_priv->ring.tail_mask; \
+ virt = dev_priv->ring.virtual_start; \
+} while (*"\0")
+#endif
+#if I915_VERBOSE
+#define OUT_RING(n) do { \
+ DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
+ *(volatile unsigned int *)(void *)(virt + outring) = (n); \
+ outcount++; \
+ outring += 4; \
+ outring &= ringmask; \
+} while (*"\0")
+#else
#define OUT_RING(n) do { \
*(volatile unsigned int *)(void *)(virt + outring) = (n); \
outcount++; \
outring += 4; \
outring &= ringmask; \
} while (*"\0")
+#endif
+#if I915_VERBOSE
#define ADVANCE_LP_RING() do { \
+ DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \
+ I915_RING_DO_VALIDATE(dev); \
dev_priv->ring.tail = outring; \
dev_priv->ring.space -= outcount * 4; \
- I915_WRITE(LP_RING + RING_TAIL, outring); \
+ I915_WRITE(PRB0_TAIL, outring); \
} while (*"\0")
+#else
+#define ADVANCE_LP_RING() do { \
+ I915_RING_DO_VALIDATE(dev); \
+ dev_priv->ring.tail = outring; \
+ dev_priv->ring.space -= outcount * 4; \
+ I915_WRITE(PRB0_TAIL, outring); \
+} while (*"\0")
+#endif
extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
@@ -403,10 +452,14 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define INST_OP_FLUSH 0x02000000
#define INST_FLUSH_MAP_CACHE 0x00000001
-#define CMD_MI_FLUSH (0x04 << 23)
+#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags))
+#define MI_USER_INTERRUPT MI_INSTR(2, (0 << 29))
+#define MI_FLUSH (0x04 << 23)
#define MI_NO_WRITE_FLUSH (1 << 2)
#define MI_READ_FLUSH (1 << 0)
#define MI_EXE_FLUSH (1 << 1)
+#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1)
+#define MI_STORE_DWORD_INDEX_SHIFT 2
#define BB1_START_ADDR_MASK (~0x7)
#define BB1_PROTECTED (1<<0)
@@ -414,16 +467,18 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define BB2_END_ADDR_MASK (~0x7)
#define I915REG_PGTBL_CTRL 0x2020
-#define I915REG_HWSTAM 0x02098
-#define I915REG_INT_IDENTITY_R 0x020a4
-#define I915REG_INT_MASK_R 0x020a8
-#define I915REG_INT_ENABLE_R 0x020a0
-#define I915REG_INSTPM 0x020c0
-
-#define I915REG_PIPEASTAT 0x70024
-#define I915REG_PIPEBSTAT 0x71024
-
-#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
+#define HWSTAM 0x02098
+#define IIR 0x020a4
+#define IMR 0x020a8
+#define IER 0x020a0
+#define INSTPM 0x020c0
+#define ACTHD 0x020c8
+#define PIPEASTAT 0x70024
+#define PIPEBSTAT 0x71024
+#define ACTHD_I965 0x02074
+#define HWS_PGA 0x02080
+
+#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17)
#define I915_VBLANK_CLEAR (1UL<<1)
#define SRX_INDEX 0x3c4
@@ -454,9 +509,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define NOPID 0x2094
#define LP_RING 0x2030
#define HP_RING 0x2040
-#define RING_TAIL 0x00
#define TAIL_ADDR 0x001FFFF8
-#define RING_HEAD 0x04
#define HEAD_WRAP_COUNT 0xFFE00000
#define HEAD_WRAP_ONE 0x00200000
#define HEAD_ADDR 0x001FFFFC
@@ -471,7 +524,9 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define RING_VALID_MASK 0x00000001
#define RING_VALID 0x00000001
#define RING_INVALID 0x00000000
-
+#define PRB0_TAIL 0x02030
+#define PRB0_HEAD 0x02034
+#define PRB0_CTL 0x0203c
#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19))
#define SC_UPDATE_SCISSOR (0x1<<1)
#define SC_ENABLE_MASK (0x1<<0)
@@ -497,13 +552,18 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
+#define XY_SRC_COPY_BLT_SRC_TILED (1<<15)
+#define XY_SRC_COPY_BLT_DST_TILED (1<<11)
#define MI_BATCH_BUFFER ((0x30<<23)|1)
#define MI_BATCH_BUFFER_START (0x31<<23)
#define MI_BATCH_BUFFER_END (0xA<<23)
#define MI_BATCH_NON_SECURE (1)
+#define MI_BATCH_NON_SECURE_I965 (1<<8)
+
#define MI_WAIT_FOR_EVENT ((0x3<<23))
+#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6)
#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2)
#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
@@ -511,11 +571,15 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
#define ASYNC_FLIP (1<<22)
+#define DISPLAY_PLANE_A (0<<20)
+#define DISPLAY_PLANE_B (1<<20)
#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
-#define BREADCRUMB_OFFSET 32 /* dword offset 20h */
-#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[BREADCRUMB_OFFSET])
+#define BREADCRUMB_BITS 31
+#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1)
+
+#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5])
#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg])
/*
@@ -731,7 +795,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define DSPBTILEOFF 0x711A4
#define PIPEACONF 0x70008
-#define PIPEACONF_ENABLE (1<<31)
+#define PIPEACONF_ENABLE (1UL<<31)
#define PIPEACONF_DISABLE 0
#define PIPEACONF_DOUBLE_WIDE (1<<30)
#define I965_PIPECONF_ACTIVE (1<<30)
@@ -746,7 +810,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
#define PIPEBCONF 0x71008
-#define PIPEBCONF_ENABLE (1<<31)
+#define PIPEBCONF_ENABLE (1UL<<31)
#define PIPEBCONF_DISABLE 0
#define PIPEBCONF_DOUBLE_WIDE (1<<30)
#define PIPEBCONF_DISABLE 0
@@ -820,6 +884,61 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define DSPARB 0x70030
+#define PIPEAFRAMEHIGH 0x70040
+#define PIPEBFRAMEHIGH 0x71040
+#define PIPE_FRAME_HIGH_MASK 0x0000ffff
+#define PIPE_FRAME_HIGH_SHIFT 0
+#define PIPEAFRAMEPIXEL 0x70044
+#define PIPEBFRAMEPIXEL 0x71044
+
+#define PIPE_FRAME_LOW_MASK 0xff000000
+#define PIPE_FRAME_LOW_SHIFT 24
+
+/* Interrupt bits:
+ */
+#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
+#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
+#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
+#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14)
+#define I915_HWB_OOM_INTERRUPT (1<<13) /* binner out of memory */
+#define I915_SYNC_STATUS_INTERRUPT (1<<12)
+#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11)
+#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10)
+#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9)
+#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8)
+#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7)
+#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6)
+#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5)
+#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4)
+#define I915_DEBUG_INTERRUPT (1<<2)
+#define I915_USER_INTERRUPT (1<<1)
+
+#define I915_FIFO_UNDERRUN_STATUS (1UL<<31)
+#define I915_CRC_ERROR_ENABLE (1UL<<29)
+#define I915_CRC_DONE_ENABLE (1UL<<28)
+#define I915_GMBUS_EVENT_ENABLE (1UL<<27)
+#define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25)
+#define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24)
+#define I915_DPST_EVENT_ENABLE (1UL<<23)
+#define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22)
+#define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21)
+#define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20)
+#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */
+#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
+#define I915_OVERLAY_UPDATED_ENABLE (1UL<<16)
+#define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13)
+#define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12)
+#define I915_GMBUS_INTERRUPT_STATUS (1UL<<11)
+#define I915_VSYNC_INTERRUPT_STATUS (1UL<<9)
+#define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8)
+#define I915_DPST_EVENT_STATUS (1UL<<7)
+#define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6)
+#define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5)
+#define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4)
+#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
+#define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1)
+#define I915_OVERLAY_UPDATED_STATUS (1UL<<0)
+
/*
* Some BIOS scratch area registers. The 845 (and 830?) store the amount
* of video memory available to the BIOS in SWF1.
@@ -856,6 +975,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define PCI_DEVICE_ID_INTEL_EL_IG 0x2e02
#define PCI_DEVICE_ID_INTEL_82Q45_IG 0x2e12
#define PCI_DEVICE_ID_INTEL_82G45_IG 0x2e22
+#define PCI_DEVICE_ID_INTEL_82G41_IG 0x2e32
#define IS_I830(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82830_CGC)
@@ -879,7 +999,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
(dev)->pci_device == PCI_DEVICE_ID_INTEL_CANTIGA_IG || \
(dev)->pci_device == PCI_DEVICE_ID_INTEL_EL_IG || \
(dev)->pci_device == PCI_DEVICE_ID_INTEL_82Q45_IG || \
- (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G45_IG)
+ (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G45_IG || \
+ (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G41_IG)
#define IS_I965GM(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_GM965_IG)
@@ -887,7 +1008,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define IS_G4X(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_EL_IG || \
(dev)->pci_device == PCI_DEVICE_ID_INTEL_82Q45_IG || \
- (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G45_IG)
+ (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G45_IG || \
+ (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G41_IG)
#define IS_G33(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82G33_IG || \
(dev)->pci_device == PCI_DEVICE_ID_INTEL_82Q35_IG || \
diff --git a/usr/src/uts/intel/io/drm/i915_irq.c b/usr/src/uts/intel/io/drm/i915_irq.c
index dd5c141c59..a8e44ca953 100644
--- a/usr/src/uts/intel/io/drm/i915_irq.c
+++ b/usr/src/uts/intel/io/drm/i915_irq.c
@@ -29,7 +29,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -38,12 +38,140 @@
#include "i915_drm.h"
#include "i915_drv.h"
-#define USER_INT_FLAG (1<<1)
-#define VSYNC_PIPEB_FLAG (1<<5)
-#define VSYNC_PIPEA_FLAG (1<<7)
#define MAX_NOPID ((u32)~0)
+/*
+ * These are the interrupts used by the driver
+ */
+#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
+
+static inline void
+i915_enable_irq(drm_i915_private_t *dev_priv, uint32_t mask)
+{
+ if ((dev_priv->irq_mask_reg & mask) != 0) {
+ dev_priv->irq_mask_reg &= ~mask;
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IMR);
+ }
+}
+
+static inline void
+i915_disable_irq(drm_i915_private_t *dev_priv, uint32_t mask)
+{
+ if ((dev_priv->irq_mask_reg & mask) != mask) {
+ dev_priv->irq_mask_reg |= mask;
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IMR);
+ }
+}
+ /**
+ * i915_get_pipe - return the the pipe associated with a given plane
+ * @dev: DRM device
+ * @plane: plane to look for
+ *
+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number
+ * rather than a pipe number, since they may not always be equal. This routine
+ * maps the given @plane back to a pipe number.
+ */
+static int
+i915_get_pipe(struct drm_device *dev, int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 dspcntr;
+
+ dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR);
+
+ return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0;
+}
+
+/**
+ * i915_get_plane - return the the plane associated with a given pipe
+ * @dev: DRM device
+ * @pipe: pipe to look for
+ *
+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number
+ * rather than a plane number, since they may not always be equal. This routine
+ * maps the given @pipe back to a plane number.
+ */
+static int
+i915_get_plane(struct drm_device *dev, int pipe)
+{
+ if (i915_get_pipe(dev, 0) == pipe)
+ return 0;
+ return 1;
+}
+
+/**
+ * i915_pipe_enabled - check if a pipe is enabled
+ * @dev: DRM device
+ * @pipe: pipe to check
+ *
+ * Reading certain registers when the pipe is disabled can hang the chip.
+ * Use this routine to make sure the PLL is running and the pipe is active
+ * before reading such registers if unsure.
+ */
+static int
+i915_pipe_enabled(struct drm_device *dev, int pipe)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
+
+ if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Emit a synchronous flip.
+ *
+ * This function must be called with the drawable spinlock held.
+ */
+static void
+i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw,
+ int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ u16 x1, y1, x2, y2;
+ int pf_planes = 1 << plane;
+
+ DRM_SPINLOCK_ASSERT(&dev->drw_lock);
+
+ /* If the window is visible on the other plane, we have to flip on that
+ * plane as well.
+ */
+ if (plane == 1) {
+ x1 = sarea_priv->planeA_x;
+ y1 = sarea_priv->planeA_y;
+ x2 = x1 + sarea_priv->planeA_w;
+ y2 = y1 + sarea_priv->planeA_h;
+ } else {
+ x1 = sarea_priv->planeB_x;
+ y1 = sarea_priv->planeB_y;
+ x2 = x1 + sarea_priv->planeB_w;
+ y2 = y1 + sarea_priv->planeB_h;
+ }
+
+ if (x2 > 0 && y2 > 0) {
+ int i, num_rects = drw->num_rects;
+ struct drm_clip_rect *rect = drw->rects;
+
+ for (i = 0; i < num_rects; i++)
+ if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 ||
+ rect[i].x2 <= x1 || rect[i].y2 <= y1)) {
+ pf_planes = 0x3;
+
+ break;
+ }
+ }
+
+ i915_dispatch_flip(dev, pf_planes, 1);
+}
+
/**
* Emit blits for scheduled buffer swaps.
*
@@ -52,57 +180,74 @@
static void i915_vblank_tasklet(drm_device_t *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- /* LINTED E_FUNC_VAR_UNUSED */
- unsigned long irqflags;
struct list_head *list, *tmp, hits, *hit;
- int nhits, slice[2], upper[2], lower[2], i;
- unsigned counter[2] = { atomic_read(&dev->vbl_received),
- atomic_read(&dev->vbl_received2) };
- drm_drawable_info_t *drw;
+ int nhits, slice[2], upper[2], lower[2], i, num_pages;
+ unsigned counter[2];
+ struct drm_drawable_info *drw;
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
- u32 cpp = dev_priv->cpp;
+ u32 cpp = dev_priv->cpp, offsets[3];
u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
XY_SRC_COPY_BLT_WRITE_ALPHA |
XY_SRC_COPY_BLT_WRITE_RGB)
: XY_SRC_COPY_BLT_CMD;
- u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) |
- (cpp << 23) | (1 << 24);
+ u32 src_pitch = sarea_priv->pitch * cpp;
+ u32 dst_pitch = sarea_priv->pitch * cpp;
+ /* COPY rop (0xcc), map cpp to magic color depth constants */
+ u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24);
RING_LOCALS;
-
- DRM_DEBUG("%s\n", __FUNCTION__);
+
+ if (IS_I965G(dev) && sarea_priv->front_tiled) {
+ cmd |= XY_SRC_COPY_BLT_DST_TILED;
+ dst_pitch >>= 2;
+ }
+ if (IS_I965G(dev) && sarea_priv->back_tiled) {
+ cmd |= XY_SRC_COPY_BLT_SRC_TILED;
+ src_pitch >>= 2;
+ }
+
+ counter[0] = drm_vblank_count(dev, 0);
+ counter[1] = drm_vblank_count(dev, 1);
INIT_LIST_HEAD(&hits);
nhits = 0;
- spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ /* No irqsave/restore necessary. This tasklet may be run in an
+ * interrupt context or normal context, but we don't have to worry
+ * about getting interrupted by something acquiring the lock, because
+ * we are the interrupt context thing that acquires the lock.
+ */
+ DRM_SPINLOCK(&dev_priv->swaps_lock);
/* Find buffer swaps scheduled for this vertical blank */
list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
drm_i915_vbl_swap_t *vbl_swap =
list_entry(list, drm_i915_vbl_swap_t, head);
+ int pipe = i915_get_pipe(dev, vbl_swap->plane);
- if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
+ if ((counter[pipe] - vbl_swap->sequence) > (1<<23))
continue;
list_del(list);
dev_priv->swaps_pending--;
+ drm_vblank_put(dev, pipe);
- spin_unlock(&dev_priv->swaps_lock);
- spin_lock(&dev->drw_lock);
+ DRM_SPINUNLOCK(&dev_priv->swaps_lock);
+ DRM_SPINLOCK(&dev->drw_lock);
drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
if (!drw) {
- spin_unlock(&dev->drw_lock);
+ DRM_SPINUNLOCK(&dev->drw_lock);
drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
- spin_lock(&dev_priv->swaps_lock);
+ DRM_SPINLOCK(&dev_priv->swaps_lock);
continue;
}
list_for_each(hit, &hits) {
drm_i915_vbl_swap_t *swap_cmp =
list_entry(hit, drm_i915_vbl_swap_t, head);
- drm_drawable_info_t *drw_cmp =
+ struct drm_drawable_info *drw_cmp =
drm_get_drawable_info(dev, swap_cmp->drw_id);
if (drw_cmp &&
@@ -112,7 +257,7 @@ static void i915_vblank_tasklet(drm_device_t *dev)
}
}
- spin_unlock(&dev->drw_lock);
+ DRM_SPINUNLOCK(&dev->drw_lock);
/* List of hits was empty, or we reached the end of it */
if (hit == &hits)
@@ -120,38 +265,29 @@ static void i915_vblank_tasklet(drm_device_t *dev)
nhits++;
- spin_lock(&dev_priv->swaps_lock);
+ DRM_SPINLOCK(&dev_priv->swaps_lock);
}
+ DRM_SPINUNLOCK(&dev_priv->swaps_lock);
+
if (nhits == 0) {
- spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
return;
}
- spin_unlock(&dev_priv->swaps_lock);
-
i915_kernel_lost_context(dev);
- BEGIN_LP_RING(6);
-
- OUT_RING(GFX_OP_DRAWRECT_INFO);
- OUT_RING(0);
- OUT_RING(0);
- OUT_RING(sarea_priv->width | sarea_priv->height << 16);
- OUT_RING(sarea_priv->width | sarea_priv->height << 16);
- OUT_RING(0);
-
- ADVANCE_LP_RING();
-
- sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
-
upper[0] = upper[1] = 0;
- slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
- slice[1] = max(sarea_priv->pipeB_h / nhits, 1);
- lower[0] = sarea_priv->pipeA_y + slice[0];
- lower[1] = sarea_priv->pipeB_y + slice[0];
+ slice[0] = max(sarea_priv->planeA_h / nhits, 1);
+ slice[1] = max(sarea_priv->planeB_h / nhits, 1);
+ lower[0] = sarea_priv->planeA_y + slice[0];
+ lower[1] = sarea_priv->planeB_y + slice[0];
+
+ offsets[0] = sarea_priv->front_offset;
+ offsets[1] = sarea_priv->back_offset;
+ offsets[2] = sarea_priv->third_offset;
+ num_pages = sarea_priv->third_handle ? 3 : 2;
- spin_lock(&dev->drw_lock);
+ DRM_SPINLOCK(&dev->drw_lock);
/* Emit blits for buffer swaps, partitioning both outputs into as many
* slices as there are buffer swaps scheduled in order to avoid tearing
@@ -161,14 +297,16 @@ static void i915_vblank_tasklet(drm_device_t *dev)
for (i = 0; i++ < nhits;
upper[0] = lower[0], lower[0] += slice[0],
upper[1] = lower[1], lower[1] += slice[1]) {
+ int init_drawrect = 1;
+
if (i == nhits)
lower[0] = lower[1] = sarea_priv->height;
list_for_each(hit, &hits) {
drm_i915_vbl_swap_t *swap_hit =
list_entry(hit, drm_i915_vbl_swap_t, head);
- drm_clip_rect_t *rect;
- int num_rects, pipe;
+ struct drm_clip_rect *rect;
+ int num_rects, plane, front, back;
unsigned short top, bottom;
drw = drm_get_drawable_info(dev, swap_hit->drw_id);
@@ -176,10 +314,46 @@ static void i915_vblank_tasklet(drm_device_t *dev)
if (!drw)
continue;
+ plane = swap_hit->plane;
+
+ if (swap_hit->flip) {
+ i915_dispatch_vsync_flip(dev, drw, plane);
+ continue;
+ }
+
+ if (init_drawrect) {
+ int width = sarea_priv->width;
+ int height = sarea_priv->height;
+ if (IS_I965G(dev)) {
+ BEGIN_LP_RING(4);
+ OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
+ OUT_RING(0);
+ OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16));
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ } else {
+ BEGIN_LP_RING(6);
+ OUT_RING(GFX_OP_DRAWRECT_INFO);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16));
+ OUT_RING(0);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ }
+
+ sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
+
+ init_drawrect = 0;
+ }
+
rect = drw->rects;
- pipe = swap_hit->pipe;
- top = upper[pipe];
- bottom = lower[pipe];
+ top = upper[plane];
+ bottom = lower[plane];
+
+ front = (dev_priv->sarea_priv->pf_current_page >>
+ (2 * plane)) & 0x3;
+ back = (front + 1) % num_pages;
for (num_rects = drw->num_rects; num_rects--; rect++) {
int y1 = max(rect->y1, top);
@@ -189,22 +363,20 @@ static void i915_vblank_tasklet(drm_device_t *dev)
continue;
BEGIN_LP_RING(8);
-
OUT_RING(cmd);
- OUT_RING(pitchropcpp);
+ OUT_RING(ropcpp | dst_pitch);
OUT_RING((y1 << 16) | rect->x1);
OUT_RING((y2 << 16) | rect->x2);
- OUT_RING(sarea_priv->front_offset);
+ OUT_RING(offsets[front]);
OUT_RING((y1 << 16) | rect->x1);
- OUT_RING(pitchropcpp & 0xffff);
- OUT_RING(sarea_priv->back_offset);
-
+ OUT_RING(src_pitch);
+ OUT_RING(offsets[back]);
ADVANCE_LP_RING();
}
}
}
- spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ DRM_SPINUNLOCK(&dev->drw_lock);
list_for_each_safe(hit, tmp, &hits) {
drm_i915_vbl_swap_t *swap_hit =
@@ -216,66 +388,119 @@ static void i915_vblank_tasklet(drm_device_t *dev)
}
}
-irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
+u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
{
- drm_device_t *dev = (drm_device_t *) (void *)arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 temp;
- u32 pipea_stats, pipeb_stats;
+ unsigned long high_frame;
+ unsigned long low_frame;
+ u32 high1, high2, low, count;
+ int pipe;
+
+ pipe = i915_get_pipe(dev, plane);
+ high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+ low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
+ if (!i915_pipe_enabled(dev, pipe)) {
+ DRM_DEBUG("trying to get vblank count for disabled pipe %d\n", pipe);
+ return 0;
+ }
- pipea_stats = I915_READ(I915REG_PIPEASTAT);
- pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
-
- temp = I915_READ16(I915REG_INT_IDENTITY_R);
- temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG);
+ /*
+ * High & low register fields aren't synchronized, so make sure
+ * we get a low value that's stable across two reads of the high
+ * register.
+ */
+ do {
+ high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+ PIPE_FRAME_HIGH_SHIFT);
+ low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
+ PIPE_FRAME_LOW_SHIFT);
+ high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+ PIPE_FRAME_HIGH_SHIFT);
+ } while (high1 != high2);
+
+ count = (high1 << 8) | low;
+
+ /* count may be reset by other driver(e.g. 2D driver),
+ we have no way to know if it is wrapped or resetted
+ when count is zero. do a rough guess.
+ */
+ if (count < dev->last_vblank[pipe] && dev->last_vblank[pipe] < dev->max_vblank_count/2)
+ dev->last_vblank[pipe]=0;
+ return count;
+}
-#if 0
- DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
-#endif
- if (temp == 0)
- return IRQ_NONE;
+irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
+{
+ drm_device_t *dev = (drm_device_t *) (void *) arg;
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 iir;
+ u32 pipea_stats = 0, pipeb_stats = 0;
+ int vblank = 0;
+ iir = I915_READ(IIR);
+
+ atomic_inc(&dev_priv->irq_received);
- I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+ if (iir == 0) {
+ return IRQ_NONE;
+ }
- dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+ if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
+ pipea_stats = I915_READ(PIPEASTAT);
+
+ /* The vblank interrupt gets enabled even if we didn't ask for
+ it, so make sure it's shut down again */
+ if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A))
+ pipea_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+ PIPE_VBLANK_INTERRUPT_ENABLE);
+ else if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+ PIPE_VBLANK_INTERRUPT_STATUS))
+ {
+ vblank++;
+ drm_handle_vblank(dev, i915_get_plane(dev, 0));
+ }
- if (temp & USER_INT_FLAG) {
- DRM_WAKEUP(&dev_priv->irq_queue);
-#ifdef I915_HAVE_FENCE
- i915_fence_handler(dev);
-#endif
+ I915_WRITE(PIPEASTAT, pipea_stats);
}
+ if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
+ pipeb_stats = I915_READ(PIPEBSTAT);
+
+ /* The vblank interrupt gets enabled even if we didn't ask for
+ it, so make sure it's shut down again */
+ if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B))
+ pipeb_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+ PIPE_VBLANK_INTERRUPT_ENABLE);
+ else if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+ PIPE_VBLANK_INTERRUPT_STATUS))
+ {
+ vblank++;
+ drm_handle_vblank(dev, i915_get_plane(dev, 1));
+ }
+
+ I915_WRITE(PIPEBSTAT, pipeb_stats);
+ }
+
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
- int vblank_pipe = dev_priv->vblank_pipe;
+ I915_WRITE(IIR, iir);
- if ((vblank_pipe &
- (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
- == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
- if (temp & VSYNC_PIPEA_FLAG)
- atomic_inc(&dev->vbl_received);
- if (temp & VSYNC_PIPEB_FLAG)
- atomic_inc(&dev->vbl_received2);
- } else if (((temp & VSYNC_PIPEA_FLAG) &&
- (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
- ((temp & VSYNC_PIPEB_FLAG) &&
- (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
- atomic_inc(&dev->vbl_received);
+ (void) I915_READ(IIR); /* Flush posted writes */
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ if (iir & I915_USER_INTERRUPT) {
+ DRM_WAKEUP(&dev_priv->irq_queue);
+#ifdef I915_HAVE_FENCE
+ i915_fence_handler(dev);
+#endif
+ }
+ if (vblank) {
if (dev_priv->swaps_pending > 0)
drm_locked_tasklet(dev, i915_vblank_tasklet);
- I915_WRITE(I915REG_PIPEASTAT,
- pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
- I915_VBLANK_CLEAR);
- I915_WRITE(I915REG_PIPEBSTAT,
- pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
- I915_VBLANK_CLEAR);
}
return IRQ_HANDLED;
+
}
int i915_emit_irq(drm_device_t * dev)
@@ -286,34 +511,21 @@ int i915_emit_irq(drm_device_t * dev)
i915_kernel_lost_context(dev);
- DRM_DEBUG("%s\n", __FUNCTION__);
-
- dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
-
- if (dev_priv->counter > 0x7FFFFFFFUL)
- dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
-
- BEGIN_LP_RING(6);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(BREADCRUMB_OFFSET << 2);
- OUT_RING(dev_priv->counter);
+ i915_emit_breadcrumb(dev);
+ BEGIN_LP_RING(2);
OUT_RING(0);
- OUT_RING(0);
- OUT_RING(GFX_OP_USER_INTERRUPT);
+ OUT_RING(MI_USER_INTERRUPT);
ADVANCE_LP_RING();
return dev_priv->counter;
-
-
}
void i915_user_irq_on(drm_i915_private_t *dev_priv)
{
spin_lock(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){
- dev_priv->irq_enable_reg |= USER_INT_FLAG;
- I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
}
spin_unlock(&dev_priv->user_irq_lock);
@@ -323,9 +535,7 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv)
{
spin_lock(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
- /*EMPTY*/;
- // dev_priv->irq_enable_reg &= ~USER_INT_FLAG;
- // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
}
spin_unlock(&dev_priv->user_irq_lock);
}
@@ -336,59 +546,41 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = 0;
- DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr,
- READ_BREADCRUMB(dev_priv));
- if (READ_BREADCRUMB(dev_priv) >= irq_nr)
- return 0;
- dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+ if (!dev_priv) {
+ DRM_ERROR("called with no initialization\n");
+ return -EINVAL;
+ }
+
+
+
+
+ if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_dispatch =
+ READ_BREADCRUMB(dev_priv);
+ return 0;
+ }
+ DRM_DEBUG("i915_wait_irq: irq_nr=%d breadcrumb=%d\n", irq_nr, READ_BREADCRUMB(dev_priv));
i915_user_irq_on(dev_priv);
DRM_WAIT_ON(ret, &dev_priv->irq_queue, 3 * DRM_HZ,
READ_BREADCRUMB(dev_priv) >= irq_nr);
i915_user_irq_off(dev_priv);
- if (ret == EBUSY) {
- DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
- __FUNCTION__,
+ if (ret == EBUSY || ret == EINTR) {
+ DRM_DEBUG("%d: EBUSY -- rec: %d emitted: %d\n",
+ ret,
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
}
- dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- return ret;
-}
-
-static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence,
- atomic_t *counter)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- unsigned int cur_vblank;
- int ret = 0;
-
- if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return (EINVAL);
- }
-
- DRM_WAIT_ON(ret, &dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(counter))
- - *sequence) <= (1<<23)));
-
- *sequence = cur_vblank;
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
return ret;
}
-int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
-{
- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
-}
-
-int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence)
-{
- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
-}
/* Needs the lock as it touches the ring.
*/
@@ -448,77 +640,365 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
return i915_wait_irq(dev, irqwait.irq_seq);
}
+int i915_enable_vblank(struct drm_device *dev, int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe = i915_get_pipe(dev, plane);
+ u32 pipestat_reg = 0;
+ u32 mask_reg = 0;
+ u32 pipestat;
+
+ switch (pipe) {
+ case 0:
+ pipestat_reg = PIPEASTAT;
+ mask_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+ break;
+ case 1:
+ pipestat_reg = PIPEBSTAT;
+ mask_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+ break;
+ default:
+ DRM_ERROR("tried to enable vblank on non-existent pipe %d\n",
+ pipe);
+ break;
+ }
+
+ if (pipestat_reg)
+ {
+ pipestat = I915_READ (pipestat_reg);
+ /*
+ * Older chips didn't have the start vblank interrupt,
+ * but
+ */
+ if (IS_I965G (dev))
+ pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE;
+ else
+ pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE;
+ /*
+ * Clear any pending status
+ */
+ pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
+ PIPE_VBLANK_INTERRUPT_STATUS);
+ I915_WRITE(pipestat_reg, pipestat);
+ }
+ DRM_SPINLOCK(&dev_priv->user_irq_lock);
+ i915_enable_irq(dev_priv, mask_reg);
+ DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
+
+ return 0;
+}
+
+void i915_disable_vblank(struct drm_device *dev, int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe = i915_get_pipe(dev, plane);
+ u32 pipestat_reg = 0;
+ u32 mask_reg = 0;
+ u32 pipestat;
+
+ switch (pipe) {
+ case 0:
+ pipestat_reg = PIPEASTAT;
+ mask_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+ break;
+ case 1:
+ pipestat_reg = PIPEBSTAT;
+ mask_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+ break;
+ default:
+ DRM_ERROR("tried to disable vblank on non-existent pipe %d\n",
+ pipe);
+ break;
+ }
+
+ DRM_SPINLOCK(&dev_priv->user_irq_lock);
+ i915_disable_irq(dev_priv, mask_reg);
+ DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
+
+ if (pipestat_reg)
+ {
+ pipestat = I915_READ (pipestat_reg);
+ pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+ PIPE_VBLANK_INTERRUPT_ENABLE);
+ /*
+ * Clear any pending status
+ */
+ pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
+ PIPE_VBLANK_INTERRUPT_STATUS);
+ I915_WRITE(pipestat_reg, pipestat);
+ (void) I915_READ(pipestat_reg);
+ }
+}
+
+
static void i915_enable_interrupt (drm_device_t *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-
- dev_priv->irq_enable_reg = USER_INT_FLAG;
- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
- dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG;
- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
- dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG;
- I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ dev_priv->irq_mask_reg = 0xffffffff;
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
+ (void) I915_READ (IER);
+
dev_priv->irq_enabled = 1;
}
+/* Set the vblank monitor pipe
+ */
+/*ARGSUSED*/
+int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ if (!dev_priv) {
+ DRM_ERROR("called with no initialization\n");
+ return (-EINVAL);
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_vblank_pipe_t pipe;
+
+ if (!dev_priv) {
+ DRM_ERROR("called with no initialization\n");
+ return -EINVAL;
+ }
+
+
+ DRM_COPYFROM_WITH_RETURN(&pipe, (drm_i915_vblank_pipe_t __user *)data, sizeof (pipe));
+
+ pipe.pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
+
+ return 0;
+}
+
+/**
+ * Schedule buffer swap at given vertical blank.
+ */
+/*ARGSUSED*/
+int i915_vblank_swap(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_vblank_swap_t *swap;
+ drm_i915_vbl_swap_t *vbl_swap;
+ unsigned int pipe, seqtype, curseq, plane;
+ struct list_head *list;
+ int ret;
+
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) {
+ DRM_DEBUG("Rotation not supported\n");
+ return -EINVAL;
+ }
+
+ DRM_COPYFROM_WITH_RETURN(&swap, (drm_i915_vblank_swap_t __user *)data, sizeof (swap));
+
+ if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
+ _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS |
+ _DRM_VBLANK_FLIP)) {
+ DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype);
+ return -EINVAL;
+ }
+
+ plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+ pipe = i915_get_pipe(dev, plane);
+
+ seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
+
+ if (!(dev_priv->vblank_pipe & (1 << pipe))) {
+ DRM_ERROR("Invalid pipe %d\n", pipe);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ /* It makes no sense to schedule a swap for a drawable that doesn't have
+ * valid information at this point. E.g. this could mean that the X
+ * server is too old to push drawable information to the DRM, in which
+ * case all such swaps would become ineffective.
+ */
+ if (!drm_get_drawable_info(dev, swap->drawable)) {
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
+ return -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ /*
+ * We take the ref here and put it when the swap actually completes
+ * in the tasklet.
+ */
+ ret = drm_vblank_get(dev, pipe);
+ if (ret)
+ return ret;
+ curseq = drm_vblank_count(dev, pipe);
+
+ if (seqtype == _DRM_VBLANK_RELATIVE)
+ swap->sequence += curseq;
+
+ if ((curseq - swap->sequence) <= (1<<23)) {
+ if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) {
+ swap->sequence = curseq + 1;
+ } else {
+ DRM_DEBUG("Missed target sequence\n");
+ drm_vblank_put(dev, pipe);
+ return -EINVAL;
+ }
+ }
+
+ if (swap->seqtype & _DRM_VBLANK_FLIP) {
+ swap->sequence--;
+
+ if ((curseq - swap->sequence) <= (1<<23)) {
+ struct drm_drawable_info *drw;
+
+ LOCK_TEST_WITH_RETURN(dev, fpriv);
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ drw = drm_get_drawable_info(dev, swap->drawable);
+
+ if (!drw) {
+ spin_unlock_irqrestore(&dev->drw_lock,
+ irqflags);
+ DRM_DEBUG("Invalid drawable ID %d\n",
+ swap->drawable);
+ drm_vblank_put(dev, pipe);
+ return -EINVAL;
+ }
+
+ i915_dispatch_vsync_flip(dev, drw, plane);
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ drm_vblank_put(dev, pipe);
+ return 0;
+ }
+ }
+
+ spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ list_for_each(list, &dev_priv->vbl_swaps.head) {
+ vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
+
+ if (vbl_swap->drw_id == swap->drawable &&
+ vbl_swap->plane == plane &&
+ vbl_swap->sequence == swap->sequence) {
+ vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP);
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+ DRM_DEBUG("Already scheduled\n");
+ return 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+ if (dev_priv->swaps_pending >= 100) {
+ DRM_DEBUG("Too many swaps queued\n");
+ drm_vblank_put(dev, pipe);
+ return -EBUSY;
+ }
+
+ vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
+
+ if (!vbl_swap) {
+ DRM_ERROR("Failed to allocate memory to queue swap\n");
+ drm_vblank_put(dev, pipe);
+ return -ENOMEM;
+ }
+
+ DRM_DEBUG("vbl_swap\n");
+
+ vbl_swap->drw_id = swap->drawable;
+ vbl_swap->plane = plane;
+ vbl_swap->sequence = swap->sequence;
+ vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP);
+
+ if (vbl_swap->flip)
+ swap->sequence++;
+
+ spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head);
+ dev_priv->swaps_pending++;
+
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+ return 0;
+}
+
/* drm_dma.h hooks
*/
void i915_driver_irq_preinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- I915_WRITE16(I915REG_HWSTAM, 0xeffe);
- I915_WRITE16(I915REG_INT_MASK_R, 0x0);
- I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+ I915_WRITE(HWSTAM, 0xeffe);
+ I915_WRITE(IMR, 0xffffffff);
+ I915_WRITE(IER, 0x0);
}
void i915_driver_irq_postinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int ret, num_pipes=2;
- mutex_init(&dev_priv->swaps_lock, NULL, MUTEX_DRIVER, NULL);
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
dev_priv->swaps_pending = 0;
- if (!dev_priv->vblank_pipe)
- dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
-
- mutex_init(&dev_priv->user_irq_lock, NULL, MUTEX_DRIVER, NULL);
dev_priv->user_irq_refcount = 0;
+ dev_priv->irq_mask_reg = 0xffffffff;
- if (!dev_priv->vblank_pipe)
- dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
-
- DRM_INIT_WAITQUEUE(&dev_priv->irq_queue, DRM_INTR_PRI(dev));
+ ret = drm_vblank_init(dev, num_pipes);
+ if (ret)
+ return;
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
+ dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
i915_enable_interrupt(dev);
+ DRM_INIT_WAITQUEUE(&dev_priv->irq_queue, DRM_INTR_PRI(dev));
/*
* Initialize the hardware status page IRQ location.
*/
- I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21));
+ I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
+ return;
}
void i915_driver_irq_uninstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 temp;
+ u32 temp;
if (!dev_priv)
return;
+ dev_priv->vblank_pipe = 0;
dev_priv->irq_enabled = 0;
- I915_WRITE16(I915REG_HWSTAM, 0xffff);
- I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
- I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
- temp = I915_READ16(I915REG_INT_IDENTITY_R);
- I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+ I915_WRITE(HWSTAM, 0xffffffff);
+ I915_WRITE(IMR, 0xffffffff);
+ I915_WRITE(IER, 0x0);
- DRM_FINI_WAITQUEUE(&dev_priv->irq_queue);
- mutex_destroy(&dev_priv->swaps_lock);
- mutex_destroy(&dev_priv->user_irq_lock);
+ temp = I915_READ(PIPEASTAT);
+ I915_WRITE(PIPEASTAT, temp);
+ temp = I915_READ(PIPEBSTAT);
+ I915_WRITE(PIPEBSTAT, temp);
+ temp = I915_READ(IIR);
+ I915_WRITE(IIR, temp);
}