diff options
| author | miao chen - Sun Microsystems - Beijing China <Miao.Chen@Sun.COM> | 2009-02-17 16:22:10 +0800 |
|---|---|---|
| committer | miao chen - Sun Microsystems - Beijing China <Miao.Chen@Sun.COM> | 2009-02-17 16:22:10 +0800 |
| commit | d02310705313ee2fcefee164a4b26d1fa85e9d22 (patch) | |
| tree | 00eee2f6127e0c3b06b8ada57322f99073d66268 | |
| parent | 6532b9600e063234d62bca681503353c01abad20 (diff) | |
| download | illumos-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/postinstall | 5 | ||||
| -rw-r--r-- | usr/src/uts/common/io/drm/drm.h | 9 | ||||
| -rw-r--r-- | usr/src/uts/common/io/drm/drmP.h | 53 | ||||
| -rw-r--r-- | usr/src/uts/common/io/drm/drm_atomic.h | 6 | ||||
| -rw-r--r-- | usr/src/uts/common/io/drm/drm_bufs.c | 10 | ||||
| -rw-r--r-- | usr/src/uts/common/io/drm/drm_drawable.c | 12 | ||||
| -rw-r--r-- | usr/src/uts/common/io/drm/drm_drv.c | 16 | ||||
| -rw-r--r-- | usr/src/uts/common/io/drm/drm_io32.h | 14 | ||||
| -rw-r--r-- | usr/src/uts/common/io/drm/drm_irq.c | 288 | ||||
| -rw-r--r-- | usr/src/uts/common/io/drm/drm_lock.c | 39 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/agp/agpdefs.h | 4 | ||||
| -rw-r--r-- | usr/src/uts/intel/io/agpgart/agptarget.c | 4 | ||||
| -rw-r--r-- | usr/src/uts/intel/io/agpmaster/agpmaster.c | 6 | ||||
| -rw-r--r-- | usr/src/uts/intel/io/drm/drm_pciids.h | 3 | ||||
| -rw-r--r-- | usr/src/uts/intel/io/drm/i915_dma.c | 514 | ||||
| -rw-r--r-- | usr/src/uts/intel/io/drm/i915_drm.h | 47 | ||||
| -rw-r--r-- | usr/src/uts/intel/io/drm/i915_drv.c | 19 | ||||
| -rw-r--r-- | usr/src/uts/intel/io/drm/i915_drv.h | 194 | ||||
| -rw-r--r-- | usr/src/uts/intel/io/drm/i915_irq.c | 854 |
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(¶m, (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); } |
